---
title: "Hand a page to somebody else"
method: POST
path: "/api/{org_id}/oncall/responses/{response_id}/handoff"
tags: ["OnCall"]
---

# Hand a page to somebody else

`POST /api/{org_id}/oncall/responses/{response_id}/handoff`

## Request

- Base URL: `https://api.openobserve.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.openobserve.ai/api/{org_id}/oncall/responses/{response_id}/handoff`
- Auth: API key in header `Authorization`
- TypeScript: <https://skmtc.dev/openobserve/apis/openobserve-api-http/docs/api/:org_id/oncall/responses/:response_id/handoff/post.ts> (a function with typed inputs; its response is checked against the schema)

## Path parameters

- `org_id` string, required
- `response_id` string, required

## Request body

- HandoffRequest: Exactly one of `to` (a person here) or `to_team_id` (the other team's on-call is paged).
  - `note` string, nullable
  - `to` string, nullable
  - `to_team_id` string, nullable

## Response `200`

Success

- OnCallResponse: The record itself, as the API and the UI see it.
  - `acked_at` integer, nullable
  - `acked_by` string, nullable
  - `cause` 'config_change_or_deploy' | 'capacity_or_load' | 'dependency_failure' | 'expected_or_maintenance' | 'noisy_threshold' | 'data_or_ingestion_issue' | 'genuine_defect' | 'still_unknown': Why a page turned out to happen. A fixed list rather than free text, so the next firing of the same rule can say "3× config change". Free text fragments into near-duplicates and never groups. Nuance goes in `cause_note`.
  - `cause_note` string, nullable: The sentence beside the structured cause. One dropdown plus one line is the whole ask — anything longer does not get filled in at 3am.
  - `closed_at` integer, nullable
  - `exhausted_at` integer, nullable: When the ladder ran out with nobody answering. `None` while it is still climbing, or if somebody took it first. Deliberately NOT a `ResponseState`. An exhausted page can still be acknowledged and resolved, so a lifecycle state would force a false either/or: exhaustion is a property of the ladder, the state is a property of the human.
  - `id` string, required
  - `incident_id` string, nullable: Set only when this firing also produced an incident. A record is never owned by an incident, so this stays `None` for most firings.
  - `ladder_anchor` integer, nullable: Where step delays count from: `opened_at`, moved by a snooze or a triage-held first page.
  - `ladder_run` integer, nullable: Which run of the ladder the record is on. Handing a page to another person or team starts a new run, and the ledger is read per run — which is what makes the receiving responder's ladder begin at its first rung. Absent means the first run.
  - `opened_at` integer, required
  - `org_id` string, required
  - `origin_response_id` string, nullable: For an impacted record, the owner record it was opened alongside.
  - `priority` integer, required: `AlertPriority::to_i32` — the same scale alerts already use.
  - `responder_role` 'owner' | 'impacted': Why this team was paged. A database goes down and five services break. The owner fixes the database; the impacted teams contain the blast radius on their own service. Different jobs, so they get different records, and each team acks and resolves its own.
  - `snoozed_until` integer, nullable: Quiet until this instant, in micros. Not an acknowledgement: snoozing says "I know, stop shouting", not "I have this". The record stays open and unowned and the ladder resumes when it expires — which is what makes it safe to offer.
  - `state` 'triggered' | 'triaged' | 'acknowledged' | 'resolved', required: Lifecycle of a response record: `triggered → triaged → acknowledged → resolved`. `triaged` comes from the L0 agent and is skipped entirely when the agent is absent or disabled.
  - `subject` SubjectRef, required: Points at one firing of one thing. `source_id` is the rule or check that produced it; `firing` counts firings of that source. Together they form the `subject_id` stored on the record.
    - `firing` integer, required: 1-based firing counter. The first firing of a source is `#1`.
    - `source_id` string, required: The rule, check or incident this firing came from.
    - `subject_type` 'alert' | 'incident', required: What kind of thing paged a human.
  - `team_id` string, nullable: The team that owns this firing, or `None` when routing found nobody. A teamless record pages nobody — no policy, no rotation, no ladder — and exists so the firing appears beside the ones that did page. Handing it to a team gives it an owner and starts its ladder (R-D6).
  - `title` string, nullable: What the page is about. Kept on the record so it survives the alert being renamed or deleted.
  - `updated_at` integer: Revision of the write this record came from, and what a replica accepts or refuses a snapshot on. The queue redelivers an unacked message behind newer ones, so a blind apply lets an older snapshot un-acknowledge a page that a human already answered.

---

[API](https://skmtc.dev/openobserve/apis/openobserve-api-http.md) - [All operations](https://skmtc.dev/openobserve/apis/openobserve-api-http/llms.txt) - [OpenAPI document](https://skmtc.dev/openobserve/apis/openobserve-api-http/revisions/0529b8a10252?raw)
