# Playbooks

> The Playbooks operations of the Hub REST API (5 operations).

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

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

## GET /playbooks

List playbooks

Playbooks visible to the caller across the pod — every member workspace plus pod-wide templates. Cursor-paginated. Same door as MCP synap_list_playbooks.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `workspaceId` | query | string |  | Narrows to this workspace (pod-wide playbooks still included). |
| `status` | query | "draft" \| "active" \| "paused" \| "archived" |  |  |
| `limit` | query | integer |  |  |
| `cursor` | query | string |  |  |

Responses:

- `200`: { playbooks, nextCursor }
- `400`: Bad request
- `403`: Forbidden
- `500`: Internal error

## POST /playbooks

Create a playbook

Creates a reusable playbook (staged process template). Governed: an agent caller gets 202 `status: 'proposed'` with a `reviewUrl` — that is success, not an error. Same door as MCP synap_create_playbook.

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes |  |
| `goalTemplate` | string | yes | May reference a declared param as {name}; an undeclared name, or {{name}}, is refused. |
| `description` | string |  |  |
| `stages` | array<object> |  |  |
| `status` | "draft" \| "active" \| "paused" \| "archived" |  | Defaults to active. |
| `subjectProfile` | object |  | The kind this playbook runs ON, e.g. { profileSlug: 'crm-lead' }. A profileSlug that resolves to no profile is refused. |
| `scope` | "session" \| "project" |  | session (default) = a template for one focus session; project = a METHOD a project runs as a track. |
| `params` | array<object> |  | Declared params [{ name, label?, type: text\|number\|entity\|choice\|boolean, options?, default?, required? }]. Makes a method self-onboarding: a required param left unanswered when a track starts becomes a question owed to the person. |
| `criteria` | array<object> |  | Binary acceptance criteria [{ key, statement, required?, check: { kind, ... }, stageKey? }] every instantiated session is graded against. |
| `workspaceId` | string | yes | The playbook's home workspace. |
| `forceCreate` | boolean |  | Only after a CONFLICT naming an overlapping playbook. Creates anyway. |
| `agentUserId` | string |  |  |

Responses:

- `200`: Created (or existing by name)
- `202`: Proposed for review
- `400`: Bad request
- `403`: Forbidden
- `500`: Internal error

## POST /playbooks/{id}/run

Run a playbook

Launches a playbook via its executor. Governed: an agent launch gets 202 `status: 'proposed'`. A playbook that depends on skills not enabled yet returns `status: 'blocked'` with `unenabledSkills` and `enableProposals` — nothing ran. Same door as MCP synap_run_playbook.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `workspaceId` | string |  | Write home for the run. Omit to use the playbook's own workspace (then the subject's). |
| `subjectId` | string |  |  |
| `params` | object |  |  |
| `agentIds` | array<string> |  |  |
| `reasoning` | string |  |  |
| `agentUserId` | string |  |  |
| `projectId` | string |  | File the run into this project (must be visible to you). |
| `trackId` | string |  | File the run inside this track (a method running in a project). Implies its project. |
| `trackStage` | string |  | The stage of that track the run is filed at. Omit for its current stage. Needs trackId. |

Responses:

- `200`: Running, or blocked
- `202`: Proposed for review
- `400`: Bad request
- `403`: Forbidden
- `404`: Playbook not found
- `412`: Skills not enabled (human caller)
- `500`: Internal error

## POST /runs/{runId}/cancel

Cancel a live playbook run (and its external agent task)

Marks a running run cancelled. When the run was handed to an external agent whose binding supports cancel, the binding's cancel verb runs first and must succeed; otherwise the run is cancelled and the response says the agent could not be stopped from Synap. Human-only: an agent key gets 403.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `runId` | path | string | yes |  |

Responses:

- `200`: Cancelled
- `403`: Forbidden
- `404`: Run not found
- `409`: Run is not live
- `502`: The agent's cancel failed

## POST /runs/{runId}/capture

Capture a playbook run's outcome

Reports a run's status/summary back into Synap and records the entities it produced (session → produced → entity links). Governance-gated; on 'proposed' the run is not mutated.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `runId` | path | string | yes |  |

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `summary` | string |  |  |
| `status` | "running" \| "completed" \| "failed" \| "proposed" |  |  |
| `error` | string |  |  |
| `producedEntityIds` | array<string> |  |  |
| `usedCapabilities` | array<object> |  |  |
| `agentUserId` | string |  |  |

Responses:

- `200`: Capture recorded
- `400`: Bad request
- `403`: Forbidden
- `404`: Run not found
- `409`: The run already reached a verdict (terminal capture refused)
- `500`: Internal error
