> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scrubbe.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Playbooks API: build, execute, and manage runbooks

> Create and publish versioned runbooks, match them to live incidents, execute step-by-step workflows, and surface AI-suggested response actions.

Playbooks in Scrubbe are versioned, executable runbooks that codify your team's incident response procedures. You can create and publish playbooks through the API, match a playbook to a live incident context, and trigger executions that guide responders through each step — completing or skipping steps individually, recording ad-hoc actions, and cancelling when needed. Ezra AI can also suggest response actions based on real-time incident context, and the patterns endpoint surfaces lessons from historical executions.

<Note>
  All endpoints require `Authorization: Bearer <token>`. Only published playbooks are eligible for matching and execution. Use `POST /:id/publish` to promote a draft.
</Note>

**Base path:** `https://your-api-domain.com/api/v1/playbooks`

***

## Create a playbook

Creates a new playbook in `DRAFT` status. Publish it with `POST /:id/publish` when it is ready for use in incidents.

`POST https://your-api-domain.com/api/v1/playbooks`

<ParamField body="title" type="string" required>
  Short title for the playbook (e.g. `"Database failover response"`).
</ParamField>

<ParamField body="description" type="string">
  Overview of when this playbook should be used.
</ParamField>

<ParamField body="steps" type="object[]" required>
  Ordered list of response steps.

  <Expandable title="step properties">
    <ParamField body="title" type="string" required>Step title.</ParamField>
    <ParamField body="instructions" type="string">Detailed instructions for the responder.</ParamField>
    <ParamField body="optional" type="boolean" default="false">Whether this step can be skipped.</ParamField>
  </Expandable>
</ParamField>

<ParamField body="triggerConditions" type="object">
  Conditions used during automatic matching — service area, severity, environment, and similar fields.
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://your-api-domain.com/api/v1/playbooks \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "title": "Database failover response",
      "description": "Steps to handle an unplanned database primary failover.",
      "steps": [
        { "title": "Verify failover status", "instructions": "Check replication lag and confirm replica is promoted." },
        { "title": "Update DNS / connection strings", "instructions": "Point services to new primary endpoint." },
        { "title": "Confirm service recovery", "instructions": "Validate error rates have returned to baseline." }
      ],
      "triggerConditions": { "serviceArea": "database", "priority": "CRITICAL" }
    }'
  ```

  ```python Python theme={null}
  import requests

  resp = requests.post(
      'https://your-api-domain.com/api/v1/playbooks',
      headers={'Authorization': 'Bearer <token>'},
      json={
          'title': 'Database failover response',
          'description': 'Steps to handle an unplanned database primary failover.',
          'steps': [
              {'title': 'Verify failover status', 'instructions': 'Check replication lag and confirm replica is promoted.'},
              {'title': 'Update DNS / connection strings', 'instructions': 'Point services to new primary endpoint.'},
              {'title': 'Confirm service recovery', 'instructions': 'Validate error rates have returned to baseline.'},
          ],
          'triggerConditions': {'serviceArea': 'database', 'priority': 'CRITICAL'},
      },
  )
  print(resp.json())
  ```
</CodeGroup>

<ResponseField name="id" type="string" required>Unique playbook identifier.</ResponseField>
<ResponseField name="status" type="string" required>Initial status — always `DRAFT`.</ResponseField>
<ResponseField name="createdAt" type="string" required>ISO 8601 creation timestamp.</ResponseField>

***

## List playbooks

Returns a paginated list of playbooks ordered by creation date descending. Filter by status to view only published playbooks available for execution.

`GET https://your-api-domain.com/api/v1/playbooks`

<ParamField query="page" type="number" default="1">Page number.</ParamField>
<ParamField query="limit" type="number" default="20">Items per page (max 100).</ParamField>
<ParamField query="status" type="string">Filter by status: `DRAFT` or `PUBLISHED`.</ParamField>

```bash cURL theme={null}
curl "https://your-api-domain.com/api/v1/playbooks?status=PUBLISHED" \
  -H "Authorization: Bearer <token>"
```

***

## Get playbook stats

Returns aggregate statistics across all playbooks — total executions, average completion time, step skip rates, and most-executed playbooks.

`GET https://your-api-domain.com/api/v1/playbooks/stats`

```bash cURL theme={null}
curl https://your-api-domain.com/api/v1/playbooks/stats \
  -H "Authorization: Bearer <token>"
```

<ResponseField name="totalPlaybooks" type="number">Total playbook count in the workspace.</ResponseField>
<ResponseField name="totalExecutions" type="number">Total number of executions across all playbooks.</ResponseField>
<ResponseField name="averageCompletionMinutes" type="number">Average time to complete an execution in minutes.</ResponseField>
<ResponseField name="stepSkipRate" type="number">Proportion of optional steps skipped across all executions, from `0` to `1`.</ResponseField>

***

## Get a playbook

Fetch a single playbook by its ID, including its full step list and trigger conditions.

`GET https://your-api-domain.com/api/v1/playbooks/:id`

<ParamField path="id" type="string" required>
  The playbook ID.
</ParamField>

```bash cURL theme={null}
curl https://your-api-domain.com/api/v1/playbooks/PB-0012 \
  -H "Authorization: Bearer <token>"
```

***

## Update a playbook

Update an existing playbook. Only the fields you provide are modified. Updating a published playbook creates a new draft version; use `POST /:id/publish` to promote it.

`PUT https://your-api-domain.com/api/v1/playbooks/:id`

<ParamField path="id" type="string" required>
  The playbook ID.
</ParamField>

Accepts the same body fields as `POST /`.

***

## Publish a playbook

Promote a draft playbook to `PUBLISHED` status, making it eligible for matching and execution.

`POST https://your-api-domain.com/api/v1/playbooks/:id/publish`

<ParamField path="id" type="string" required>
  The playbook ID to publish.
</ParamField>

```bash cURL theme={null}
curl -X POST https://your-api-domain.com/api/v1/playbooks/PB-0012/publish \
  -H "Authorization: Bearer <token>"
```

***

## Delete a playbook

Permanently delete a playbook and all its associated execution history.

`DELETE https://your-api-domain.com/api/v1/playbooks/:id`

<ParamField path="id" type="string" required>
  The playbook ID to delete.
</ParamField>

<Warning>
  Deletion is permanent and removes all execution history. Consider keeping published playbooks and creating updated draft versions instead.
</Warning>

***

## Match a playbook to an incident

Find the best-matching published playbook for a given incident context. Scrubbe scores all published playbooks against the provided context and returns the top match.

`POST https://your-api-domain.com/api/v1/playbooks/match`

<ParamField body="incidentId" type="string">
  ID of the active incident. Scrubbe reads its context automatically.
</ParamField>

<ParamField body="serviceArea" type="string">
  Service area to match against when not providing an incident ID.
</ParamField>

<ParamField body="priority" type="string">
  Incident priority: `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL`.
</ParamField>

<ParamField body="environment" type="string">
  Target environment (e.g. `"production"`, `"staging"`).
</ParamField>

```bash cURL theme={null}
curl -X POST https://your-api-domain.com/api/v1/playbooks/match \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "incidentId": "INC-20260522-0041" }'
```

<ResponseField name="playbookId" type="string" required>ID of the best-matched playbook.</ResponseField>
<ResponseField name="title" type="string" required>Playbook title.</ResponseField>
<ResponseField name="matchScore" type="number">Confidence score for the match, from `0` to `1`.</ResponseField>

***

## Execute a playbook

Start a new execution of a published playbook. Returns an execution ID that you use to track and drive progress through each step.

`POST https://your-api-domain.com/api/v1/playbooks/:id/execute`

<ParamField path="id" type="string" required>
  The playbook ID to execute.
</ParamField>

<ParamField body="incidentId" type="string">
  Link this execution to an active incident.
</ParamField>

<ParamField body="assignedToEmail" type="string">
  Email address of the engineer leading the execution.
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://your-api-domain.com/api/v1/playbooks/PB-0012/execute \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
      "incidentId": "INC-20260522-0041",
      "assignedToEmail": "oncall@example.com"
    }'
  ```

  ```javascript Node.js theme={null}
  const resp = await fetch(
    'https://your-api-domain.com/api/v1/playbooks/PB-0012/execute',
    {
      method: 'POST',
      headers: {
        Authorization: 'Bearer <token>',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        incidentId: 'INC-20260522-0041',
        assignedToEmail: 'oncall@example.com',
      }),
    }
  );
  const { data } = await resp.json();
  ```
</CodeGroup>

<ResponseField name="executionId" type="string" required>Unique identifier for this execution.</ResponseField>
<ResponseField name="status" type="string" required>Execution status — `IN_PROGRESS` on creation.</ResponseField>

***

## List executions

Returns a paginated list of all playbook executions in the workspace.

`GET https://your-api-domain.com/api/v1/playbooks/executions/list`

<ParamField query="page" type="number" default="1">Page number.</ParamField>
<ParamField query="limit" type="number" default="20">Items per page (max 100).</ParamField>
<ParamField query="status" type="string">Filter by execution status: `IN_PROGRESS`, `COMPLETED`, or `CANCELLED`.</ParamField>

```bash cURL theme={null}
curl "https://your-api-domain.com/api/v1/playbooks/executions/list?status=IN_PROGRESS" \
  -H "Authorization: Bearer <token>"
```

***

## Get an execution

Fetch a single execution by its ID, including current step progress and per-step status.

`GET https://your-api-domain.com/api/v1/playbooks/executions/:executionId`

<ParamField path="executionId" type="string" required>
  The execution ID.
</ParamField>

```bash cURL theme={null}
curl https://your-api-domain.com/api/v1/playbooks/executions/EXEC-20260522-0005 \
  -H "Authorization: Bearer <token>"
```

<ResponseField name="executionId" type="string" required>Execution identifier.</ResponseField>
<ResponseField name="playbookId" type="string" required>ID of the playbook being executed.</ResponseField>
<ResponseField name="incidentId" type="string">Linked incident ID, if any.</ResponseField>
<ResponseField name="status" type="string" required>Execution status: `IN_PROGRESS`, `COMPLETED`, or `CANCELLED`.</ResponseField>
<ResponseField name="currentStepIndex" type="number">Zero-based index of the step currently in progress.</ResponseField>

<ResponseField name="steps" type="object[]">
  Per-step state.

  <Expandable title="step object">
    <ResponseField name="index" type="number">Zero-based step position.</ResponseField>
    <ResponseField name="title" type="string">Step title.</ResponseField>
    <ResponseField name="status" type="string">`PENDING`, `IN_PROGRESS`, `COMPLETED`, or `SKIPPED`.</ResponseField>
    <ResponseField name="notes" type="string">Responder notes added on completion.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="startedAt" type="string" required>ISO 8601 timestamp when execution began.</ResponseField>

***

## Complete a step

Mark a step in an active execution as completed and advance to the next step.

`POST https://your-api-domain.com/api/v1/playbooks/executions/:executionId/steps/:stepIndex/complete`

<ParamField path="executionId" type="string" required>
  The execution ID.
</ParamField>

<ParamField path="stepIndex" type="number" required>
  Zero-based index of the step to complete.
</ParamField>

<ParamField body="notes" type="string">
  Optional notes from the responder about this step.
</ParamField>

```bash cURL theme={null}
curl -X POST \
  "https://your-api-domain.com/api/v1/playbooks/executions/EXEC-20260522-0005/steps/1/complete" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "notes": "DNS updated and propagated" }'
```

***

## Skip a step

Skip an optional step in an active execution. Only steps defined with `"optional": true` can be skipped.

`POST https://your-api-domain.com/api/v1/playbooks/executions/:executionId/steps/:stepIndex/skip`

<ParamField path="executionId" type="string" required>
  The execution ID.
</ParamField>

<ParamField path="stepIndex" type="number" required>
  Zero-based index of the step to skip.
</ParamField>

<ParamField body="reason" type="string">
  Reason for skipping the step.
</ParamField>

<Note>
  Skipping a required step returns a `400` error. Mark the step as `optional` in the playbook definition to allow skipping.
</Note>

```bash cURL theme={null}
curl -X POST \
  "https://your-api-domain.com/api/v1/playbooks/executions/EXEC-20260522-0005/steps/2/skip" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Not applicable for this environment" }'
```

***

## Record an ad-hoc action

Record an unscripted action taken during an execution — useful for capturing steps not covered by the playbook or for audit purposes.

`POST https://your-api-domain.com/api/v1/playbooks/executions/:executionId/action`

<ParamField path="executionId" type="string" required>
  The execution ID.
</ParamField>

<ParamField body="description" type="string" required>
  Description of the action taken.
</ParamField>

```bash cURL theme={null}
curl -X POST \
  "https://your-api-domain.com/api/v1/playbooks/executions/EXEC-20260522-0005/action" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "description": "Rolled back deployment svc-payments@1.4.2 to 1.4.1" }'
```

***

## Complete an execution

Mark the entire execution as `COMPLETED` once all required steps have been finished.

`POST https://your-api-domain.com/api/v1/playbooks/executions/:executionId/complete`

<ParamField path="executionId" type="string" required>
  The execution ID.
</ParamField>

```bash cURL theme={null}
curl -X POST \
  "https://your-api-domain.com/api/v1/playbooks/executions/EXEC-20260522-0005/complete" \
  -H "Authorization: Bearer <token>"
```

***

## Cancel an execution

Cancel an active execution. Cancelled executions are retained for audit purposes and excluded from completion rate statistics.

`POST https://your-api-domain.com/api/v1/playbooks/executions/:executionId/cancel`

<ParamField path="executionId" type="string" required>
  The execution ID.
</ParamField>

<ParamField body="reason" type="string">
  Reason for cancelling the execution.
</ParamField>

```bash cURL theme={null}
curl -X POST \
  "https://your-api-domain.com/api/v1/playbooks/executions/EXEC-20260522-0005/cancel" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Incident mitigated before playbook completion" }'
```

***

## AI: suggest response actions

Ask Ezra AI to suggest ad-hoc response actions based on an incident context. Returns an ordered list of recommendations that responders can act on immediately or log via `POST /executions/:executionId/action`.

`POST https://your-api-domain.com/api/v1/playbooks/suggest`

<ParamField body="incidentId" type="string" required>
  ID of the active incident to generate suggestions for.
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://your-api-domain.com/api/v1/playbooks/suggest \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{ "incidentId": "INC-20260522-0041" }'
  ```

  ```javascript Node.js theme={null}
  const resp = await fetch('https://your-api-domain.com/api/v1/playbooks/suggest', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer <token>',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ incidentId: 'INC-20260522-0041' }),
  });
  const { data } = await resp.json();
  ```
</CodeGroup>

<ResponseField name="suggestions" type="string[]" required>Ordered list of AI-recommended response actions.</ResponseField>
<ResponseField name="confidence" type="number">Overall confidence score for the suggestion set, from `0` to `1`.</ResponseField>

***

## Get execution patterns

Returns patterns detected across playbook execution history — steps most frequently skipped, executions that correlated with faster resolution, and playbooks with the highest completion rates.

`GET https://your-api-domain.com/api/v1/playbooks/patterns`

```bash cURL theme={null}
curl https://your-api-domain.com/api/v1/playbooks/patterns \
  -H "Authorization: Bearer <token>"
```

<ResponseField name="data" type="object[]">
  Array of detected execution patterns.

  <Expandable title="pattern object">
    <ResponseField name="patternId" type="string" required>Unique pattern identifier.</ResponseField>
    <ResponseField name="description" type="string" required>Description of the execution pattern.</ResponseField>
    <ResponseField name="playbookId" type="string">Playbook associated with this pattern, if any.</ResponseField>
    <ResponseField name="occurrences" type="number" required>Number of executions matching this pattern.</ResponseField>
    <ResponseField name="insight" type="string">Ezra's recommendation based on the pattern.</ResponseField>
  </Expandable>
</ResponseField>
