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

# Policy layers

> Add, update, reorder, and remove layers from an escalation policy.

Policy layers are the ordered steps in an escalation policy. When an incident fires, scaling.cloud notifies the `position: 1` layer first. If that layer does not acknowledge within `ackTimeoutMinutes`, it moves to `position: 2`, and so on.

<Note>
  Layers are sub-resources of policies. All layer endpoints require the parent `policyId` in the path. To manage the policy itself, see [Policies](/api/escalation/policies).
</Note>

## Layer targets

Each layer has a `target` that specifies who to notify. The `target` field is a discriminated union on `type`:

| `type`     | Additional fields     | Description                                                 |
| ---------- | --------------------- | ----------------------------------------------------------- |
| `schedule` | `scheduleId` (UUID)   | Notify whoever is currently on call for the given schedule. |
| `users`    | `userIds` (string\[]) | Notify a specific set of users directly.                    |

***

## `POST /escalation/policies/{policyId}/layers`

Add a layer to an escalation policy. You can specify the `position` to insert the layer at a particular point in the escalation sequence.

<Tip>
  Use `PUT /escalation/policies/{policyId}/layers/order` after adding multiple layers to set the final escalation order in one request.
</Tip>

### Path parameters

<ParamField path="policyId" type="string" required>
  The UUID of the policy to add the layer to.
</ParamField>

### Request body

<ParamField body="position" type="number" required>
  1-based position of this layer in the escalation sequence. Position `1` is notified first. Must be a positive integer.
</ParamField>

<ParamField body="ackTimeoutMinutes" type="number" required>
  Number of minutes to wait for an acknowledgment before escalating to the next layer. Minimum `1`, maximum `10080` (7 days).
</ParamField>

<ParamField body="target" type="object" required>
  The notification target for this layer. Must be one of:

  **Schedule target** — notify the current on-call for a schedule:

  ```json theme={null}
  { "type": "schedule", "scheduleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
  ```

  **Users target** — notify specific users directly:

  ```json theme={null}
  { "type": "users", "userIds": ["user_aaa111", "user_bbb222"] }
  ```
</ParamField>

### Response fields

<ResponseField name="data" type="object" required>
  The created policy layer.

  <Expandable title="Layer object fields">
    <ResponseField name="id" type="string" required>
      Unique layer ID (UUID).
    </ResponseField>

    <ResponseField name="policyId" type="string" required>
      ID of the parent escalation policy.
    </ResponseField>

    <ResponseField name="orgId" type="string" required>
      The organization this layer belongs to.
    </ResponseField>

    <ResponseField name="position" type="number" required>
      1-based position in the escalation sequence.
    </ResponseField>

    <ResponseField name="ackTimeoutMinutes" type="number" required>
      Minutes to wait before escalating to the next layer.
    </ResponseField>

    <ResponseField name="target" type="object" required>
      The notification target. Either `{ type: "schedule", scheduleId }` or `{ type: "users", userIds }`.
    </ResponseField>

    <ResponseField name="createdAt" type="string" required>
      ISO 8601 creation timestamp.
    </ResponseField>

    <ResponseField name="updatedAt" type="string" required>
      ISO 8601 last-updated timestamp.
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL — schedule target theme={null}
  curl --request POST \
    --url https://api.scaling.cloud/v1/escalation/policies/d4e5f6a7-b8c9-0123-defa-234567890123/layers \
    --header 'Authorization: Bearer scl_live_your_api_key_here' \
    --header 'Content-Type: application/json' \
    --data '{
      "position": 1,
      "ackTimeoutMinutes": 5,
      "target": {
        "type": "schedule",
        "scheduleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
      }
    }'
  ```

  ```bash cURL — users target theme={null}
  curl --request POST \
    --url https://api.scaling.cloud/v1/escalation/policies/d4e5f6a7-b8c9-0123-defa-234567890123/layers \
    --header 'Authorization: Bearer scl_live_your_api_key_here' \
    --header 'Content-Type: application/json' \
    --data '{
      "position": 2,
      "ackTimeoutMinutes": 10,
      "target": {
        "type": "users",
        "userIds": ["user_mgr001", "user_mgr002"]
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "id": "f6a7b8c9-d0e1-2345-fabc-456789012345",
      "policyId": "d4e5f6a7-b8c9-0123-defa-234567890123",
      "orgId": "org_2abc123def456",
      "position": 1,
      "ackTimeoutMinutes": 5,
      "target": {
        "type": "schedule",
        "scheduleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
      },
      "createdAt": "2026-04-07T10:00:00.000Z",
      "updatedAt": "2026-04-07T10:00:00.000Z"
    }
  }
  ```

  ```json 400 — invalid target theme={null}
  {
    "statusCode": 400,
    "type": "invalid_request_error",
    "code": "invalid_target",
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
  ```

  ```json 404 — policy not found theme={null}
  {
    "statusCode": 404,
    "type": "invalid_request_error",
    "code": "not_found",
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
  ```
</ResponseExample>

### Error codes

| HTTP  | Code             | Description                                                                                         |
| ----- | ---------------- | --------------------------------------------------------------------------------------------------- |
| `400` | `invalid_target` | The referenced `scheduleId` does not exist in your organization, or the target object is malformed. |
| `401` | `not_authorized` | Missing or invalid API key.                                                                         |
| `404` | `not_found`      | No policy found with the given `policyId`.                                                          |
| `500` | `server_error`   | Unexpected server error.                                                                            |

***

## `PATCH /escalation/policies/{policyId}/layers/{layerId}`

Update one or more fields on an existing policy layer. All fields are optional — only the fields you include are updated.

### Path parameters

<ParamField path="policyId" type="string" required>
  The UUID of the parent escalation policy.
</ParamField>

<ParamField path="layerId" type="string" required>
  The UUID of the layer to update.
</ParamField>

### Request body

<ParamField body="ackTimeoutMinutes" type="number">
  Updated acknowledgment timeout in minutes. Minimum `1`, maximum `10080`.
</ParamField>

<ParamField body="target" type="object">
  Updated notification target. Replaces the existing target entirely. Must be a valid `schedule` or `users` target object.
</ParamField>

### Response fields

<ResponseField name="data" type="object" required>
  The updated policy layer object.
</ResponseField>

<RequestExample>
  ```bash cURL — update timeout theme={null}
  curl --request PATCH \
    --url https://api.scaling.cloud/v1/escalation/policies/d4e5f6a7-b8c9-0123-defa-234567890123/layers/f6a7b8c9-d0e1-2345-fabc-456789012345 \
    --header 'Authorization: Bearer scl_live_your_api_key_here' \
    --header 'Content-Type: application/json' \
    --data '{
      "ackTimeoutMinutes": 15
    }'
  ```

  ```bash cURL — change target to a different schedule theme={null}
  curl --request PATCH \
    --url https://api.scaling.cloud/v1/escalation/policies/d4e5f6a7-b8c9-0123-defa-234567890123/layers/f6a7b8c9-d0e1-2345-fabc-456789012345 \
    --header 'Authorization: Bearer scl_live_your_api_key_here' \
    --header 'Content-Type: application/json' \
    --data '{
      "target": {
        "type": "schedule",
        "scheduleId": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "id": "f6a7b8c9-d0e1-2345-fabc-456789012345",
      "policyId": "d4e5f6a7-b8c9-0123-defa-234567890123",
      "orgId": "org_2abc123def456",
      "position": 1,
      "ackTimeoutMinutes": 15,
      "target": {
        "type": "schedule",
        "scheduleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
      },
      "createdAt": "2026-04-07T10:00:00.000Z",
      "updatedAt": "2026-04-07T11:30:00.000Z"
    }
  }
  ```

  ```json 400 — invalid target theme={null}
  {
    "statusCode": 400,
    "type": "invalid_request_error",
    "code": "invalid_target",
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
  ```

  ```json 404 theme={null}
  {
    "statusCode": 404,
    "type": "invalid_request_error",
    "code": "not_found",
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
  ```
</ResponseExample>

### Error codes

| HTTP  | Code             | Description                                                                              |
| ----- | ---------------- | ---------------------------------------------------------------------------------------- |
| `400` | `invalid_target` | The referenced schedule does not exist in your organization, or the target is malformed. |
| `401` | `not_authorized` | Missing or invalid API key.                                                              |
| `404` | `not_found`      | No layer found with the given `layerId` on this policy.                                  |
| `500` | `server_error`   | Unexpected server error.                                                                 |

***

## `DELETE /escalation/policies/{policyId}/layers/{layerId}`

Remove a layer from an escalation policy. This action is permanent.

### Path parameters

<ParamField path="policyId" type="string" required>
  The UUID of the parent escalation policy.
</ParamField>

<ParamField path="layerId" type="string" required>
  The UUID of the layer to delete.
</ParamField>

### Response fields

<ResponseField name="success" type="boolean" required>
  `true` when the layer was deleted.
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request DELETE \
    --url https://api.scaling.cloud/v1/escalation/policies/d4e5f6a7-b8c9-0123-defa-234567890123/layers/f6a7b8c9-d0e1-2345-fabc-456789012345 \
    --header 'Authorization: Bearer scl_live_your_api_key_here'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "success": true
  }
  ```

  ```json 404 theme={null}
  {
    "statusCode": 404,
    "type": "invalid_request_error",
    "code": "not_found",
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
  ```
</ResponseExample>

### Error codes

| HTTP  | Code             | Description                                             |
| ----- | ---------------- | ------------------------------------------------------- |
| `401` | `not_authorized` | Missing or invalid API key.                             |
| `404` | `not_found`      | No layer found with the given `layerId` on this policy. |
| `500` | `server_error`   | Unexpected server error.                                |

***

## `PUT /escalation/policies/{policyId}/layers/order`

Reorder all layers in a policy by providing the complete ordered list of layer IDs. The first ID in `layerIds` becomes `position: 1`, the second becomes `position: 2`, and so on.

You must include every layer ID that belongs to the policy — partial lists are rejected.

<Tip>
  Use this endpoint after adding multiple layers to set the final escalation order in a single request, rather than updating each layer's `position` individually.
</Tip>

<Note>
  `position` determines the escalation order — layer at `position: 1` is always notified first. Reordering layers directly changes who gets paged and when during an active incident response.
</Note>

### Path parameters

<ParamField path="policyId" type="string" required>
  The UUID of the escalation policy whose layers you want to reorder.
</ParamField>

### Request body

<ParamField body="layerIds" type="string[]" required>
  Complete ordered list of layer IDs in the desired escalation sequence. Must include all existing layer IDs for this policy — no more, no fewer. Accepts 1–50 IDs.
</ParamField>

### Response fields

<ResponseField name="data" type="object[]" required>
  The full list of policy layers in their new order, with updated `position` values.
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl --request PUT \
    --url https://api.scaling.cloud/v1/escalation/policies/d4e5f6a7-b8c9-0123-defa-234567890123/layers/order \
    --header 'Authorization: Bearer scl_live_your_api_key_here' \
    --header 'Content-Type: application/json' \
    --data '{
      "layerIds": [
        "a7b8c9d0-e1f2-3456-abcd-567890123456",
        "f6a7b8c9-d0e1-2345-fabc-456789012345"
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": [
      {
        "id": "a7b8c9d0-e1f2-3456-abcd-567890123456",
        "policyId": "d4e5f6a7-b8c9-0123-defa-234567890123",
        "orgId": "org_2abc123def456",
        "position": 1,
        "ackTimeoutMinutes": 10,
        "target": {
          "type": "users",
          "userIds": ["user_mgr001", "user_mgr002"]
        },
        "createdAt": "2026-01-05T08:12:00.000Z",
        "updatedAt": "2026-04-07T12:00:00.000Z"
      },
      {
        "id": "f6a7b8c9-d0e1-2345-fabc-456789012345",
        "policyId": "d4e5f6a7-b8c9-0123-defa-234567890123",
        "orgId": "org_2abc123def456",
        "position": 2,
        "ackTimeoutMinutes": 15,
        "target": {
          "type": "schedule",
          "scheduleId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
        },
        "createdAt": "2026-04-07T10:00:00.000Z",
        "updatedAt": "2026-04-07T12:00:00.000Z"
      }
    ]
  }
  ```

  ```json 400 — mismatched layer IDs theme={null}
  {
    "statusCode": 400,
    "type": "invalid_request_error",
    "code": "invalid_reorder",
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
  ```

  ```json 404 — policy not found theme={null}
  {
    "statusCode": 404,
    "type": "invalid_request_error",
    "code": "not_found",
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
  ```
</ResponseExample>

### Error codes

| HTTP  | Code              | Description                                                                             |
| ----- | ----------------- | --------------------------------------------------------------------------------------- |
| `400` | `invalid_reorder` | The provided `layerIds` do not exactly match the set of existing layers on this policy. |
| `401` | `not_authorized`  | Missing or invalid API key.                                                             |
| `404` | `not_found`       | No policy found with the given `policyId`.                                              |
| `500` | `server_error`    | Unexpected server error.                                                                |
