# Links

> The Links operations of the Hub REST API (2 operations).

URL: https://docs.synap.live/docs/reference/hub-api/links · Generated from Synap-core/backend@c31e261ab (main)

Paths are relative to `/api/hub` on a pod.

## GET /links

Read a node's links (neighbours in the config/runtime graph)

Returns every edge touching (type, id) — the REST mirror of the canonical getLinksFor reader. Lets any agent/app traverse the graph (tool↔vault, skill↔tool, session↔used→tool, playbook→grants→capability) uniformly. Scoped to the caller's visible workspaces.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `type` | query | "playbook" \| "tool" \| "skill" \| "command" \| "session" \| "source" \| "entity" \| "channel" \| "participant" \| "automation" \| "project" \| "secret" \| "capability" \| "agent" \| "workspace" \| "document" \| "track" \| "profile" | yes |  |
| `id` | query | string | yes |  |

Responses:

- `200`: The edges touching this node
- `400`: Bad request
- `403`: Forbidden
- `500`: Internal error

## POST /links

Create a config/runtime link edge

Creates a typed edge in the config graph (`links`) — the mirror of `relations`. Can bridge entity DATA to config objects, e.g. entity(knowledge) --about--> tool. Gated by checkPermissionOrPropose.

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `userId` | string |  |  |
| `workspaceId` | string |  |  |
| `fromType` | "playbook" \| "tool" \| "skill" \| "command" \| "session" \| "source" \| "entity" \| "channel" \| "participant" \| "automation" \| "project" \| "secret" \| "capability" \| "agent" \| "workspace" \| "document" \| "track" \| "profile" | yes |  |
| `fromId` | string | yes |  |
| `toType` | "playbook" \| "tool" \| "skill" \| "command" \| "session" \| "source" \| "entity" \| "channel" \| "participant" \| "automation" \| "project" \| "secret" \| "capability" \| "agent" \| "workspace" \| "document" \| "track" \| "profile" | yes |  |
| `toId` | string | yes |  |
| `linkType` | "grants" \| "requires" \| "instantiated_from" \| "used" \| "targets" \| "produced" \| "member_of" \| "feeds" \| "promoted_to" \| "provided_by" \| "about" \| "documents" \| "concerns" \| "activates" \| "spawned_from" \| "blocked_by" \| "replaces" \| "uses" \| "dispatched_via" \| "assigned_to" | yes |  |
| `metadata` | object |  |  |
| `agentUserId` | string |  |  |
| `reasoning` | string |  |  |

Responses:

- `200`: Created link, or a proposal when governance defers. For `blocked_by`, `link` is always null (there is no row to hand back through the dedicated producer) and `blockedBy.inserted` distinguishes a new edge (1) from an already-existing one (0).
- `400`: Bad request
- `403`: Forbidden
- `404`: Session not found
- `500`: Internal error
