# Escalation paths

An escalation path decides who reviews a request once the pipeline hands it to a person, and what happens when nobody answers in time.

To change a path, [create a revision](#createEscalationPathRevision), then
[activate it](#activateEscalationPathRevision). Activation affects requests
that reach a person from then on. A request already waiting for review stays
with the revision it was routed with, so its reviewers and timers do not
change.

## List escalation paths

`GET /api/v1/escalation-paths`

Auth: Reviewer session cookie (`withhuman_session`) or personal API key (`Authorization: Bearer $WITHHUMAN_API_KEY`)

Requires: `escalation_path.read`

Returns the organization's escalation paths, one entry per key, with the active revision number and a summary of the history. Live paths are returned unless `status` says otherwise; an archived path carries `archived_at`.

### Request

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `status` | query | string | no | Which paths to return. `live` (the default) leaves archived paths out, `archived` returns only them, and `all` returns both. |
| `limit` | query | integer | no | How many paths to return. Defaults to 50. |

### Response

| Status | Body | Description |
| --- | --- | --- |
| 200 | object | The paths |
| 400 | ErrorResponse | `status` is not live, archived, or all |
| 401 | ErrorResponse | You are not signed in |
| 403 | ErrorResponse | You cannot read escalation paths |

Response body (200):

- `escalation_paths` · array<EscalationPathSummary> · required
  - `path_key` · string · required
  - `name` · string · required: The name from the latest revision.
  - `active_revision` · int64: The revision requests are routed with. Absent while no revision is active, which is always the case for an archived path.
  - `latest_revision` · int64 · required: The newest revision, active or not.
  - `revision_count` · int64 · required
  - `latest_created_at` · date-time · required: When the newest revision was created.
  - `archived_at` · date-time: When the path was archived. Absent for a live path.

### Example

```bash
curl -X GET "$WITHHUMAN_URL/api/v1/escalation-paths" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
```

200 response

```json
{
  "escalation_paths": [
    {
      "path_key": "string",
      "name": "string",
      "active_revision": 1,
      "latest_revision": 1,
      "revision_count": 1,
      "latest_created_at": "2026-09-08T12:02:11Z",
      "archived_at": "2026-09-08T12:02:11Z"
    }
  ]
}
```

## Create an escalation path

`POST /api/v1/escalation-paths`

Auth: Reviewer session cookie (`withhuman_session`) or personal API key (`Authorization: Bearer $WITHHUMAN_API_KEY`)

Requires: `escalation_path.write`

Creates a path and its first revision in one call, from a complete document plus the key pipelines will reference. The document is validated first, including that every person and team it targets exists. The revision is created inactive, and it never changes. Activate it to put it into use.

A key can be used once. A key that belongs to a path, archived or not, is refused with 409 `escalation_path_exists`.

The response may carry warnings, for example a team whose members cannot decide requests. A warning never blocks creation.

### Request

Request body:

- `path_key` · string · required
- `name` · string · required
- `working_hours` · array<WorkingHoursSet> · required
  - `id` · string · required: A key for the set, unique within the document.
  - `name` · string · required: A display name.
  - `timezone` · string · required: An IANA timezone name, such as `Europe/London`.
  - `intervals` · array<WeekdayInterval> · required: The open windows. At least one.
    - `weekdays` · array<enum> · required: The days the window applies to.
    - `start` · string · required: When the window opens, as `HH:MM` in 24-hour time.
    - `end` · string · required: When the window closes, as `HH:MM` in 24-hour time.
- `nodes` · array<EscalationPathNode> · required
  - `id` · uuid · required: An id for the node, unique within the path.
  - `type` · enum · required: The kind of node. One of `level`, `if_else`, `defer`.
  - `targets` · array<EscalationTarget>: `level` only. The people and teams to notify.
    - `type` · enum · required One of `user`, `team`, `broadcast`.
    - `id` · uuid: Required for user and team, absent for broadcast.
  - `escalate_after` · string: `level` only. How long to wait for a decision before moving to the next node. A duration from `1m` to `168h`.
  - `raise_urgency` · boolean: `level` only. Raise the request to `interrupt` urgency before notifying.
  - `conditions` · array<EscalationPathCondition>: `if_else` only. Every condition must hold for `then` to run. From 1 to 10.
    - `type` · enum · required: The kind of test. `working_hours` tests whether a named window is open. `urgency` tests the request's current urgency. `request` tests the request itself. One of `working_hours`, `urgency`, `request`.
    - `working_hours_id` · string: `working_hours` only. The set to test.
    - `active` · boolean: `working_hours` only. `true` tests that the window is open, `false` that it is closed.
    - `urgency` · enum: `urgency` only. The urgency the request must have. One of `standard`, `interrupt`.
    - `when` · CELLeafCondition | CELAllCondition | CELAnyCondition | CELSomeCondition | CELEveryCondition: A condition tree. A leaf tests one field. all and any combine conditions. some and every test the items of a list field.
  - `then` · array<EscalationPathNode>: `if_else` only. The nodes to run when every condition holds. An empty list moves on to the next node.
  - `else` · array<EscalationPathNode>: `if_else` only. The nodes to run otherwise. An empty list moves on to the next node.
  - `working_hours_id` · string: `defer` only. The working-hours set to wait for.
  - `standard_only` · boolean: `defer` only. Let `interrupt` requests skip the wait.
- `repeat` · EscalationPathRepeat: Run the path again from the top when the nodes run out without a decision. Every condition is evaluated again on each run.
  - `times` · integer · required: How many extra runs, from 1 to 9.
  - `after` · string · required: How long to wait before each extra run. A duration from `1m` to `168h`.

### Response

| Status | Body | Description |
| --- | --- | --- |
| 201 | EscalationPathRevision | The path's first revision, inactive |
| 400 | ErrorResponse | The document is invalid, a target does not exist, or the key is malformed |
| 401 | ErrorResponse | You are not signed in |
| 403 | ErrorResponse | You cannot edit escalation paths |
| 409 | ErrorResponse | The key is already in use |

Response body (201):

- `id` · uuid · required
- `path_key` · string · required
- `revision` · int64 · required: The revision number. Revisions count up from 1.
- `is_active` · boolean · required: Whether requests are routed with this revision.
- `name` · string · required: The display name.
- `created_by_actor_id` · uuid · required: The membership or organization-key actor that created the revision.
- `created_at` · date-time · required
- `archived_at` · date-time: When the path was archived. Absent for a revision of a live path; an archived revision can no longer be activated.
- `working_hours` · array<WorkingHoursSet> · required: The named working-hours sets the nodes refer to.
  - `id` · string · required: A key for the set, unique within the document.
  - `name` · string · required: A display name.
  - `timezone` · string · required: An IANA timezone name, such as `Europe/London`.
  - `intervals` · array<WeekdayInterval> · required: The open windows. At least one.
    - `weekdays` · array<enum> · required: The days the window applies to.
    - `start` · string · required: When the window opens, as `HH:MM` in 24-hour time.
    - `end` · string · required: When the window closes, as `HH:MM` in 24-hour time.
- `nodes` · array<EscalationPathNode> · required: The nodes, in order.
  - `id` · uuid · required: An id for the node, unique within the path.
  - `type` · enum · required: The kind of node. One of `level`, `if_else`, `defer`.
  - `targets` · array<EscalationTarget>: `level` only. The people and teams to notify.
    - `type` · enum · required One of `user`, `team`, `broadcast`.
    - `id` · uuid: Required for user and team, absent for broadcast.
  - `escalate_after` · string: `level` only. How long to wait for a decision before moving to the next node. A duration from `1m` to `168h`.
  - `raise_urgency` · boolean: `level` only. Raise the request to `interrupt` urgency before notifying.
  - `conditions` · array<EscalationPathCondition>: `if_else` only. Every condition must hold for `then` to run. From 1 to 10.
    - `type` · enum · required: The kind of test. `working_hours` tests whether a named window is open. `urgency` tests the request's current urgency. `request` tests the request itself. One of `working_hours`, `urgency`, `request`.
    - `working_hours_id` · string: `working_hours` only. The set to test.
    - `active` · boolean: `working_hours` only. `true` tests that the window is open, `false` that it is closed.
    - `urgency` · enum: `urgency` only. The urgency the request must have. One of `standard`, `interrupt`.
    - `when` · CELLeafCondition | CELAllCondition | CELAnyCondition | CELSomeCondition | CELEveryCondition: A condition tree. A leaf tests one field. all and any combine conditions. some and every test the items of a list field.
  - `then` · array<EscalationPathNode>: `if_else` only. The nodes to run when every condition holds. An empty list moves on to the next node.
  - `else` · array<EscalationPathNode>: `if_else` only. The nodes to run otherwise. An empty list moves on to the next node.
  - `working_hours_id` · string: `defer` only. The working-hours set to wait for.
  - `standard_only` · boolean: `defer` only. Let `interrupt` requests skip the wait.
- `repeat` · EscalationPathRepeat: Run the path again from the top when the nodes run out without a decision. Every condition is evaluated again on each run.
  - `times` · integer · required: How many extra runs, from 1 to 9.
  - `after` · string · required: How long to wait before each extra run. A duration from `1m` to `168h`.
- `document_version` · integer · required: The version of the document format.
- `warnings` · array<EscalationPathWarning> · required: Advisory findings about the document's targets. They are computed when a revision is created or activated, and the list is empty on plain reads. A warning never blocks anything: a path narrows who decides, it never grants.
  - `code` · enum · required: `team_members_cannot_decide`: `count` of the team's `member_count` members cannot decide requests, so routing to the team reaches fewer deciders than its size suggests. `path_may_reach_nobody`: some request's conditions leave no level to run, so such a request is routed to nobody and only break-glass reviewers can decide it; the team fields are absent. One of `team_members_cannot_decide`, `path_may_reach_nobody`.
  - `team_id` · uuid
  - `team_name` · string
  - `count` · integer: Members of the team who cannot decide requests.
  - `member_count` · integer: Active members of the team.

### Example

```bash
curl -X POST "$WITHHUMAN_URL/api/v1/escalation-paths" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "path_key": "string",
  "name": "string",
  "working_hours": [
    {
      "id": "uk-office",
      "name": "UK office hours",
      "timezone": "Europe/London",
      "intervals": [
        {
          "weekdays": [
            "mon"
          ],
          "start": "09:00",
          "end": "18:00"
        }
      ]
    }
  ],
  "nodes": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "type": "level",
      "targets": [
        {
          "type": "user",
          "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
        }
      ],
      "escalate_after": "15m",
      "raise_urgency": true,
      "conditions": [
        {
          "type": "working_hours",
          "working_hours_id": "string",
          "active": true,
          "urgency": "standard",
          "when": {
            "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
            "field": "/request/arguments/amount_cents",
            "operator": "exists",
            "value": {}
          }
        }
      ],
      "then": [
        {}
      ],
      "else": [
        {}
      ],
      "working_hours_id": "string",
      "standard_only": true
    }
  ],
  "repeat": {
    "times": 1,
    "after": "1h"
  }
}'
```

201 response

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "path_key": "string",
  "revision": 1,
  "is_active": true,
  "name": "On-call engineers",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z",
  "working_hours": [
    {
      "id": "uk-office",
      "name": "UK office hours",
      "timezone": "Europe/London",
      "intervals": [
        {
          "weekdays": [
            "mon"
          ],
          "start": "09:00",
          "end": "18:00"
        }
      ]
    }
  ],
  "nodes": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "type": "level",
      "targets": [
        {
          "type": "user",
          "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
        }
      ],
      "escalate_after": "15m",
      "raise_urgency": true,
      "conditions": [
        {
          "type": "working_hours",
          "working_hours_id": "string",
          "active": true,
          "urgency": "standard",
          "when": {
            "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
            "field": "/request/arguments/amount_cents",
            "operator": "exists",
            "value": {}
          }
        }
      ],
      "then": [
        {}
      ],
      "else": [
        {}
      ],
      "working_hours_id": "string",
      "standard_only": true
    }
  ],
  "repeat": {
    "times": 1,
    "after": "1h"
  },
  "document_version": 1,
  "warnings": [
    {
      "code": "team_members_cannot_decide",
      "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "team_name": "string",
      "count": 1,
      "member_count": 1
    }
  ]
}
```

## Retrieve an escalation path

`GET /api/v1/escalation-paths/{path_key}`

Auth: Reviewer session cookie (`withhuman_session`) or personal API key (`Authorization: Bearer $WITHHUMAN_API_KEY`)

Requires: `escalation_path.read`

Returns the path's active revision with its full document. This is the revision new requests are routed with.

The `ETag` header carries the active revision number. Pass it as `If-Match` when you activate another revision.

### Request

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `path_key` | path | string | yes | The path's key. Lowercase letters, digits, dots, underscores and hyphens, up to 63 characters. You choose it when you create the first revision. |

### Response

| Status | Body | Description |
| --- | --- | --- |
| 200 | EscalationPathRevision | The active revision |
| 401 | ErrorResponse | You are not signed in |
| 403 | ErrorResponse | You cannot read escalation paths |
| 404 | ErrorResponse | No such path, or no revision is active (an archived path never has one) |

Response body (200):

- `id` · uuid · required
- `path_key` · string · required
- `revision` · int64 · required: The revision number. Revisions count up from 1.
- `is_active` · boolean · required: Whether requests are routed with this revision.
- `name` · string · required: The display name.
- `created_by_actor_id` · uuid · required: The membership or organization-key actor that created the revision.
- `created_at` · date-time · required
- `archived_at` · date-time: When the path was archived. Absent for a revision of a live path; an archived revision can no longer be activated.
- `working_hours` · array<WorkingHoursSet> · required: The named working-hours sets the nodes refer to.
  - `id` · string · required: A key for the set, unique within the document.
  - `name` · string · required: A display name.
  - `timezone` · string · required: An IANA timezone name, such as `Europe/London`.
  - `intervals` · array<WeekdayInterval> · required: The open windows. At least one.
    - `weekdays` · array<enum> · required: The days the window applies to.
    - `start` · string · required: When the window opens, as `HH:MM` in 24-hour time.
    - `end` · string · required: When the window closes, as `HH:MM` in 24-hour time.
- `nodes` · array<EscalationPathNode> · required: The nodes, in order.
  - `id` · uuid · required: An id for the node, unique within the path.
  - `type` · enum · required: The kind of node. One of `level`, `if_else`, `defer`.
  - `targets` · array<EscalationTarget>: `level` only. The people and teams to notify.
    - `type` · enum · required One of `user`, `team`, `broadcast`.
    - `id` · uuid: Required for user and team, absent for broadcast.
  - `escalate_after` · string: `level` only. How long to wait for a decision before moving to the next node. A duration from `1m` to `168h`.
  - `raise_urgency` · boolean: `level` only. Raise the request to `interrupt` urgency before notifying.
  - `conditions` · array<EscalationPathCondition>: `if_else` only. Every condition must hold for `then` to run. From 1 to 10.
    - `type` · enum · required: The kind of test. `working_hours` tests whether a named window is open. `urgency` tests the request's current urgency. `request` tests the request itself. One of `working_hours`, `urgency`, `request`.
    - `working_hours_id` · string: `working_hours` only. The set to test.
    - `active` · boolean: `working_hours` only. `true` tests that the window is open, `false` that it is closed.
    - `urgency` · enum: `urgency` only. The urgency the request must have. One of `standard`, `interrupt`.
    - `when` · CELLeafCondition | CELAllCondition | CELAnyCondition | CELSomeCondition | CELEveryCondition: A condition tree. A leaf tests one field. all and any combine conditions. some and every test the items of a list field.
  - `then` · array<EscalationPathNode>: `if_else` only. The nodes to run when every condition holds. An empty list moves on to the next node.
  - `else` · array<EscalationPathNode>: `if_else` only. The nodes to run otherwise. An empty list moves on to the next node.
  - `working_hours_id` · string: `defer` only. The working-hours set to wait for.
  - `standard_only` · boolean: `defer` only. Let `interrupt` requests skip the wait.
- `repeat` · EscalationPathRepeat: Run the path again from the top when the nodes run out without a decision. Every condition is evaluated again on each run.
  - `times` · integer · required: How many extra runs, from 1 to 9.
  - `after` · string · required: How long to wait before each extra run. A duration from `1m` to `168h`.
- `document_version` · integer · required: The version of the document format.
- `warnings` · array<EscalationPathWarning> · required: Advisory findings about the document's targets. They are computed when a revision is created or activated, and the list is empty on plain reads. A warning never blocks anything: a path narrows who decides, it never grants.
  - `code` · enum · required: `team_members_cannot_decide`: `count` of the team's `member_count` members cannot decide requests, so routing to the team reaches fewer deciders than its size suggests. `path_may_reach_nobody`: some request's conditions leave no level to run, so such a request is routed to nobody and only break-glass reviewers can decide it; the team fields are absent. One of `team_members_cannot_decide`, `path_may_reach_nobody`.
  - `team_id` · uuid
  - `team_name` · string
  - `count` · integer: Members of the team who cannot decide requests.
  - `member_count` · integer: Active members of the team.

### Example

```bash
curl -X GET "$WITHHUMAN_URL/api/v1/escalation-paths/{path_key}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
```

200 response

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "path_key": "string",
  "revision": 1,
  "is_active": true,
  "name": "On-call engineers",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z",
  "working_hours": [
    {
      "id": "uk-office",
      "name": "UK office hours",
      "timezone": "Europe/London",
      "intervals": [
        {
          "weekdays": [
            "mon"
          ],
          "start": "09:00",
          "end": "18:00"
        }
      ]
    }
  ],
  "nodes": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "type": "level",
      "targets": [
        {
          "type": "user",
          "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
        }
      ],
      "escalate_after": "15m",
      "raise_urgency": true,
      "conditions": [
        {
          "type": "working_hours",
          "working_hours_id": "string",
          "active": true,
          "urgency": "standard",
          "when": {
            "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
            "field": "/request/arguments/amount_cents",
            "operator": "exists",
            "value": {}
          }
        }
      ],
      "then": [
        {}
      ],
      "else": [
        {}
      ],
      "working_hours_id": "string",
      "standard_only": true
    }
  ],
  "repeat": {
    "times": 1,
    "after": "1h"
  },
  "document_version": 1,
  "warnings": [
    {
      "code": "team_members_cannot_decide",
      "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "team_name": "string",
      "count": 1,
      "member_count": 1
    }
  ]
}
```

## Archive an escalation path

`DELETE /api/v1/escalation-paths/{path_key}`

Auth: Reviewer session cookie (`withhuman_session`) or personal API key (`Authorization: Bearer $WITHHUMAN_API_KEY`)

Requires: `escalation_path.activate`

Archives the path and every revision it has. Nothing is deleted: the path is still listed with `status=archived` or `all`, its revisions can still be retrieved, and a request already routed with one of them keeps it. But the path is never active again, it takes no new revisions, and no pipeline can name it. Its key cannot be used for a new path.

A path that an active pipeline revision names, in a block or as the pipeline default, cannot be archived. The call fails with 409 `escalation_path_in_use` and lists those revisions in `details.uses`; replace them first.

### Request

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `path_key` | path | string | yes | The path's key. Lowercase letters, digits, dots, underscores and hyphens, up to 63 characters. You choose it when you create the first revision. |

### Response

| Status | Body | Description |
| --- | --- | --- |
| 204 |  | The path is archived |
| 400 | ErrorResponse | `path_key` is malformed |
| 401 | ErrorResponse | You are not signed in |
| 403 | ErrorResponse | You cannot archive escalation paths |
| 404 | ErrorResponse | No such path |
| 409 | ErrorResponse | An active pipeline revision names the path (`escalation_path_in_use`), or the path is already archived (`escalation_path_archived`) |

### Example

```bash
curl -X DELETE "$WITHHUMAN_URL/api/v1/escalation-paths/{path_key}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
```

## List escalation path revisions

`GET /api/v1/escalation-paths/{path_key}/revisions`

Auth: Reviewer session cookie (`withhuman_session`) or personal API key (`Authorization: Bearer $WITHHUMAN_API_KEY`)

Requires: `escalation_path.read`

Returns the path's revisions, newest first, without their documents. An archived path's revisions carry `archived_at`.

Paging is by cursor. When more revisions follow, the response carries `next_cursor`. Pass it back as `cursor` to get the next page. The last page has no `next_cursor`. `total_count` is how many revisions there are across every page.

### Request

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `path_key` | path | string | yes | The path's key. Lowercase letters, digits, dots, underscores and hyphens, up to 63 characters. You choose it when you create the first revision. |
| `cursor` | query | string | no | The `next_cursor` from the previous page. |
| `limit` | query | integer | no | How many revisions to return per page. Defaults to 50. |

### Response

| Status | Body | Description |
| --- | --- | --- |
| 200 | object | The revisions, newest first |
| 400 | ErrorResponse | `cursor` is not a cursor this endpoint issued |
| 401 | ErrorResponse | You are not signed in |
| 403 | ErrorResponse | You cannot read escalation paths |

Response body (200):

- `revisions` · array<EscalationPathRevisionSummary> · required: The revisions on this page, newest first.
  - `id` · uuid · required
  - `path_key` · string · required
  - `revision` · int64 · required: The revision number. Revisions count up from 1.
  - `is_active` · boolean · required: Whether requests are routed with this revision.
  - `name` · string · required: The display name.
  - `created_by_actor_id` · uuid · required: The membership or organization-key actor that created the revision.
  - `created_at` · date-time · required
  - `archived_at` · date-time: When the path was archived. Absent for a revision of a live path; an archived revision can no longer be activated.
- `next_cursor` · string: Present when another page follows.
- `total_count` · int64 · required: How many revisions the path has, across every page.

### Example

```bash
curl -X GET "$WITHHUMAN_URL/api/v1/escalation-paths/{path_key}/revisions" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
```

200 response

```json
{
  "revisions": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "path_key": "string",
      "revision": 1,
      "is_active": true,
      "name": "On-call engineers",
      "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "created_at": "2026-09-08T12:02:11Z",
      "archived_at": "2026-09-08T12:02:11Z"
    }
  ],
  "next_cursor": "string",
  "total_count": 1
}
```

## Create an escalation path revision

`POST /api/v1/escalation-paths/{path_key}/revisions`

Auth: Reviewer session cookie (`withhuman_session`) or personal API key (`Authorization: Bearer $WITHHUMAN_API_KEY`)

Requires: `escalation_path.write`

Creates a new revision of an existing path from a complete document. The document is validated first, including that every person and team it targets exists. The revision is created inactive, and it never changes. Activate it to put it into use.

The path must exist and not be archived. A new path is created with `POST /api/v1/escalation-paths`.

The response may carry warnings, for example a team whose members cannot decide requests. A warning never blocks creation.

### Request

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `path_key` | path | string | yes | The path's key. Lowercase letters, digits, dots, underscores and hyphens, up to 63 characters. You choose it when you create the first revision. |

Request body:

- `name` · string · required: A display name. Reviewers see it on the requests the path routes.
- `working_hours` · array<WorkingHoursSet> · required: Named working-hours sets that `if_else` and `defer` nodes refer to by id. May be empty.
  - `id` · string · required: A key for the set, unique within the document.
  - `name` · string · required: A display name.
  - `timezone` · string · required: An IANA timezone name, such as `Europe/London`.
  - `intervals` · array<WeekdayInterval> · required: The open windows. At least one.
    - `weekdays` · array<enum> · required: The days the window applies to.
    - `start` · string · required: When the window opens, as `HH:MM` in 24-hour time.
    - `end` · string · required: When the window closes, as `HH:MM` in 24-hour time.
- `nodes` · array<EscalationPathNode> · required: The nodes, in order. At least one.
  - `id` · uuid · required: An id for the node, unique within the path.
  - `type` · enum · required: The kind of node. One of `level`, `if_else`, `defer`.
  - `targets` · array<EscalationTarget>: `level` only. The people and teams to notify.
    - `type` · enum · required One of `user`, `team`, `broadcast`.
    - `id` · uuid: Required for user and team, absent for broadcast.
  - `escalate_after` · string: `level` only. How long to wait for a decision before moving to the next node. A duration from `1m` to `168h`.
  - `raise_urgency` · boolean: `level` only. Raise the request to `interrupt` urgency before notifying.
  - `conditions` · array<EscalationPathCondition>: `if_else` only. Every condition must hold for `then` to run. From 1 to 10.
    - `type` · enum · required: The kind of test. `working_hours` tests whether a named window is open. `urgency` tests the request's current urgency. `request` tests the request itself. One of `working_hours`, `urgency`, `request`.
    - `working_hours_id` · string: `working_hours` only. The set to test.
    - `active` · boolean: `working_hours` only. `true` tests that the window is open, `false` that it is closed.
    - `urgency` · enum: `urgency` only. The urgency the request must have. One of `standard`, `interrupt`.
    - `when` · CELLeafCondition | CELAllCondition | CELAnyCondition | CELSomeCondition | CELEveryCondition: A condition tree. A leaf tests one field. all and any combine conditions. some and every test the items of a list field.
  - `then` · array<EscalationPathNode>: `if_else` only. The nodes to run when every condition holds. An empty list moves on to the next node.
  - `else` · array<EscalationPathNode>: `if_else` only. The nodes to run otherwise. An empty list moves on to the next node.
  - `working_hours_id` · string: `defer` only. The working-hours set to wait for.
  - `standard_only` · boolean: `defer` only. Let `interrupt` requests skip the wait.
- `repeat` · EscalationPathRepeat: Run the path again from the top when the nodes run out without a decision. Every condition is evaluated again on each run.
  - `times` · integer · required: How many extra runs, from 1 to 9.
  - `after` · string · required: How long to wait before each extra run. A duration from `1m` to `168h`.

### Response

| Status | Body | Description |
| --- | --- | --- |
| 201 | EscalationPathRevision | The new revision, inactive |
| 400 | ErrorResponse | The document is invalid, or a target does not exist |
| 401 | ErrorResponse | You are not signed in |
| 403 | ErrorResponse | You cannot edit escalation paths |
| 404 | ErrorResponse | No such path |
| 409 | ErrorResponse | The path is archived |

Response body (201):

- `id` · uuid · required
- `path_key` · string · required
- `revision` · int64 · required: The revision number. Revisions count up from 1.
- `is_active` · boolean · required: Whether requests are routed with this revision.
- `name` · string · required: The display name.
- `created_by_actor_id` · uuid · required: The membership or organization-key actor that created the revision.
- `created_at` · date-time · required
- `archived_at` · date-time: When the path was archived. Absent for a revision of a live path; an archived revision can no longer be activated.
- `working_hours` · array<WorkingHoursSet> · required: The named working-hours sets the nodes refer to.
  - `id` · string · required: A key for the set, unique within the document.
  - `name` · string · required: A display name.
  - `timezone` · string · required: An IANA timezone name, such as `Europe/London`.
  - `intervals` · array<WeekdayInterval> · required: The open windows. At least one.
    - `weekdays` · array<enum> · required: The days the window applies to.
    - `start` · string · required: When the window opens, as `HH:MM` in 24-hour time.
    - `end` · string · required: When the window closes, as `HH:MM` in 24-hour time.
- `nodes` · array<EscalationPathNode> · required: The nodes, in order.
  - `id` · uuid · required: An id for the node, unique within the path.
  - `type` · enum · required: The kind of node. One of `level`, `if_else`, `defer`.
  - `targets` · array<EscalationTarget>: `level` only. The people and teams to notify.
    - `type` · enum · required One of `user`, `team`, `broadcast`.
    - `id` · uuid: Required for user and team, absent for broadcast.
  - `escalate_after` · string: `level` only. How long to wait for a decision before moving to the next node. A duration from `1m` to `168h`.
  - `raise_urgency` · boolean: `level` only. Raise the request to `interrupt` urgency before notifying.
  - `conditions` · array<EscalationPathCondition>: `if_else` only. Every condition must hold for `then` to run. From 1 to 10.
    - `type` · enum · required: The kind of test. `working_hours` tests whether a named window is open. `urgency` tests the request's current urgency. `request` tests the request itself. One of `working_hours`, `urgency`, `request`.
    - `working_hours_id` · string: `working_hours` only. The set to test.
    - `active` · boolean: `working_hours` only. `true` tests that the window is open, `false` that it is closed.
    - `urgency` · enum: `urgency` only. The urgency the request must have. One of `standard`, `interrupt`.
    - `when` · CELLeafCondition | CELAllCondition | CELAnyCondition | CELSomeCondition | CELEveryCondition: A condition tree. A leaf tests one field. all and any combine conditions. some and every test the items of a list field.
  - `then` · array<EscalationPathNode>: `if_else` only. The nodes to run when every condition holds. An empty list moves on to the next node.
  - `else` · array<EscalationPathNode>: `if_else` only. The nodes to run otherwise. An empty list moves on to the next node.
  - `working_hours_id` · string: `defer` only. The working-hours set to wait for.
  - `standard_only` · boolean: `defer` only. Let `interrupt` requests skip the wait.
- `repeat` · EscalationPathRepeat: Run the path again from the top when the nodes run out without a decision. Every condition is evaluated again on each run.
  - `times` · integer · required: How many extra runs, from 1 to 9.
  - `after` · string · required: How long to wait before each extra run. A duration from `1m` to `168h`.
- `document_version` · integer · required: The version of the document format.
- `warnings` · array<EscalationPathWarning> · required: Advisory findings about the document's targets. They are computed when a revision is created or activated, and the list is empty on plain reads. A warning never blocks anything: a path narrows who decides, it never grants.
  - `code` · enum · required: `team_members_cannot_decide`: `count` of the team's `member_count` members cannot decide requests, so routing to the team reaches fewer deciders than its size suggests. `path_may_reach_nobody`: some request's conditions leave no level to run, so such a request is routed to nobody and only break-glass reviewers can decide it; the team fields are absent. One of `team_members_cannot_decide`, `path_may_reach_nobody`.
  - `team_id` · uuid
  - `team_name` · string
  - `count` · integer: Members of the team who cannot decide requests.
  - `member_count` · integer: Active members of the team.

### Example

```bash
curl -X POST "$WITHHUMAN_URL/api/v1/escalation-paths/{path_key}/revisions" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "On-call engineers",
  "working_hours": [
    {
      "id": "uk-office",
      "name": "UK office hours",
      "timezone": "Europe/London",
      "intervals": [
        {
          "weekdays": [
            "mon"
          ],
          "start": "09:00",
          "end": "18:00"
        }
      ]
    }
  ],
  "nodes": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "type": "level",
      "targets": [
        {
          "type": "user",
          "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
        }
      ],
      "escalate_after": "15m",
      "raise_urgency": true,
      "conditions": [
        {
          "type": "working_hours",
          "working_hours_id": "string",
          "active": true,
          "urgency": "standard",
          "when": {
            "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
            "field": "/request/arguments/amount_cents",
            "operator": "exists",
            "value": {}
          }
        }
      ],
      "then": [
        {}
      ],
      "else": [
        {}
      ],
      "working_hours_id": "string",
      "standard_only": true
    }
  ],
  "repeat": {
    "times": 1,
    "after": "1h"
  }
}'
```

201 response

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "path_key": "string",
  "revision": 1,
  "is_active": true,
  "name": "On-call engineers",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z",
  "working_hours": [
    {
      "id": "uk-office",
      "name": "UK office hours",
      "timezone": "Europe/London",
      "intervals": [
        {
          "weekdays": [
            "mon"
          ],
          "start": "09:00",
          "end": "18:00"
        }
      ]
    }
  ],
  "nodes": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "type": "level",
      "targets": [
        {
          "type": "user",
          "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
        }
      ],
      "escalate_after": "15m",
      "raise_urgency": true,
      "conditions": [
        {
          "type": "working_hours",
          "working_hours_id": "string",
          "active": true,
          "urgency": "standard",
          "when": {
            "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
            "field": "/request/arguments/amount_cents",
            "operator": "exists",
            "value": {}
          }
        }
      ],
      "then": [
        {}
      ],
      "else": [
        {}
      ],
      "working_hours_id": "string",
      "standard_only": true
    }
  ],
  "repeat": {
    "times": 1,
    "after": "1h"
  },
  "document_version": 1,
  "warnings": [
    {
      "code": "team_members_cannot_decide",
      "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "team_name": "string",
      "count": 1,
      "member_count": 1
    }
  ]
}
```

## Retrieve an escalation path revision

`GET /api/v1/escalation-paths/{path_key}/revisions/{revision}`

Auth: Reviewer session cookie (`withhuman_session`) or personal API key (`Authorization: Bearer $WITHHUMAN_API_KEY`)

Requires: `escalation_path.read`

Returns one revision of a path, active or not, with its full document. Revisions of an archived path can still be retrieved.

### Request

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `path_key` | path | string | yes | The path's key. Lowercase letters, digits, dots, underscores and hyphens, up to 63 characters. You choose it when you create the first revision. |
| `revision` | path | int64 | yes | The revision number. Revisions count up from 1. |

### Response

| Status | Body | Description |
| --- | --- | --- |
| 200 | EscalationPathRevision | The revision |
| 400 | ErrorResponse | `revision` is not a positive integer |
| 401 | ErrorResponse | You are not signed in |
| 403 | ErrorResponse | You cannot read escalation paths |
| 404 | ErrorResponse | No such revision |

Response body (200):

- `id` · uuid · required
- `path_key` · string · required
- `revision` · int64 · required: The revision number. Revisions count up from 1.
- `is_active` · boolean · required: Whether requests are routed with this revision.
- `name` · string · required: The display name.
- `created_by_actor_id` · uuid · required: The membership or organization-key actor that created the revision.
- `created_at` · date-time · required
- `archived_at` · date-time: When the path was archived. Absent for a revision of a live path; an archived revision can no longer be activated.
- `working_hours` · array<WorkingHoursSet> · required: The named working-hours sets the nodes refer to.
  - `id` · string · required: A key for the set, unique within the document.
  - `name` · string · required: A display name.
  - `timezone` · string · required: An IANA timezone name, such as `Europe/London`.
  - `intervals` · array<WeekdayInterval> · required: The open windows. At least one.
    - `weekdays` · array<enum> · required: The days the window applies to.
    - `start` · string · required: When the window opens, as `HH:MM` in 24-hour time.
    - `end` · string · required: When the window closes, as `HH:MM` in 24-hour time.
- `nodes` · array<EscalationPathNode> · required: The nodes, in order.
  - `id` · uuid · required: An id for the node, unique within the path.
  - `type` · enum · required: The kind of node. One of `level`, `if_else`, `defer`.
  - `targets` · array<EscalationTarget>: `level` only. The people and teams to notify.
    - `type` · enum · required One of `user`, `team`, `broadcast`.
    - `id` · uuid: Required for user and team, absent for broadcast.
  - `escalate_after` · string: `level` only. How long to wait for a decision before moving to the next node. A duration from `1m` to `168h`.
  - `raise_urgency` · boolean: `level` only. Raise the request to `interrupt` urgency before notifying.
  - `conditions` · array<EscalationPathCondition>: `if_else` only. Every condition must hold for `then` to run. From 1 to 10.
    - `type` · enum · required: The kind of test. `working_hours` tests whether a named window is open. `urgency` tests the request's current urgency. `request` tests the request itself. One of `working_hours`, `urgency`, `request`.
    - `working_hours_id` · string: `working_hours` only. The set to test.
    - `active` · boolean: `working_hours` only. `true` tests that the window is open, `false` that it is closed.
    - `urgency` · enum: `urgency` only. The urgency the request must have. One of `standard`, `interrupt`.
    - `when` · CELLeafCondition | CELAllCondition | CELAnyCondition | CELSomeCondition | CELEveryCondition: A condition tree. A leaf tests one field. all and any combine conditions. some and every test the items of a list field.
  - `then` · array<EscalationPathNode>: `if_else` only. The nodes to run when every condition holds. An empty list moves on to the next node.
  - `else` · array<EscalationPathNode>: `if_else` only. The nodes to run otherwise. An empty list moves on to the next node.
  - `working_hours_id` · string: `defer` only. The working-hours set to wait for.
  - `standard_only` · boolean: `defer` only. Let `interrupt` requests skip the wait.
- `repeat` · EscalationPathRepeat: Run the path again from the top when the nodes run out without a decision. Every condition is evaluated again on each run.
  - `times` · integer · required: How many extra runs, from 1 to 9.
  - `after` · string · required: How long to wait before each extra run. A duration from `1m` to `168h`.
- `document_version` · integer · required: The version of the document format.
- `warnings` · array<EscalationPathWarning> · required: Advisory findings about the document's targets. They are computed when a revision is created or activated, and the list is empty on plain reads. A warning never blocks anything: a path narrows who decides, it never grants.
  - `code` · enum · required: `team_members_cannot_decide`: `count` of the team's `member_count` members cannot decide requests, so routing to the team reaches fewer deciders than its size suggests. `path_may_reach_nobody`: some request's conditions leave no level to run, so such a request is routed to nobody and only break-glass reviewers can decide it; the team fields are absent. One of `team_members_cannot_decide`, `path_may_reach_nobody`.
  - `team_id` · uuid
  - `team_name` · string
  - `count` · integer: Members of the team who cannot decide requests.
  - `member_count` · integer: Active members of the team.

### Example

```bash
curl -X GET "$WITHHUMAN_URL/api/v1/escalation-paths/{path_key}/revisions/{revision}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
```

200 response

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "path_key": "string",
  "revision": 1,
  "is_active": true,
  "name": "On-call engineers",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z",
  "working_hours": [
    {
      "id": "uk-office",
      "name": "UK office hours",
      "timezone": "Europe/London",
      "intervals": [
        {
          "weekdays": [
            "mon"
          ],
          "start": "09:00",
          "end": "18:00"
        }
      ]
    }
  ],
  "nodes": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "type": "level",
      "targets": [
        {
          "type": "user",
          "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
        }
      ],
      "escalate_after": "15m",
      "raise_urgency": true,
      "conditions": [
        {
          "type": "working_hours",
          "working_hours_id": "string",
          "active": true,
          "urgency": "standard",
          "when": {
            "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
            "field": "/request/arguments/amount_cents",
            "operator": "exists",
            "value": {}
          }
        }
      ],
      "then": [
        {}
      ],
      "else": [
        {}
      ],
      "working_hours_id": "string",
      "standard_only": true
    }
  ],
  "repeat": {
    "times": 1,
    "after": "1h"
  },
  "document_version": 1,
  "warnings": [
    {
      "code": "team_members_cannot_decide",
      "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "team_name": "string",
      "count": 1,
      "member_count": 1
    }
  ]
}
```

## Activate an escalation path revision

`POST /api/v1/escalation-paths/{path_key}/revisions/{revision}/activate`

Auth: Reviewer session cookie (`withhuman_session`) or personal API key (`Authorization: Bearer $WITHHUMAN_API_KEY`)

Requires: `escalation_path.activate`

Makes a revision the active one. Requests that reach a person from then on are routed with it. A request already waiting for review stays with the revision it was routed with, so its reviewers and timers do not change. Activating an older revision is how you roll back.

Pass the revision you expect to be active in `If-Match`, quoted, as returned in `ETag`. Pass `"0"` if no revision is active. If the active revision changed in the meantime, the call fails with 412 and nothing changes.

A revision of an archived path cannot be activated; the call fails with 409 `escalation_path_archived`.

### Request

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `path_key` | path | string | yes | The path's key. Lowercase letters, digits, dots, underscores and hyphens, up to 63 characters. You choose it when you create the first revision. |
| `revision` | path | int64 | yes | The revision number. Revisions count up from 1. |
| `If-Match` | header | string | yes | The revision you expect to be active, quoted, for example `"2"`. Take it from the `ETag` of your last read. If the active revision changed in the meantime, the call fails with 412 and nothing changes. Escalation paths and webhook endpoints accept `"0"` when no revision is active. Pipelines always have an active revision. |

### Response

| Status | Body | Description |
| --- | --- | --- |
| 200 | EscalationPathRevision | The revision, now active |
| 400 | ErrorResponse | `revision` or `If-Match` is malformed |
| 401 | ErrorResponse | You are not signed in |
| 403 | ErrorResponse | You cannot activate escalation paths |
| 404 | ErrorResponse | No such revision |
| 409 | ErrorResponse | The path is archived |
| 412 | ErrorResponse | `If-Match` does not match the active revision |
| 428 | ErrorResponse | The `If-Match` header is missing |

Response body (200):

- `id` · uuid · required
- `path_key` · string · required
- `revision` · int64 · required: The revision number. Revisions count up from 1.
- `is_active` · boolean · required: Whether requests are routed with this revision.
- `name` · string · required: The display name.
- `created_by_actor_id` · uuid · required: The membership or organization-key actor that created the revision.
- `created_at` · date-time · required
- `archived_at` · date-time: When the path was archived. Absent for a revision of a live path; an archived revision can no longer be activated.
- `working_hours` · array<WorkingHoursSet> · required: The named working-hours sets the nodes refer to.
  - `id` · string · required: A key for the set, unique within the document.
  - `name` · string · required: A display name.
  - `timezone` · string · required: An IANA timezone name, such as `Europe/London`.
  - `intervals` · array<WeekdayInterval> · required: The open windows. At least one.
    - `weekdays` · array<enum> · required: The days the window applies to.
    - `start` · string · required: When the window opens, as `HH:MM` in 24-hour time.
    - `end` · string · required: When the window closes, as `HH:MM` in 24-hour time.
- `nodes` · array<EscalationPathNode> · required: The nodes, in order.
  - `id` · uuid · required: An id for the node, unique within the path.
  - `type` · enum · required: The kind of node. One of `level`, `if_else`, `defer`.
  - `targets` · array<EscalationTarget>: `level` only. The people and teams to notify.
    - `type` · enum · required One of `user`, `team`, `broadcast`.
    - `id` · uuid: Required for user and team, absent for broadcast.
  - `escalate_after` · string: `level` only. How long to wait for a decision before moving to the next node. A duration from `1m` to `168h`.
  - `raise_urgency` · boolean: `level` only. Raise the request to `interrupt` urgency before notifying.
  - `conditions` · array<EscalationPathCondition>: `if_else` only. Every condition must hold for `then` to run. From 1 to 10.
    - `type` · enum · required: The kind of test. `working_hours` tests whether a named window is open. `urgency` tests the request's current urgency. `request` tests the request itself. One of `working_hours`, `urgency`, `request`.
    - `working_hours_id` · string: `working_hours` only. The set to test.
    - `active` · boolean: `working_hours` only. `true` tests that the window is open, `false` that it is closed.
    - `urgency` · enum: `urgency` only. The urgency the request must have. One of `standard`, `interrupt`.
    - `when` · CELLeafCondition | CELAllCondition | CELAnyCondition | CELSomeCondition | CELEveryCondition: A condition tree. A leaf tests one field. all and any combine conditions. some and every test the items of a list field.
  - `then` · array<EscalationPathNode>: `if_else` only. The nodes to run when every condition holds. An empty list moves on to the next node.
  - `else` · array<EscalationPathNode>: `if_else` only. The nodes to run otherwise. An empty list moves on to the next node.
  - `working_hours_id` · string: `defer` only. The working-hours set to wait for.
  - `standard_only` · boolean: `defer` only. Let `interrupt` requests skip the wait.
- `repeat` · EscalationPathRepeat: Run the path again from the top when the nodes run out without a decision. Every condition is evaluated again on each run.
  - `times` · integer · required: How many extra runs, from 1 to 9.
  - `after` · string · required: How long to wait before each extra run. A duration from `1m` to `168h`.
- `document_version` · integer · required: The version of the document format.
- `warnings` · array<EscalationPathWarning> · required: Advisory findings about the document's targets. They are computed when a revision is created or activated, and the list is empty on plain reads. A warning never blocks anything: a path narrows who decides, it never grants.
  - `code` · enum · required: `team_members_cannot_decide`: `count` of the team's `member_count` members cannot decide requests, so routing to the team reaches fewer deciders than its size suggests. `path_may_reach_nobody`: some request's conditions leave no level to run, so such a request is routed to nobody and only break-glass reviewers can decide it; the team fields are absent. One of `team_members_cannot_decide`, `path_may_reach_nobody`.
  - `team_id` · uuid
  - `team_name` · string
  - `count` · integer: Members of the team who cannot decide requests.
  - `member_count` · integer: Active members of the team.

### Example

```bash
curl -X POST "$WITHHUMAN_URL/api/v1/escalation-paths/{path_key}/revisions/{revision}/activate" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "If-Match: "2""
```

200 response

```json
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "path_key": "string",
  "revision": 1,
  "is_active": true,
  "name": "On-call engineers",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z",
  "working_hours": [
    {
      "id": "uk-office",
      "name": "UK office hours",
      "timezone": "Europe/London",
      "intervals": [
        {
          "weekdays": [
            "mon"
          ],
          "start": "09:00",
          "end": "18:00"
        }
      ]
    }
  ],
  "nodes": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "type": "level",
      "targets": [
        {
          "type": "user",
          "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71"
        }
      ],
      "escalate_after": "15m",
      "raise_urgency": true,
      "conditions": [
        {
          "type": "working_hours",
          "working_hours_id": "string",
          "active": true,
          "urgency": "standard",
          "when": {
            "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
            "field": "/request/arguments/amount_cents",
            "operator": "exists",
            "value": {}
          }
        }
      ],
      "then": [
        {}
      ],
      "else": [
        {}
      ],
      "working_hours_id": "string",
      "standard_only": true
    }
  ],
  "repeat": {
    "times": 1,
    "after": "1h"
  },
  "document_version": 1,
  "warnings": [
    {
      "code": "team_members_cannot_decide",
      "team_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "team_name": "string",
      "count": 1,
      "member_count": 1
    }
  ]
}
```
