---
title: "Record that the holder opened Voice Down or picked Escalate - dispatch"
method: POST
path: "/events/{event_id}/claim/acting"
tags: ["events"]
---

# Record that the holder opened Voice Down or picked Escalate - dispatch

`POST /events/{event_id}/claim/acting`

## Request

- Base URL: `https://api.verdun.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.verdun.ai/events/{event_id}/claim/acting`
- Auth: HTTP bearer

Claim-lock R2, the escalation record. The operator HOLDING this alarm tells the other consoles they are about to escalate, so they show "Escalation in progress". Body `{action: voice_down|dispatch, generation, action_token}`: `generation` is `claim.generation` (the ownership generation, which changes when the holder changes and never on a renewal), `action_token` a client nonce minted once per panel open. There is no expiry: the intent lasts while the alarm is this operator's and is cleared by `.../acting/cancel`, a close, a claim lapse or a take-over. Under the event row lock: a closed, expired or unqueued alarm is a plain 409; no live claim is 409 `claim_changed` (claim null); another operator's live claim is 409 `claim_held`; a stale `generation` is 409 `claim_changed` with the current claim; the same token and generation again is a 200 replay that writes nothing, and so is the token of an action that already finished (cancelled, completed, closed, lapsed or taken over) or was replaced by a newer pick (the row remembers the newest 32 per generation): `recorded: false, replay: true`, it is never revived and never overwrites the newer pick; a new pick needs a new token. Requires claim participation, central staff, and the action's own permission (`escalate_voice_down` / `escalate_dispatch`). 404 while `CLAIM_ESCALATION_ENABLED` is off (or site claims are on, or claim cleanup is off): read `claim_escalation_enabled` on `GET /auth/me` first.

## Path parameters

- `event_id` string, required

## Request body

- SetClaimActingRequest: Body of `POST /events/{id}/claim/acting`.
  - `action` 'voice_down' | 'dispatch', required: What the holder opened: the Voice Down panel, or Escalate - dispatch.
  - `generation` string, uuid, required: `claim.generation` the console holds. A stale one is rejected 409 `claim_changed`.
  - `action_token` string, required: A client nonce minted once per panel open (a UUID is fine); echo it on cancel.

## Response `200`

Successful Response

- ClaimActingResponse
  - `claim` AlarmClaim, required
    - `operator_id` string, required: The operator holding the alarm
    - `operator_name` string, nullable: Their display name; null if the operator no longer exists
    - `claimed_at` string, required: When the claim was taken (ISO 8601, UTC)
    - `expires_at` string, required: When the claim lapses (ISO 8601, UTC)
    - `expires_in_seconds` integer, required: Seconds left on the claim, computed server-side. Time the claim from this against the local clock at receipt, not from `expires_at`, so a skewed workstation clock does not move it.
    - `generation` string, nullable: Ownership generation (a UUID): it changes whenever the claim's HOLDER changes (acquire, take-over) and never on a renewal. Echo it on `POST /events/{id}/claim/acting` and its cancel; a write carrying an old one is rejected. Null while CLAIM_ESCALATION_ENABLED is off, or on a claim stamped before generations existed (the holder's next renew fills it in).
  - `activity` ActivityPayload
    - `state` 'preparing' | 'active', required: `active` iff at least one live session record exists (operator or automated). Otherwise `preparing`: a valid intent and no session yet.
    - `operator_acting` boolean, required: True iff a valid intent exists or a live session is attributed to an operator. The console shows no red cue while this is true; the age stays visible either way. False means only an automated agent call is live.
    - `since` string, required: `preparing`: the intent's set_at. `active`: the earliest live session start (ISO 8601, UTC)
    - `elapsed_seconds` integer, required: Server-computed now - since, for the age display; time it from this against the local clock at receipt
    - `action` 'voice_down' | 'dispatch', required: Of the primary source
    - `actor` ActivityActor, required
      - `operator_id` string, nullable: The operator acting. Null for an automated agent call.
      - `operator_name` string, nullable: Their display name; null if the operator no longer exists or kind is agent.
      - `kind` 'operator' | 'agent', required: `agent` is an automated AI call: it never counts as an operator acting.
    - `intent` ActivityIntent
      - `action` 'voice_down' | 'dispatch', required: What the holder opened: the Voice Down panel, or Escalate - dispatch.
      - `set_at` string, required: When the holder opened Voice Down / picked dispatch (ISO 8601, UTC)
      - `operator_id` string, required: The operator who recorded the intent (the claim holder when it was set)
      - `operator_name` string, nullable: Their display name; null if the operator no longer exists
      - `generation` string, required: The ownership generation the intent is bound to
    - `sessions` ActivitySession[]: Live records, oldest first, at most five. Empty while `preparing`.
      - `source` 'voice_session' | 'voice_agent_call' | 'external_talkdown' | 'dispatch_call', required: Which session table the live record comes from.
      - `session_id` string, required: The id of that session record
      - `action` 'voice_down' | 'dispatch', required: `dispatch` is the grouping for every dispatch_call row; `target` says which.
      - `target` 'police' | 'guard' | 'owner', nullable: Dispatch rows only: who was dialled. An owner call is activity but is not police dispatch.
      - `status` string, required: The source's own status word (opening/live, placing/connected, requested/connected, the dispatch status)
      - `started_at` string, required: When the record started being live (ISO 8601, UTC); the source's own start time
      - `actor` ActivityActor, required
        - `operator_id` string, nullable: The operator acting. Null for an automated agent call.
        - `operator_name` string, nullable: Their display name; null if the operator no longer exists or kind is agent.
        - `kind` 'operator' | 'agent', required: `agent` is an automated AI call: it never counts as an operator acting.
  - `recorded` boolean: True when the intent is recorded (a new write or an exact replay of the current one). False when the token belongs to an action that already finished (cancelled, completed, closed, lapsed, taken over) or was replaced by a newer pick: it is never revived or applied, `activity` is the state as it is, and a new pick needs a new token.
  - `replay` boolean: True when nothing was written because this token and generation were already seen (recorded or finished)

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/verdun/apis/verdun-api.md) - [All operations](https://skmtc.dev/verdun/apis/verdun-api/llms.txt) - [OpenAPI document](https://skmtc.dev/verdun/apis/verdun-api/revisions/35a2a6ebedda?raw)
