{
  "components": {
    "securitySchemes": {
      "access_token": {
        "bearerFormat": "Opaque access token",
        "description": "A responder's own access token, from `POST /api/v1/auth/login` or\n`POST /api/v1/auth/refresh`. Opaque and database-backed, never a JWT, so\nrevoking one stops it on the next request (`docs/AUTHENTICATION.md` §6).\n\nIt lives 15 minutes. Most of `/api/v1` accepts one up to five minutes\npast expiry, because a phone waking to a page must be able to\nacknowledge before its refresh completes; the routes that change *who\ngets paged* do not, and say so in their description.\n",
        "scheme": "bearer",
        "type": "http"
      },
      "account_token": {
        "bearerFormat": "art_…",
        "description": "An account-level API token, the alternative to a sync integration key on\nLane B when one caller acts for several sources. Returned once at\ncreation; only its digest is stored. `docs/LANE_B_API.md` §3.\n",
        "scheme": "bearer",
        "type": "http"
      },
      "async_key": {
        "bearerFormat": "ark_async_…",
        "description": "An async integration key, held by a monitor firing events at Lane A\n(`POST /api/v2/enqueue`). Scoped to one source.\n\nAn `ark_sync_…` key is **refused** here, and there is no account-level\nAPI token on this lane at all: a token names its source per request, and\na firehose credential that could name any source would let every monitor\nraise events as every other one. `docs/LANE_A_API.md` §3.\n",
        "scheme": "bearer",
        "type": "http"
      },
      "lead_signature": {
        "description": "`t=<unix>,v1=<hex>`: HMAC-SHA256 over `\"<t>.<raw body>\"` with the secret\n`X-AlertRoster-Key` names: `platform` (the shared platform secret) or\n`partner` (the partner's own callback secret). Five minutes either way.\nThe same scheme AlertRoster signs its own callbacks with.\n`docs/REFERRAL_LEADS.md` §3.\n",
        "in": "header",
        "name": "X-AlertRoster-Signature",
        "type": "apiKey"
      },
      "sync_key": {
        "bearerFormat": "ark_sync_…",
        "description": "A sync integration key, held by a ticket system of record calling Lane B\n(`/api/v2/incidents`). Scoped to one source. An `ark_async_…` key is\nrefused here. `docs/LANE_B_API.md` §3.\n",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "AlertRoster is a call-out notification and escalation tool: an event becomes\nan incident, the incident pages the people a schedule says are on call, and\nit keeps paging until somebody acknowledges.\n\nThis document is generated from the application's own router, so every\nendpoint it serves appears here and nothing else does.\n\n## Two lanes, two kinds of caller\n\n`/api/v1` is authenticated as a **responder** holding an access token. It\nis what the iOS and desktop clients are written against, and what a person\nacting on their own behalf uses.\n\n`/api/v2` is authenticated as a **system**: an integration key or an\naccount-level API token, held by a monitor or a ticket system acting on\nbehalf of a ticket rather than a person. The two must not be reachable with\neach other's credentials, which is what the lane on the key is for.\n\n## Conventions\n\nRequests with a body send `Content-Type: application/json`; every response\nis JSON. Identifiers are UUIDs. Timestamps are ISO 8601 in UTC, to the\nsecond.\n\nFailures answer a machine-readable code rather than prose:\n`{\"error\": \"not_found\"}`, `{\"error\": \"invalid_credentials\"}`. A `422` adds a\nper-field `details` object: `{\"error\": \"invalid_request\", \"details\":\n{\"deadline_at\": [\"must be in the future\"]}}`.\n\nEvery transition is a `POST` naming what it does (`acknowledge`, `resolve`,\n`arm`, `satisfy`) rather than a `PATCH` carrying a state. A caller that\nnames the transition it wants cannot ask for one the transition table would\nrefuse.\n\n## Not in this document\n\nTwo WebSocket surfaces, because OpenAPI does not describe them: the\nincident channel at `/socket` (`docs/INCIDENT_CHANNEL.md`) carrying live\nincident state and presence, and the agent channel at `/agent`\n(`docs/AGENT_API.md`) carrying the command set for the on-prem local agent.\n",
    "license": {
      "name": "Proprietary"
    },
    "title": "AlertRoster API",
    "version": "1.3.53"
  },
  "openapi": "3.0.3",
  "paths": {
    "/api/v1/incidents/{id}/search/locate": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Queues a command the phone answers on its next wake. The device is never\ntold why (`docs/CHECKIN_API.md` §15), and this route answers with the\ncommand rather than a position, because the fix has not happened yet.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_locate",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "command": {
                    "id": "77aa…",
                    "kind": "locate",
                    "status": "queued"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Command queued."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Ask the subject's device for a fresh fix",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Oldest first, after `after_seq` (exclusive), or the latest `limit`\nbefore `before_seq` to open at the end and scroll back, at most `limit`\n(default 200, max 500), with `has_more`: the message object of\n`docs/INCIDENT_API.md` §23.2, plus `conversation_id` and, on a `system`\nmessage, `event`. `seq` rises within a conversation but is not dense.\n`docs/CHAT_API.md` §5.",
        "operationId": "v2_chat_message_index",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Return messages with a `seq` greater than this. Default 0.",
            "in": "query",
            "name": "after_seq",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Return the latest messages with a `seq` less than this.",
            "in": "query",
            "name": "before_seq",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "At most this many messages, 1 to 500. Default 200.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "c41d…",
                  "has_more": false,
                  "messages": [
                    {
                      "body": "Sector 4 is clear.",
                      "conversation_id": "c41d…",
                      "event": null,
                      "id": "8e2a…",
                      "incident_id": null,
                      "kind": "text",
                      "seq": 41
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Read a conversation's messages",
        "tags": [
          "chat"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "As `docs/INCIDENT_API.md` §23.1: `client_message_id` makes it\nidempotent (`201` new, `200` a resend), `kind` is `text`, `location` or\n`location_request`, and where you were rides along. In an incident's\nconversation this is a post to the incident's thread. Elsewhere you\nmust be in the conversation (`403`), and it must not be archived\n(`409`). The answer carries the message's `pts` in the stream, for an\noptimistic client to reconcile. Optional: `mentions` (structured spans,\n§13), `thread_root_id` with `also_send_to_conversation` (a reply, §12),\n`forward_of_message_id` (§17). Rich messages (§19), in a channel, DM or\ngroup only: `kind` `poll` with `poll`, `checklist` with `checklist`,\n`voice_note` with `voice_note_id`; `blocks` and `file_ids` (up to 10\ncompleted uploads of yours, §20.2) on a `text`; `live` on a\n`location`. Anything with no words for a plain leg is `422`.\n`docs/CHAT_API.md` §5.",
        "operationId": "v2_chat_message_create",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "body": "Sector 4 is clear.",
                "client_message_id": "a1b2c3d4-5e6f-…",
                "kind": "text"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "kind": "text",
                    "seq": 41
                  },
                  "pts": 1043
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Post to a conversation",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/incidents/{id}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "There is deliberately **no list route** on this lane: a ticket system\nholds the ids it created, and an account-wide list would make one source's\nkey a bulk reader of every incident in the tenant.",
        "operationId": "v2_incident_show",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "id": "4c1f…",
                    "status": "triggered"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "sync_key": []
          },
          {
            "account_token": []
          }
        ],
        "summary": "Read an incident",
        "tags": [
          "lane-b"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Title and urgency: what the incident *says*, never what it *is*. The\nstatus moves only through the transitions below.",
        "operationId": "v2_incident_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "title": "Payment gateway timeouts (EU only)",
                "urgency": "low"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "id": "4c1f…",
                    "title": "Payment gateway timeouts (EU only)"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "sync_key": []
          },
          {
            "account_token": []
          }
        ],
        "summary": "Revise what an incident says",
        "tags": [
          "lane-b"
        ]
      }
    },
    "/api/v2/chat/broadcasts/{broadcast_id}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "An account admin: each recipient, when they acknowledged (`null` if\nthey have not), and the incident they were escalated with.\n`docs/CHAT_API.md` §25.",
        "operationId": "v2_chat_command_broadcast_status",
        "parameters": [
          {
            "description": "The broadcast id.",
            "in": "path",
            "name": "broadcast_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "broadcast": {
                    "id": "b7e2…",
                    "recipients": [
                      {
                        "acknowledged_at": "…",
                        "incident_id": null,
                        "name": "Sam Reyes",
                        "user_id": "9a2b…"
                      }
                    ]
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Who has acknowledged a broadcast",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/receivers/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Revokes its certificate. The device stops being able to connect immediately.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "receiver_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a receiver",
        "tags": [
          "receivers"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "The per-unit place settings (`docs/RECEIVER_API.md` §7a). `measured_power`\nis the reference RSSI at one metre and is a property of *this board in\nits enclosure at its mounting*, not of the model, which is why\ncorrecting a badly-sited unit is this call rather than a reflash. The\nnew config is pushed to the board on the channel at once, and again\nwhenever it rejoins.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "receiver_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "measured_power": -65,
                "place_advertising": true,
                "place_id": "7c1e…",
                "tx_power_dbm": -12
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "receiver": {
                    "id": "bb22…",
                    "measured_power": -65,
                    "place_advertising": true,
                    "place_id": "7c1e…",
                    "tx_power_dbm": -12
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Assign a receiver to a place, and trim its radio",
        "tags": [
          "receivers"
        ]
      }
    },
    "/api/v1/satellite/sos_reports": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Under Bluetooth only there is no Outbound webhook, so an SOS the app\ndeclares reaches Garmin Response and nothing reaches AlertRoster. This\nis how the roster hears of it. A declared report (`declared` the\nliteral `true`) is folded into the responder's open check-in-miss\nincident exactly as a delivered Declare SOS is (promoted to\n`emergency`) or opens its own. A declare the radio **refused** carries\n`refused`: `already_in_emergency` takes that same road, because one is\nactive on that unit and nothing else will say so, while every other\nreason is recorded as a failed declare and alarmed, never paged. A\nreport with neither is a rehearsal, recorded and never an emergency.\nIdempotent on `report_id` (a retry must resend the stored report\nunchanged), and the unit must be one an administrator registered to the\ncaller. `origin` is `auto` (the automatic SOS on a missed check-in) or\n`manual` (the responder pressed the panic control); absent reads\n`auto`. A `manual` declare never lands on a check-in-miss incident: it\nopens its own at `emergency`. `docs/SATELLITE_API.md` §14.6.",
        "operationId": "satellite_sos_report_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "battery_percent": 14,
                "checkin_id": "c7d2…",
                "declared": false,
                "declared_at": "2026-09-21T14:02:11Z",
                "imei": "300434030000001",
                "origin": "auto",
                "point": {
                  "latitude": 47.6062,
                  "longitude": -122.3321
                },
                "refused": "already_in_emergency",
                "refused_detail": "the radio is already in an emergency",
                "report_id": "9b1c…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "outcome": "declared",
                  "status": "accepted"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Stored, or already stored; processing follows."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Report an SOS the app declared, refused or rehearsed",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/files": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Every file posted in it, newest first, for its files browser.\n`kind` (`image`, `video`, `audio`, `pdf`, `file`), `user_id`, and\n`before` (a file id) with `limit` (1 to 200, default 50) to page.\n`docs/CHAT_API.md` §20.7.",
        "operationId": "v2_chat_file_index",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "0b6f…",
                  "files": [
                    {
                      "filename": "ridge.jpg",
                      "id": "7d1c…",
                      "kind": "image",
                      "thumbnails": [
                        "thumb_64"
                      ]
                    }
                  ],
                  "has_more": false
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "A conversation's files",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/cases/{id}/sightings": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`observed_at`, `latitude`, `longitude` and `confidence` (`certain`,\n`probable`, `possible`) are required. `observed_at` is when it was seen,\nnever defaulted to now. Arrives `unreviewed`. `409 case_finished` on a\nrecovered or closed case. `docs/CASES_API.md` §6.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "case_create_sighting",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "accuracy_m": 25,
                "confidence": "probable",
                "latitude": 32.7581,
                "longitude": -97.3274,
                "notes": "Running north on Main, no collar visible",
                "observed_at": "2026-10-05T19:05:00Z"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "sighting": {
                    "id": "40aa…",
                    "source": "coordinator",
                    "status": "unreviewed"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Added."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Add a sighting",
        "tags": [
          "cases"
        ]
      }
    },
    "/api/v1/checkins/location": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "A client asks this before every capture, to know whether to attach a\nposition at all, which is why it is on the hot half with the transitions\nrather than behind a fresh token. `track` carries the sampling cadence for\ncontinuous capture, advertised rather than fixed so it moves without a\nclient release.",
        "operationId": "checkin_location_status",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "location_opt_in": false,
                  "track": {
                    "distance_m": 50,
                    "final_interval_seconds": 60,
                    "final_lead_seconds": 900,
                    "interval_seconds": 180
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Whether you have opted in to location",
        "tags": [
          "checkins"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Withdrawing also purges what was already captured, and is deliberately\n**not** gated on the account feature flag: a flag may stop somebody\ncollecting more, it may not trap them into keeping what is there.\n`docs/POSITIONING_AND_CLAIMS.md` §3.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_put_location_opt_in",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "opt_in": true
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "location_opt_in": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Grant or withdraw location consent",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/poll/close": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Its author, an account admin, or the channel's owner or an admin of\nit. Closing a closed poll changes nothing. `docs/CHAT_API.md` §19.4.",
        "operationId": "v2_chat_message_close_poll",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "poll": {
                      "closed": true,
                      "closed_at": "…"
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Close a poll",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/presence": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "For each of `user_ids` (comma-separated, at most 500, the account's\npeople; anybody else is left out): `state` `active` (holding a chat\nstream, not set away) or `away`, `on_call` (a schedule resolves to them\nnow) and `status`. Live changes come on the chat socket as `presence`\nand `status` pushes. `docs/CHAT_API.md` §11.4.",
        "operationId": "v2_chat_account_presence",
        "parameters": [
          {
            "description": "Comma-separated user ids, at most 500.",
            "in": "query",
            "name": "user_ids",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "presence": [
                    {
                      "on_call": true,
                      "state": "active",
                      "status": null,
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Who is around",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/{id}/details": {
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "A sentence and a pin are both answers, and they are independent: send\neither, both, or neither. Read it back on the check-in object rather than\nhere (`docs/CHECKIN_API.md` §16).\n\nThe coordinates are encrypted at rest, so this answers\n`503 encryption_unavailable` when one is sent and the deployment has\nconfigured no encryption key, as `PUT /checkins/profile` does. The text\nfields are not encrypted and still save, and a caller without `:location`\nconsent never sees it: their coordinates are dropped before anything\nencrypts.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_put_details",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "destination_latitude": 47.7423,
                "destination_longitude": -121.9857,
                "destination_text": "the ridge above Duvall",
                "wearing": "red jacket, blue rucksack"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "details": {
                    "captured_at": null,
                    "destination": {
                      "latitude": 47.7423,
                      "longitude": -121.9857,
                      "text": "the ridge above Duvall"
                    },
                    "origin": null,
                    "wearing": "red jacket, blue rucksack"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Set what you are wearing and where you are going, on one check-in",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/sources": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "What raises events here, and what each one escalates to: a schedule, an\nescalation policy, or nothing, which is the loud fallback that pages\nevery responder. Read-only and **admin-only**: this is the account's\ningest configuration, and the page it mirrors is behind the same gate.\n\nEach source carries its integration keys as a prefix, a lane and two\nstamps, enough to tell two keys apart and to spot a monitor that has\ngone quiet. **Never the key itself:** the raw string exists once, at the\nmoment it is minted. `docs/ROUTING_API.md` §2.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "source_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "sources": [
                    {
                      "default_local_grace_seconds": 0,
                      "default_priority": "normal",
                      "default_sound": "mail",
                      "escalates_to": {
                        "id": "7b0e…",
                        "type": "escalation_policy"
                      },
                      "escalation_policy_id": "7b0e…",
                      "escalation_schedule_id": null,
                      "id": "3f8a…",
                      "integration_keys": [
                        {
                          "id": "c4d2…",
                          "key_prefix": "ark_async_9Xq2TbLm",
                          "lane": "async",
                          "last_used_at": "2026-09-17T18:02:44Z",
                          "revoked_at": null
                        }
                      ],
                      "max_priority": "emergency",
                      "name": "Prometheus (prod)",
                      "type": "monitor"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Every source in the account",
        "tags": [
          "routing"
        ]
      }
    },
    "/api/v2/chat/uploads/{file_id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Aborts an open upload, or removes a completed file not yet posted.\n`409 attached` once a message carries it. `docs/CHAT_API.md` §20.1.",
        "operationId": "v2_chat_file_delete",
        "parameters": [
          {
            "description": "The file id.",
            "in": "path",
            "name": "file_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Give up an upload",
        "tags": [
          "chat"
        ]
      },
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Your own upload, and while it is open the parts the bucket already\nholds, each with its `etag`. After a dropped link, send only the parts\nnot listed. `docs/CHAT_API.md` §20.1.",
        "operationId": "v2_chat_file_show",
        "parameters": [
          {
            "description": "The file id.",
            "in": "path",
            "name": "file_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "file": {
                    "id": "7d1c…",
                    "status": "uploading"
                  },
                  "upload": {
                    "part_count": 3,
                    "part_size": 8388608,
                    "parts_received": [
                      {
                        "byte_size": 8388608,
                        "etag": "a54f…",
                        "part_number": 1
                      }
                    ],
                    "status": "open"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "An upload's progress",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}/acknowledge": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The tap that stops a roster being paged, so it is on the hot path: an\naccess token up to five minutes past expiry is accepted here, because a\nresponder whose token lapsed while the phone slept still has to be able\nto answer. A `POST` naming the transition rather than a `PATCH` carrying\na status. See `docs/INCIDENT_API.md` §1.",
        "operationId": "incident_acknowledge",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "id": "4c1f…",
                    "status": "acknowledged"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Acknowledge: stop the paging",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/stop": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The share's author only. Your other devices are told with a silent\n`chat_location_stop` push. `docs/CHAT_API.md` §19.6.",
        "operationId": "v2_chat_message_stop_live",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "live": {
                      "stop_reason": "stopped",
                      "stopped": true
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Stop your live location share",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}/reject": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Records that the caller asked for changes and resolves the incident; the\ndecision is written back to the tracker issue as `changes-requested`.\nSame refusals as approve. See `docs/INCIDENT_API.md` §24.",
        "operationId": "incident_reject",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "note": "Split the schema change into its own PR."
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "decision": {
                      "decided_at": "2026-10-07T14:03:00Z",
                      "decided_by_user_id": "9a2b…",
                      "decision": "reject",
                      "note": "Split the schema change into its own PR."
                    },
                    "id": "4c1f…",
                    "status": "resolved"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Reject: answer a dev-approval incident no",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/crew": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The people on shift that the caller may see: anybody with an armed\ncheck-in, or an open incident raised from one, each with the newest\nposition of the current period and its `fix_at`, so a client draws it\nwith its age. Never a position from a check-in that has ended, never a\nperson whose check-in could not page the caller (the incident's own\nrule for an open incident), and `position` is `null` when there is\nnone to show. `docs/CHECKIN_API.md` §22.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "crew_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "crew": [
                    {
                      "checkin_id": "c41e…",
                      "deadline_at": "2026-10-05T22:00:00Z",
                      "incident_id": null,
                      "name": "Wren Worker",
                      "on_shift": "checkin",
                      "position": {
                        "accuracy_m": 12.0,
                        "captured_at": "2026-10-05T19:58:11.204Z",
                        "fix_at": "2026-10-05T19:58:10Z",
                        "latitude": 47.61,
                        "longitude": -122.33
                      },
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Who is on shift, and where",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/detections/monitor": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Immediate, and takes a stale token so it never waits on a refresh.\nDisarms the detector and refuses new reports. A window already open keeps\nrunning; cancel it to stop it (`docs/DETECTION_API.md` §4).",
        "operationId": "detection_disable",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "monitor": {
                    "armed": false,
                    "enabled": false
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Switch fall detection off",
        "tags": [
          "detections"
        ]
      },
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Whether the caller has switched detection on, whether the phone's\ndetector is armed, and the server's view of its heartbeat, including\n`alarmed` when the server has already told the roster the detector is\nnot being heard (`docs/DETECTION_API.md` §4).",
        "operationId": "detection_monitor",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "monitor": {
                    "alarmed": false,
                    "armed": true,
                    "enabled": true,
                    "sensing_state": "active"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The caller's fall-detection opt-in and liveness",
        "tags": [
          "detections"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "The opt-in: consent to a device inferring a fall, no movement or an\nunusual heart rate. Off by\ndefault; nothing is accepted from a person who has not done this.\nOptional `silence_window_seconds` (120 to 3600, default 600). Idempotent\n(`docs/DETECTION_API.md` §4).\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "detection_enable",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "silence_window_seconds": 600
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "monitor": {
                    "armed": false,
                    "enabled": true
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Switch fall detection on",
        "tags": [
          "detections"
        ]
      }
    },
    "/api/v1/detections/monitor/disarm": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Idempotent (`docs/DETECTION_API.md` §5).",
        "operationId": "detection_disarm",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "monitor": {
                    "armed": false
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Stop watching the phone's detector",
        "tags": [
          "detections"
        ]
      }
    },
    "/api/v1/auth/refresh": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Rotates the family: the refresh token sent is spent and a new pair comes\nback. Re-using a spent refresh token revokes the whole family, because a\nreplayed one means either a bug or a stolen credential and there is no\nway to tell them apart. See `docs/AUTHENTICATION.md` §6.",
        "operationId": "auth_refresh",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "refresh_token": "…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "access_token": "…",
                  "expires_in": 900,
                  "refresh_token": "…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          }
        },
        "security": [],
        "summary": "Exchange a refresh token for a new pair",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v2/chat/saved/{message_id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "`204`; not saved is the same answer. `docs/CHAT_API.md` §16.",
        "operationId": "v2_chat_account_unsave",
        "parameters": [
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Forgotten."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Forget a saved message",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/uploads": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`conversation_id` (one you are in), `filename`, `content_type`,\n`byte_size`, and `keep_location` to keep a photo's position on the\nfile. Answers the file and how to send it: a resumable multipart\nupload of `part_count` parts of `part_size` bytes, straight to the\nbucket. `413 file_too_large` or `413 storage_full` with the plan's\nlimit. `docs/CHAT_API.md` §20.1.",
        "operationId": "v2_chat_file_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "byte_size": 3480112,
                "content_type": "image/jpeg",
                "conversation_id": "0b6f…",
                "filename": "ridge.jpg"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "file": {
                    "id": "7d1c…",
                    "kind": "image",
                    "status": "uploading"
                  },
                  "upload": {
                    "part_count": 1,
                    "part_size": 8388608,
                    "parts_received": [],
                    "status": "open"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Start a file upload",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/uploads/{file_id}/complete": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`parts`: every part, in order, with the `etag` its `PUT` answered.\nThe file then processes (thumbnails, ThumbHash, poster, preview) and\nis scanned for malware. `409 invalid_parts` when a part is missing:\nread the progress and send it. `docs/CHAT_API.md` §20.1.",
        "operationId": "v2_chat_file_complete",
        "parameters": [
          {
            "description": "The file id.",
            "in": "path",
            "name": "file_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "parts": [
                  {
                    "etag": "a54f…",
                    "part_number": 1
                  }
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "file": {
                    "id": "7d1c…",
                    "scan_status": "pending",
                    "status": "processing"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Finish a file upload",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/cases/{id}/media/{media_id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "The row goes now and the object follows. `docs/CASES_API.md` §7.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "case_delete_media",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The media id.",
            "in": "path",
            "name": "media_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a photograph",
        "tags": [
          "cases"
        ]
      }
    },
    "/api/v1/map/tiles/{z}/{x}/{y}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "A Mapbox Vector Tile (`application/vnd.mapbox-vector-tile`) at\n`z/x/y` in the standard XYZ scheme, cut by PostGIS from the caller's\naccount only. One tile layer per `kind`. An empty tile is `200` with an\nempty body. `400 invalid_tile` for a coordinate outside the zoom's grid\nor a zoom past 22. `docs/MAP_LAYERS_API.md` §5.",
        "operationId": "map_tile",
        "parameters": [
          {
            "description": "The tile's zoom, 0 to 22.",
            "in": "path",
            "name": "z",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The tile's column at that zoom.",
            "in": "path",
            "name": "x",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The tile's row at that zoom, counted from the north.",
            "in": "path",
            "name": "y",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The tile's bytes."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "A vector tile of the account's map layers",
        "tags": [
          "maps"
        ]
      }
    },
    "/api/v1/devices": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "One `POST` both creates and updates. A client re-registers on every\nlaunch and cannot know which it is doing, so there is deliberately no\nseparate update route. `platform` is `ios`, `android`, `desktop` or\n`watchos` (an Apple Watch reached directly, §9e); all but `desktop`\ncarry a push token (an APNs device token or an FCM registration token,\nvalidated separately and never interchangeable), and `ios` and\n`watchos` carry a `push_environment`. `docs/DEVICE_API.md` §3.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "device_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "app_version": "1.4.0",
                "device_identifier": "1A2B-3C4D",
                "platform": "ios",
                "push_token": "…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "device": {
                    "device_identifier": "1A2B-3C4D",
                    "id": "c81d…",
                    "platform": "ios"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Registered, whether this created the device or updated it."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Register (or re-register) this device for push",
        "tags": [
          "devices"
        ]
      }
    },
    "/api/v1/users/me": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "The account holder deletes themselves; nobody deletes anybody else here.\nWhat survives is what an incident history has to keep, and\n`docs/AUTHENTICATION.md` says which.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "user_delete",
        "parameters": [],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete your own account",
        "tags": [
          "users"
        ]
      }
    },
    "/api/v1/checkins/{id}/cancel": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The \"never mind\" for a timer armed by mistake, and the off switch for a\ndaily. Idempotent, and gated on the code where `extend` deliberately is\nnot: cancelling takes the safety net down for good.",
        "operationId": "checkin_cancel",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "checkin": {
                    "id": "5f0f…",
                    "state": "idle"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Stand down without satisfying",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/checkins/commands": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "What the *subject's* phone is told, and the only shape it is ever told it\nin: a command id, a kind, and a deadline. No incident, no responder, no\nreason, because a duress activation may be being watched over the subject's\nshoulder. `docs/CHECKIN_API.md` §15.",
        "operationId": "checkin_commands",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "commands": [
                    {
                      "command_id": "77aa…",
                      "expires_at": "2026-09-06T17:12:11Z",
                      "kind": "locate"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Commands waiting for this device",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/voice_notes": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`content_type` (`audio/mp4`, `audio/aac`, `audio/mpeg`, `audio/ogg`,\n`audio/webm`, `audio/wav`), `byte_size` (at most 10 MB) and\n`duration_ms` (at most 5 minutes). Answers the note and where to `PUT`\nthe audio, with the headers to send. `docs/CHAT_API.md` §19.7.",
        "operationId": "v2_chat_voice_note_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "byte_size": 182000,
                "content_type": "audio/mp4",
                "duration_ms": 12400
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "upload": {
                    "expires_at": "…",
                    "headers": {
                      "content-type": "audio/mp4"
                    },
                    "method": "PUT",
                    "url": "https://…"
                  },
                  "voice_note": {
                    "id": "5c0e…",
                    "transcript_status": "pending"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Start a voice note upload",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/schedules/{id}/overrides": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "\"Bea is covering Ada from six until midnight.\" An override beats the\nlayers underneath it for its window and nothing else.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_create_override",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "ends_at": "2026-09-07T00:00:00Z",
                "starts_at": "2026-09-06T18:00:00Z",
                "user_id": "9a2b…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "override": {
                    "ends_at": "2026-09-07T00:00:00Z",
                    "id": "88cd…",
                    "starts_at": "2026-09-06T18:00:00Z",
                    "user_id": "9a2b…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Override the rota for a window",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/seen": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "`seen_by_count`: the members besides its author whose read marker is at\nor past it. `seen_by_user_ids` only in a DM or a group whose account\nshows read receipts, otherwise `null`. Members only (`403`).\n`docs/CHAT_API.md` §11.5.",
        "operationId": "v2_chat_seen",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message_id": "8e2a…",
                  "seen_by_count": 2,
                  "seen_by_user_ids": [
                    "5f61…",
                    "77c0…"
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Who has seen a message",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/layers/{id}/members": {
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "The whole list, not a delta: order is the rotation, and a partial write\nwould make \"who is next\" depend on the order the writes arrived in.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "layer_set_members",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "user_ids": [
                  "9a2b…",
                  "9a2c…"
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "layer": {
                    "id": "aa11…",
                    "member_ids": [
                      "9a2b…",
                      "9a2c…"
                    ]
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Set who is in a layer's rotation, and in what order",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v1/checkins/duress_code": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Leaves the ordinary check-in code alone.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_delete_duress_code",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "code_set": true,
                  "duress_code_set": false
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Clear your duress code",
        "tags": [
          "checkins"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "`code` proves who you are and is **not** written. That is the whole\nreason this route exists: `PUT /checkins/code` writes what it is given,\nso a client without this one had to send the check-in code in order to\nchange the second code, and a person who typed the wrong one of their\ntwo codes into that field replaced their check-in code with their duress\ncode, which then stopped signalling.\n\n`409 no_code_set` when there is no check-in code yet; a duress code has\nnothing to be entered against on its own.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_put_duress_code",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "code": "246813",
                "duress_code": "135791"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "code_set": true,
                  "duress_code_set": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Set or change your duress code, and only that",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/reactions": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`emoji`: one Unicode emoji, or `:name:` of one of the account's custom\nemoji. Members only. Already there is the same answer.\n`docs/CHAT_API.md` §14.",
        "operationId": "v2_chat_message_react",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "emoji": "👍"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "body": "Sector 4 is clear.",
                    "deleted": false,
                    "edited_at": null,
                    "id": "8e2a…",
                    "pinned": false,
                    "reactions": [
                      {
                        "count": 2,
                        "emoji": "👍",
                        "user_ids": [
                          "9a2b…",
                          "5f61…"
                        ]
                      }
                    ],
                    "seq": 41,
                    "thread": null
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "React to a message",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/positions": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The share's author only. Once the share is over (its time ran out, or\nit was stopped) the answer is `409 stopped` with a `stop` object\nnaming the message, `reason` (`expired` or `stopped`) and `at`: stop\nthe position session then, and only then. A point captured before\n`at` is still kept. The same pattern as `docs/INCIDENT_API.md` §21.\n`docs/CHAT_API.md` §19.6.",
        "operationId": "v2_chat_message_position",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "accuracy_m": 12,
                "fix_at": "2026-10-14T14:31:50Z",
                "latitude": 47.75,
                "longitude": -121.85
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "live": {
                      "last": {
                        "latitude": 47.75
                      },
                      "stopped": false,
                      "until": "…"
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Post a point of your live location share",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/devices/{device_identifier}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Removes a delivery target and nothing else. It can never mint anything,\nwhich is why it sits with the stale-grace routes rather than behind a\nfresh token. A client logs out by deregistering *then* revoking\n(`docs/DEVICE_API.md` §8), and a phone whose token lapsed must not get a\n`401` on the first step and a `204` on the second.",
        "operationId": "device_delete",
        "parameters": [
          {
            "description": "The client-chosen stable identifier for the device, from registration.",
            "in": "path",
            "name": "device_identifier",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deregistered."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Deregister this device",
        "tags": [
          "devices"
        ]
      }
    },
    "/api/v1/auth/companions": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The signed-in phone mints its Apple Watch a token family of its own and\nhands the pair over, so the Watch reaches the server with no phone in\nrange and nobody types credentials on a wrist. `kind` is `apple_watch`,\nand `refresh_token` is the phone's own live refresh token: minting needs\nboth halves of the phone's pair. The Watch's family is the phone's\nchild, revoked with it, and one per phone. `companion_id` is how the\nphone revokes it (`docs/AUTHENTICATION.md` §6).\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "auth_create_companion",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "kind": "apple_watch",
                "refresh_token": "…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "access_token": "…",
                  "companion_id": "0d6c…",
                  "expires_in": 900,
                  "refresh_token": "…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "The Watch's own access and refresh tokens."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Sign in the caller's Apple Watch",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v2/incidents/{id}/resolve": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Closes the incident when the system of record closes the ticket.",
        "operationId": "v2_incident_resolve",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "id": "4c1f…",
                    "status": "resolved"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "sync_key": []
          },
          {
            "account_token": []
          }
        ],
        "summary": "Resolve on behalf of the ticket",
        "tags": [
          "lane-b"
        ]
      }
    },
    "/api/v1/detections/{id}/cancel": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`200` with the cancelled window. `409 not_pending` with the window's\nreal state if it has already ended, including one that escalated: the\nroster is then already being told, and the app must say so rather than\nshow success (`docs/DETECTION_API.md` §6).",
        "operationId": "detection_cancel",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "detection": {
                    "id": "7f3a…",
                    "state": "cancelled"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "I'm OK: cancel a detection window",
        "tags": [
          "detections"
        ]
      }
    },
    "/api/v1/detections": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Opens a window (60 s) on the server and pushes an \"Are you OK?\" prompt\nto the caller. Pages nobody by itself: only a window nobody cancels\nescalates. `201` for a new window, `200` with the existing one for a\nretry with the same `client_event_id`, `403 detection_not_enabled`\nwithout the opt-in (`docs/DETECTION_API.md` §6). `reporter` is `phone`,\n`flic_duo` or `apple_watch`; an Apple Watch fall may carry Apple's own\n`watch_resolution`, which is shown to the roster and changes nothing\nabout the window. A `heart_rate` report may carry what the Watch\nmeasured (`heart_rate_direction`, `bpm`, `sustained_seconds`), shown to\nthe roster the same way.",
        "operationId": "detection_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "client_event_id": "b1c9…",
                "confidence": 0.82,
                "detected_at": "2026-09-30T14:02:11Z",
                "kind": "fall",
                "reporter": "apple_watch",
                "watch_resolution": "unresponsive"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "detection": {
                    "expires_at": "2026-09-30T14:03:12Z",
                    "id": "7f3a…",
                    "state": "pending"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "The window is open and the person is being asked."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Report a detected fall, no movement or unusual heart rate",
        "tags": [
          "detections"
        ]
      }
    },
    "/api/v1/auth/login": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Exchanges the emailed `token` (or the `code` and `email` pair) for an\naccess token and a refresh token. The link is single-use, and `GET`ting\nit in a browser does not spend it, so a mail scanner cannot burn it\nbefore the recipient clicks.",
        "operationId": "auth_login",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "token": "Xy7…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "access_token": "…",
                  "account": {
                    "id": "14a1…",
                    "name": "Cloud Bedrock",
                    "slug": "cloud-bedrock"
                  },
                  "expires_in": 900,
                  "refresh_token": "…",
                  "user": {
                    "email": "ada@example.com",
                    "id": "9a2b…",
                    "name": "Ada Walker",
                    "role": "responder"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          }
        },
        "security": [],
        "summary": "Spend a magic link or a login code",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/incidents/{id}/resolve": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Closes the incident. Resolving an already-resolved incident is not an error.",
        "operationId": "incident_resolve",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "id": "4c1f…",
                    "status": "resolved"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Resolve",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/broadcasts": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "An account admin. `conversation_id` (a channel or group: its people) or\n`user_group_id` (its members, each in a direct message from the\nAlertRoster bot), `body`, `ack_within_minutes` (1 to 10080) and\n`escalate`: `none`, `each_person` (an incident handed to each person who\nhas not acknowledged by then) or `policy` with `policy_id` (one incident\non that ladder naming them). A person's token only.\n`docs/CHAT_API.md` §25.",
        "operationId": "v2_chat_command_broadcast",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "ack_within_minutes": 30,
                "body": "Radio check at 0600, all units",
                "conversation_id": "c41d…",
                "escalate": "each_person"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "broadcast": {
                    "ack_by": "2026-10-24T06:00:00Z",
                    "body": "Radio check at 0600, all units",
                    "escalate": "each_person",
                    "id": "b7e2…",
                    "recipients": [
                      {
                        "acknowledged_at": null,
                        "incident_id": null,
                        "name": "Sam Reyes",
                        "user_id": "9a2b…"
                      }
                    ]
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Sent."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Send a must-acknowledge broadcast",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/incidents/{id}/reassign": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Moves the page to `user_id`. The incident stays open.",
        "operationId": "v2_incident_reassign",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "user_id": "9a2b…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "assigned_user_id": "9a2b…",
                    "id": "4c1f…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "sync_key": []
          },
          {
            "account_token": []
          }
        ],
        "summary": "Reassign on behalf of the ticket",
        "tags": [
          "lane-b"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Its author, or where the account allows it an account admin or the\nchannel's owner or an admin of it. Readers see a tombstone; the message\nand every version stay on the record. `docs/CHAT_API.md` §15.",
        "operationId": "v2_chat_message_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "body": "",
                    "deleted": true,
                    "id": "8e2a…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a message for its readers",
        "tags": [
          "chat"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "`body` and optional `mentions`. The author only, within the account's\nediting window (`409 edit_window_passed`), never a system message\n(`422 unsupported`), a deleted one (`409 deleted`) or an incident's\n(`422 unsupported`). Every earlier version is kept; new mentions\nnotify nobody. `docs/CHAT_API.md` §15.\n\nWith `blocks` (and `body`), it is not an edit but an update in place,\nthe way an app changes its own card: no editing window, never shown\nas edited, every version still kept. `docs/CHAT_API.md` §22.7.",
        "operationId": "v2_chat_message_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "body": "Sector 4 is clear, both teams out."
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "body": "Sector 4 is clear.",
                    "deleted": false,
                    "edited_at": null,
                    "id": "8e2a…",
                    "pinned": false,
                    "reactions": [
                      {
                        "count": 2,
                        "emoji": "👍",
                        "user_ids": [
                          "9a2b…",
                          "5f61…"
                        ]
                      }
                    ],
                    "seq": 41,
                    "thread": null
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Edit a message",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/records/incidents": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "What the records page lists, as JSON: every incident raised between\n`from` and `to`, newest first, with when it was raised, answered and\nclosed, who answered, what it closed *as* (and `expired` is the finding),\nwhat raised it, and how far up the ladder it got.\n\n`from` and `to` are **dates**, taken as whole days in UTC at both ends,\nso what a person looked at on `/records` and what a workflow fetched are\nthe same period. Both are required: \"the last seven days\" is a decision a\ncaller makes out loud rather than inherits from a server's default.\n\nIncidents are counted by when they were **raised**, so two adjacent\nmonths add up. Paged with `limit` and `offset`; `has_more` says whether\nanother page exists. A range longer than 366 days is refused rather than\ntruncated.\n\nAdmin-only, and at the API tier rather than the records tier: the page\nis Lone Worker and the systems layer is Duty of Care, which is\n`docs/RECORDS.md` §5. §8 is this route's contract.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "records_incidents",
        "parameters": [
          {
            "description": "First day of the range, inclusive, as YYYY-MM-DD. Required.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "Last day of the range, inclusive, as YYYY-MM-DD. Required.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "Rows per page, 1 to 500. Defaults to 100.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Rows to skip. Defaults to 0.",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "from": "2026-09-01T00:00:00Z",
                  "has_more": false,
                  "incidents": [
                    {
                      "acknowledged_at": "2026-09-17T18:05:02Z",
                      "acknowledged_by_user_id": "9a2b…",
                      "checkin_id": "8b7e…",
                      "escalation_repeat_count": 0,
                      "escalation_rule_position": 1,
                      "id": "4c1f…",
                      "priority": "emergency",
                      "resolved_at": "2026-09-17T19:40:00Z",
                      "source_id": "3f8a…",
                      "status": "resolved",
                      "title": "Overdue: Evening walk",
                      "triggered_at": "2026-09-17T18:04:11Z",
                      "urgency": "high"
                    }
                  ],
                  "limit": 100,
                  "offset": 0,
                  "to": "2026-09-30T23:59:59Z"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The incidents raised in a date range",
        "tags": [
          "records"
        ]
      }
    },
    "/api/v1/checkins/{id}/briefing": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The pre-departure briefing. Every other thing this product does begins\nafter something has gone wrong; this is the one that happens before:\nwhat is happening at the destination on this check-in, in the sources'\nown words, each with whose word it is and how old.\n\nIt is not advice. Nothing here says a trip is safe, and nothing here is\never a reason a check-in was not armed or an escalation did not run.\n\n`404 no_destination` when this check-in has no **located** destination:\nno `:details` consent, nothing typed, or a place named in words without\n`:location` consent for its coordinates. A source that is down is\nreported in `sources` with its own `state` rather than failing the\nrequest, so check `complete` before showing a reassuring blank.\n`docs/CHECKIN_API.md` §21.",
        "operationId": "checkin_briefing",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "briefing": {
                    "assembled_at": "2026-09-15T17:40:00Z",
                    "complete": true,
                    "destination": {
                      "latitude": 47.7423,
                      "longitude": -121.9857,
                      "text": "the ridge above Duvall"
                    },
                    "items": [],
                    "lines": [
                      "Severe Thunderstorm Warning · Missoula, MT · National Weather Service · issued 12 min ago"
                    ],
                    "radius_km": 50,
                    "sources": [],
                    "stated_at": "2026-09-15T17:02:11Z"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "What the sources say about where you said you were going",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/schedules/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Sources pointing at it fall back to the loud default: a miss pages every\nresponder in the account.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a schedule",
        "tags": [
          "schedules"
        ]
      },
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The schedule with its layers.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_show",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "schedule": {
                    "id": "7714…",
                    "layers": [],
                    "name": "Primary on-call"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Read one schedule",
        "tags": [
          "schedules"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Changing the zone re-computes who is on call from the next boundary.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "name": "Primary on-call (US)"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "schedule": {
                    "id": "7714…",
                    "name": "Primary on-call (US)"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Rename a schedule or move its time zone",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/enqueue": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The async lane: the caller is a monitor with nowhere to put an answer, so\nwhat comes back is a **receipt for a durable write** and never the state\nof an incident. Everything that decides what the event means (dedup,\nwhether it opens an incident, who it pages) happens in a job the same\ntransaction enqueued.\n\n`event_action` is required and **never defaulted**: a caller that meant\nto resolve and mistyped the field would otherwise raise a fresh incident,\nwhich is the loudest possible way to be wrong about a payload. It is\n`trigger`, `acknowledge` or `resolve`, and `payload` is required on a\n`trigger`. `docs/LANE_A_API.md` §5.\n\n`priority` (`normal`, `high` or `emergency`) says how loud the page is,\nin place of what `payload.severity` would ask for: `normal` notifies\nonce without breaking Focus, `high` is time-sensitive once, `emergency`\nrepeats until acknowledged. `sound` names the tone, one of\n`chime`, `critical`, `high`, `mail`, `normal`, `ping`; an unknown\nname plays the source's tone instead. Both are optional, both fall back\nto the source's Default priority and Sound, both are decided by the\nevent that opens the incident, and the source's Loudest priority still\ncaps the priority. `docs/LANE_A_API.md` §4d.\n\nAn email bridge in Google Apps Script, paging quietly with a mail tone:\n\n```js\nUrlFetchApp.fetch('https://alertroster.com/api/v2/enqueue', {\n  method: 'post',\n  contentType: 'application/json',\n  headers: { Authorization: 'Bearer ' + KEY },\n  payload: JSON.stringify({\n    event_action: 'trigger',\n    dedup_key: 'email:' + thread.getId(),\n    priority: 'normal',\n    sound: 'mail',\n    payload: { summary: subject, severity: 'info' }\n  })\n});\n```",
        "operationId": "v2_enqueue_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "dedup_key": "db-primary-down",
                "event_action": "trigger",
                "payload": {
                  "custom_details": {
                    "checks_failed": 3,
                    "region": "iad"
                  },
                  "severity": "critical",
                  "source": "db-primary.iad",
                  "summary": "Primary database is not responding"
                },
                "priority": "emergency",
                "sound": "critical"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "alert_id": "dd44…",
                  "dedup_key": "db-primary-down",
                  "status": "accepted"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Accepted and durably written. The receipt is not an incident."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "async_key": []
          }
        ],
        "summary": "Fire an event at the firehose",
        "tags": [
          "lane-a"
        ]
      }
    },
    "/api/v1/map/token": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "An ArcGIS access token for basemaps and location services, so no\ninstalled client holds a long-lived Esri credential. Minted from the\naccount's own ArcGIS when it has connected one (`source: \"account\"`),\nfrom AlertRoster's otherwise (`source: \"alertroster\"`), and from\nAlertRoster's when the account's fails, with `account_error` saying\nwhy. Cached server-side; refresh on `expires_at`. `503` with\n`retry-after` when no source can mint: keep drawing with the token\nheld and say so on the map. The same `503` with reason\n`allowance_exceeded` and a `retry-after` of 900 when the account used\nits month's map allowance on AlertRoster's credential and no incident\nis open on it; an open incident is always served. `license_string` is the Native Maps SDK\nlicence string a Swift, Kotlin or Qt client passes to `setLicense`,\nfor the SDK major named by `sdk_major`, or null when none is\nconfigured for it; the `503` carries it too.\n`docs/MAP_LAYERS_API.md` §7.",
        "operationId": "map_token",
        "parameters": [
          {
            "description": "The Native Maps SDK major the client runs (`200`, `300`), which\npicks the licence string: one licenses a single major. Defaults to\n`200`; a major with no string is a null `license_string`, never a\nrefused token.\n",
            "in": "query",
            "name": "sdk_major",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "`true` to be answered with a `basemap_session` beside the token: a\nsession token for the basemap's key, billed once for up to twelve\nhours of tiles. Every session started is billed, so ask only when\nthe map needs one, not on every refresh (alertroster #560).\n",
            "in": "query",
            "name": "basemap_session",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "account_error": null,
                  "basemap_session": {
                    "expires_at": "2026-10-06T02:00:00Z",
                    "token": "AAPTxy8B…"
                  },
                  "basemap_style_url": null,
                  "expires_at": "2026-10-04T14:00:00Z",
                  "license_string": "runtimelite,1000,rud…",
                  "source": "alertroster",
                  "token": "3NKHt6i2urmWtqOuugvr9…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "A short-lived ArcGIS token for the basemap",
        "tags": [
          "maps"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/revisions": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The original and each edit, oldest first. A deleted message's history\nis an account admin's to read (`403` otherwise). `docs/CHAT_API.md`\n§15.",
        "operationId": "v2_chat_message_revisions",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message_id": "8e2a…",
                  "revisions": [
                    {
                      "at": "…",
                      "body": "Sector 4 clear",
                      "by_user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Every version of a message",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/cases": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Newest first. `status` filters to one of `open`, `sighted`, `recovered`,\n`closed`. Coordinates are full precision: this is the holding tenant\nreading its own cases. `docs/CASES_API.md` §3.",
        "operationId": "case_index",
        "parameters": [
          {
            "description": "Only cases in this status.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "enum": [
                "open",
                "sighted",
                "recovered",
                "closed"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "cases": [
                    {
                      "behaviour_profile": "flight_risk_dog",
                      "id": "9b1e…",
                      "last_seen": {
                        "latitude": 32.7555,
                        "longitude": -97.3308
                      },
                      "last_seen_at": "2026-10-05T18:20:00Z",
                      "name": "Biscuit",
                      "public_url": "https://alertroster.com/c/…",
                      "species": "dog",
                      "status": "open"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The account's missing-animal cases",
        "tags": [
          "cases"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`species`, `last_seen_at`, `latitude` and `longitude` are required. The\nresponse carries `manage_token` once and only once: it is stored as a\ndigest, so hand it to the owner now, or rotate it later.\n`public_url` is stable for the life of the case, so a printed flyer\nnever goes dead. `docs/CASES_API.md` §4.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "case_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "behaviour_profile": "flight_risk_dog",
                "contact_name": "Sam Ortiz",
                "contact_phone": "+18175550142",
                "last_seen_at": "2026-10-05T18:20:00Z",
                "latitude": 32.7555,
                "longitude": -97.3308,
                "name": "Biscuit",
                "species": "dog"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "case": {
                    "id": "9b1e…",
                    "status": "open"
                  },
                  "manage_token": "…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Opened."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Open a case",
        "tags": [
          "cases"
        ]
      }
    },
    "/api/v1/incidents/{id}/silence": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Stops the sound without acknowledging: the incident is still open and\nstill somebody's problem. The two are separate on purpose: silencing a\nphone in a meeting must not tell a roster that the page has been answered.",
        "operationId": "incident_silence",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "id": "4c1f…",
                    "status": "triggered"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Silence this incident's noise on this device",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/commands": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`text` is the whole command, `/page Night shift generator down`;\n`mentions` the composer's spans over it and `thread_root_id` the\nthread it was typed in, both optional. `/page`, `/ack` and `/resolve`\nraise, acknowledge and resolve exactly as the incident API does, as\nyou. The answer has the `ephemeral` shown only to you (also pushed to\nyour sockets with the same `id`), a `message` posted, or a modal\n`view` opened. A command whose effect failed is `422 command_failed`\nwith the reason, never a `200`. A person's token only.\n`docs/CHAT_API.md` §22.6.",
        "operationId": "v2_chat_command_run",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "mentions": [],
                "text": "/page Night shift generator 2 is down"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "closed": false,
                  "ephemeral": null,
                  "message": {
                    "body": "Dana paged Night shift (Sam): generator 2 is down",
                    "id": "8e2a…"
                  },
                  "view": null
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Run a slash command",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/users": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Who can be paged, and who a schedule or a reassignment can name.",
        "operationId": "user_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "users": [
                    {
                      "email": "ada@example.com",
                      "id": "9a2b…",
                      "name": "Ada Walker"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "List the responders in the account",
        "tags": [
          "users"
        ]
      }
    },
    "/api/v2/chat/voice_notes/{voice_note_id}/complete": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Checks the uploaded audio and transcribes it, up to 15 seconds.\n`transcript_status` is then `done`, `failed` (retried in the\nbackground) or `unavailable`. Post the note afterwards as a\n`voice_note` message. `409 object_missing` when the upload has not\nlanded. `docs/CHAT_API.md` §19.7.",
        "operationId": "v2_chat_voice_note_complete",
        "parameters": [
          {
            "description": "The voice note id.",
            "in": "path",
            "name": "voice_note_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "voice_note": {
                    "duration_ms": 12400,
                    "id": "5c0e…",
                    "transcript": "Team two is at the trailhead.",
                    "transcript_status": "done"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Finish a voice note upload",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The same object the list renders; `docs/INCIDENT_API.md` §3 defines it once.",
        "operationId": "incident_show",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "emergency": true,
                    "id": "4c1f…",
                    "status": "triggered"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Read one incident",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/checkins/{id}/positions": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Continuous capture for the length of an armed check-in, batched, and\n(once a miss has raised an incident) for as long as that incident stays\nopen. Refused unless the caller holds location consent and there is\nsomewhere for the batch to land: an open incident a miss of this check-in\nraised, or failing that an armed window. Each point's `fix_at` must fall\ninside the period it lands in. A malformed element is dropped and counted\nrather than failing the batch; a replayed batch stores nothing twice.\n\nWhen the incident a miss raised has closed and nothing else is open or\narmed, the answer is `409 not_armed` carrying `stop` (the incident, its\nterminal status and `resolved_at`): the device ends its position\nsession for this check-in. Points captured before `resolved_at` are\nstill stored; later ones are dropped. It never stops region monitoring\nor presence. `docs/CHECKIN_API.md` §13.",
        "operationId": "checkin_record_positions",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "positions": [
                  {
                    "accuracy_m": 12.5,
                    "fix_at": "2026-09-08T18:14:02Z",
                    "latitude": 47.6062,
                    "longitude": -122.3321
                  }
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "dropped": 0,
                  "stored": 1,
                  "track": {
                    "distance_m": 50,
                    "final_interval_seconds": 60,
                    "final_lead_seconds": 900,
                    "interval_seconds": 180
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Stream positions during an armed window or an open incident",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/pins": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Most recently pinned first, as the message object of §5.1.\n`docs/CHAT_API.md` §16.",
        "operationId": "v2_chat_message_pins",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "c41d…",
                  "messages": [
                    {
                      "id": "8e2a…",
                      "pinned": true
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "A conversation's pinned messages",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/images": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Its own capability rather than part of the description, because the\nprivacy policy offers \"photographs and images\" separately.",
        "operationId": "checkin_images_consent_status",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "images_opt_in": false
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Whether you have opted in to photographs",
        "tags": [
          "checkins"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Withdrawing deletes the stored images.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_put_images_consent",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "opt_in": true
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "images_opt_in": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Grant or withdraw photograph consent",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/schedules/{schedule_id}/layers": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Layers stack: the last one that covers an instant wins.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "layer_index",
        "parameters": [
          {
            "description": "The schedule's identifier.",
            "in": "path",
            "name": "schedule_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "layers": [
                    {
                      "id": "aa11…",
                      "name": "Weekdays",
                      "position": 1
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "List a schedule's layers",
        "tags": [
          "schedules"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "A rotation over a set of members, with a restriction on when it applies.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "layer_create",
        "parameters": [
          {
            "description": "The schedule's identifier.",
            "in": "path",
            "name": "schedule_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "handoff_at": "09:00:00",
                "name": "Weekdays",
                "rotation": "weekly"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "layer": {
                    "id": "aa11…",
                    "name": "Weekdays"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Add a layer",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/chat/views/{view_id}/close": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Closes it without submitting; the app is not told. Not open is the same\nanswer. `docs/CHAT_API.md` §22.8.",
        "operationId": "v2_chat_command_dismiss",
        "parameters": [
          {
            "description": "The view id.",
            "in": "path",
            "name": "view_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Closed."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Dismiss a modal",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/buttons/{id}/disarm": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "End of shift, or the button going in a drawer. Presses still page when\ndisarmed; only the silence watch stops. Idempotent\n(`docs/BUTTON_API.md` §5).",
        "operationId": "button_disarm",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "button": {
                    "armed": false,
                    "id": "0b7e…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Stop watching the button",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/v1/overrides/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "The rota underneath it applies again from the moment this returns.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "override_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Remove an override",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/chat/files/{file_id}/url": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "A short-lived signed URL for a file on a message you can read, or one\nof your own not yet posted. `variant` is `original` (the default; a\nphoto's copy without its metadata) or `thumb_64`, `thumb_320`,\n`thumb_1024`. `404` for a file you cannot read, `409 scan_pending`\nuntil the malware scan passes, `409 processing` for a thumbnail not\nmade yet, `410 infected`. Mint one per view. `docs/CHAT_API.md` §20.4.",
        "operationId": "v2_chat_file_url",
        "parameters": [
          {
            "description": "The file id.",
            "in": "path",
            "name": "file_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "expires_at": "2026-10-20T14:36:50Z",
                  "file_id": "7d1c…",
                  "url": "https://…",
                  "variant": "thumb_320"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "A file's download URL",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/user_groups/{group_id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "An account admin. Messages that mentioned it keep who it reached.\n`docs/CHAT_API.md` §18.",
        "operationId": "v2_chat_account_delete_group",
        "parameters": [
          {
            "description": "The group id.",
            "in": "path",
            "name": "group_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a user group",
        "tags": [
          "chat"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "An account admin. `handle`, `name`, and `user_ids` to replace its\nmembers. `docs/CHAT_API.md` §18.",
        "operationId": "v2_chat_account_update_group",
        "parameters": [
          {
            "description": "The group id.",
            "in": "path",
            "name": "group_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "user_ids": [
                  "9a2b…",
                  "5f61…"
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "user_groups": [
                    {
                      "handle": "nurses"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Change a user group",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/fallback": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "What an app needs to offer \"check in by text\" or \"check in by phone\" when\nthe data connection is gone. The numbers are served rather than built into\nthe client so changing one does not need an App Store release on a safety\npath, and they are two fields rather than one because they are a single\nTwilio number by provisioning rather than by contract.\n\n`null` (not omitted) means the channel is unconfigured here.\n`phone_registered: false` means an inbound text or call from this\nresponder would be answered with silence, so a client shows no fallback\nrather than one that quietly does nothing. `docs/CHECKIN_API.md` §20.\n\n`auto_sos` is whether, and how, the app declares an SOS on the\nresponder's paired inReach when they miss a check-in with no signal:\n`null` unless the organization has enabled it and this responder has a\nregistered unit. Cache it: the moment it matters is the moment the app is\noffline. A client declares only when `declare` is literally `true`; on\nany other value it rehearses. `docs/SATELLITE_API.md` §14.\n\n`manual_sos` is whether the panic control may declare an SOS on the\nresponder's paired inReach when they press it, and the countdown in\nwhich an accidental press is cancelled. Its own switch, beside\n`auto_sos` rather than behind it, so a panic control works where\nautomatic SOS is off; the same registered-unit and `declare` rules.\n`null` unless every gate holds. `docs/SATELLITE_API.md` §14.7.\n\n`satellite` is how the account gets satellite paging (`model`: `byo`,\n`hosted` or `bluetooth_only`) and whether the server can page the\nresponder's inReach at all (`server_pages`); `null` when the account has\nnever configured satellite. `docs/SATELLITE_API.md` §22.",
        "operationId": "checkin_fallback",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "auto_sos": {
                    "countdown_seconds": 60,
                    "declare": true,
                    "imeis": [
                      "300434030000001"
                    ],
                    "message_first_seconds": 600,
                    "mode": "both",
                    "organization": "Acme Utilities",
                    "reply_to": "acme@sat.alertroster.com"
                  },
                  "commands": {
                    "cancel": "OFF",
                    "extend": "EXTEND",
                    "satisfy": "OK"
                  },
                  "manual_sos": {
                    "countdown_seconds": 10,
                    "declare": true,
                    "imeis": [
                      "300434030000001"
                    ],
                    "organization": "Acme Utilities"
                  },
                  "phone_registered": true,
                  "satellite": {
                    "model": "byo",
                    "server_pages": true
                  },
                  "sms_number": "+15555550123",
                  "voice_number": "+15555550123"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Where to text or call, and whether this phone will be heard",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/incidents/{id}/messages": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Messages oldest first, after `after_seq` (exclusive), at most `limit`\n(default 200, max 500), with `has_more`. Each carries its author, the\n160-character `rendering` a unit receives, where the sender was\n(`location`, always present: attached, correlated, a place, or `none`\nwith the reason) and the current delivery state per recipient and\nchannel. A client that reconnects asks for everything after the last\n`seq` it holds and misses nothing. `docs/INCIDENT_API.md` §23.",
        "operationId": "incident_message_index",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Return messages with a `seq` greater than this. Default 0.",
            "in": "query",
            "name": "after_seq",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "At most this many messages, 1 to 500. Default 200.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "has_more": false,
                  "incident_id": "4c1f…",
                  "messages": [
                    {
                      "arrived_via": "api",
                      "author": {
                        "device_id": null,
                        "user_id": "9a2b…"
                      },
                      "body": "Heading up the north ridge now.",
                      "created_at": "2026-10-06T14:32:30Z",
                      "deliveries": [
                        {
                          "at": "…",
                          "channel": "push",
                          "recipient_user_id": "5f61…",
                          "state": "sent"
                        }
                      ],
                      "id": "8e2a…",
                      "kind": "text",
                      "location": {
                        "accuracy_m": 12.0,
                        "fix_at": "2026-10-06T14:31:50Z",
                        "gap_s": 40,
                        "latitude": 47.75,
                        "longitude": -121.85,
                        "no_location_reason": null,
                        "place_id": null,
                        "source": "correlated"
                      },
                      "rendering": [
                        "S.Searcher: Heading up the north ridge now."
                      ],
                      "seq": 12
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Read the incident's thread",
        "tags": [
          "incidents"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`client_message_id` (1 to 255 characters, required) makes it\nidempotent: a resend returns the stored message with `200`, a new one\nis `201`. `kind` is `text` (default), `location` (with a `location`\nobject) or `location_request`; a location answering a request names it\nin `answers_message_id`. Attach the sender's fix as `location`, or say\nwhy there is none with `no_location_reason` (`not_shared` from a desk\nskips correlation). Every participant is told: over the socket when\nthey hold one, by an ordinary push otherwise. `docs/INCIDENT_API.md` §23.",
        "operationId": "incident_message_create",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "body": "Heading up the north ridge now.",
                "client_message_id": "a1b2c3d4-5e6f-…",
                "kind": "text",
                "location": {
                  "accuracy_m": 12.0,
                  "fix_at": "2026-10-06T14:31:50Z",
                  "latitude": 47.75,
                  "longitude": -121.85
                }
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "kind": "text",
                    "seq": 12
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Post a message to the incident's thread",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/channels": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Every public channel, whether or not you are in it, for finding one to\njoin. `include_archived=true` adds archived ones. `docs/CHAT_API.md` §4.3.",
        "operationId": "v2_chat_channels",
        "parameters": [
          {
            "description": "`true` to include archived channels. Default `false`.",
            "in": "query",
            "name": "include_archived",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversations": [
                    {
                      "archived": false,
                      "archived_at": null,
                      "created_at": "2026-10-12T14:00:00Z",
                      "created_by_user_id": "9a2b…",
                      "default_kind": null,
                      "id": "c41d…",
                      "incident_id": null,
                      "kind": "channel",
                      "member_count": 4,
                      "member_user_ids": null,
                      "membership": {
                        "joined_at": "2026-10-12T14:00:00Z",
                        "muted": false,
                        "notification_level": "mentions",
                        "role": "owner"
                      },
                      "name": "ops",
                      "purpose": "",
                      "site_feature_id": null,
                      "topic": "North ridge search",
                      "visibility": "public"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Browse the account's public channels",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/buttons/{id}/heartbeat": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Sent about once a minute while armed, and on every link change.\n`link_state` is `connected` or `disconnected`; `battery_percent` is\noptional. The server stamps its own clock on receipt. The response is\nthe server's view, including `alarmed` (`docs/BUTTON_API.md` §6).",
        "operationId": "button_heartbeat",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "battery_percent": 88,
                "link_state": "connected"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "button": {
                    "alarmed": false,
                    "armed": true,
                    "id": "0b7e…",
                    "last_heartbeat_at": "2026-09-30T08:05:00Z",
                    "link_state": "connected"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Report the button's link",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/v1/buttons/{id}/presses": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Raises an emergency incident on the button's source, armed or not.\n`client_event_id` makes a retried press page once; nothing in the body\ncan make the server refuse a press. `gesture: \"hold\"` is a silent\nduress: the roster is paged and the presser's own devices never are.\n`202` for a new press and for a repeat (`docs/BUTTON_API.md` §7).\n\nAn optional `position` is put on the incident when the wearer holds\nlocation consent; a missing, malformed or unconsented one is dropped\nand never refuses the press. `track` in the answer says whether to\nstart the press's position stream (§7.3).",
        "operationId": "button_press",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "client_event_id": "6d1f0c52-…",
                "gesture": "press",
                "position": {
                  "accuracy_m": 12.5,
                  "fix_at": "2026-09-30T08:06:10Z",
                  "latitude": 47.6062,
                  "longitude": -122.3321
                },
                "pressed_at": "2026-09-30T08:06:12Z"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "event_id": "a41c…",
                  "status": "accepted",
                  "track": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Stored and on its way to a page, or already stored."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Report a panic press",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/v1/records/export": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The rows themselves, for a customer's own retention or BI, byte for byte\nthe file the download button on `/records` produces, from the same\nencoder and the same window.\n\n`format` is required and is one of `json` (both tables in one document),\n`timeline_csv` (the incident timeline) or `checkin_csv` (the check-in\nevents). Two files rather than one because the two tables have different\ncolumns and a merged CSV would be mostly empty cells;\n`docs/RECORDS.md` §6 names every column.\n\nThe response carries `content-disposition` with a filename that includes\nthe range, and answers `text/csv` for the two CSV formats. Ask for one\nwith `Accept: text/csv` if you like, which this route accepts and the\nJSON-only routes beside it do not.\n\nSame range rules and same gates as the two reads above.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "records_export",
        "parameters": [
          {
            "description": "One of json, timeline_csv, checkin_csv. Required.",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "enum": [
                "json",
                "timeline_csv",
                "checkin_csv"
              ],
              "type": "string"
            }
          },
          {
            "description": "First day of the range, inclusive, as YYYY-MM-DD. Required.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "Last day of the range, inclusive, as YYYY-MM-DD. Required.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file, with a content-disposition filename carrying the range."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The raw append-only rows, as a file",
        "tags": [
          "records"
        ]
      }
    },
    "/api/v2/chat/conversations": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Channels, DMs and groups you are in now, with your membership on each.\nNever incident threads, which are reached from the incident. `kind`\nnarrows to one kind; `include_archived=true` adds archived channels.\n`docs/CHAT_API.md` §4.1.",
        "operationId": "v2_chat_index",
        "parameters": [
          {
            "description": "`channel`, `dm`, `group` or `incident`.",
            "in": "query",
            "name": "kind",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "`true` to include archived channels. Default `false`.",
            "in": "query",
            "name": "include_archived",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversations": [
                    {
                      "archived": false,
                      "archived_at": null,
                      "created_at": "2026-10-12T14:00:00Z",
                      "created_by_user_id": "9a2b…",
                      "default_kind": null,
                      "id": "c41d…",
                      "incident_id": null,
                      "kind": "channel",
                      "member_count": 4,
                      "member_user_ids": null,
                      "membership": {
                        "joined_at": "2026-10-12T14:00:00Z",
                        "muted": false,
                        "notification_level": "mentions",
                        "role": "owner"
                      },
                      "name": "ops",
                      "purpose": "",
                      "site_feature_id": null,
                      "topic": "North ridge search",
                      "visibility": "public"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The conversations you are in",
        "tags": [
          "chat"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`kind` `channel` with `name` (1 to 80 lowercase letters, digits,\nhyphens or underscores; a leading `#` and capitals are folded),\n`visibility` (`public` or `private`), optional `topic`, `purpose` and\n`user_ids` to add; `dm` with the one other person in `user_ids`; or\n`group` with `user_ids`, three to nine people with you. `201` when\ncreated; a DM that already exists answers `200` with it.\n`docs/CHAT_API.md` §4.2.",
        "operationId": "v2_chat_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "kind": "channel",
                "name": "ops",
                "topic": "North ridge search",
                "visibility": "public"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "archived": false,
                    "archived_at": null,
                    "created_at": "2026-10-12T14:00:00Z",
                    "created_by_user_id": "9a2b…",
                    "default_kind": null,
                    "id": "c41d…",
                    "incident_id": null,
                    "kind": "channel",
                    "member_count": 4,
                    "member_user_ids": null,
                    "membership": {
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner"
                    },
                    "name": "ops",
                    "purpose": "",
                    "site_feature_id": null,
                    "topic": "North ridge search",
                    "visibility": "public"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Create a channel, open a DM or start a group",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/buttons": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Every button the caller has registered, with the server's view of its\nlink: whether it is armed, the last link report and when it arrived, and\nwhether a silence alarm has been raised. The app shows this rather than\nits own belief, because the server's is the one that pages\n(`docs/BUTTON_API.md` §3).",
        "operationId": "button_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "buttons": [
                    {
                      "alarmed": false,
                      "armed": true,
                      "id": "0b7e…",
                      "label": "Left strap",
                      "link_state": "connected",
                      "model": "flic2",
                      "silence_window_seconds": 300
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The caller's panic buttons",
        "tags": [
          "buttons"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Called once the phone has paired the button. Mints the button's own\nsource, which pages the people a missed check-in would page: the\n`escalation_schedule_id` given, or every responder in the account. The\nbutton starts disarmed and disconnected (`docs/BUTTON_API.md` §4).\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "button_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "label": "Left strap",
                "model": "flic2",
                "serial": "BD12-A3456"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "button": {
                    "armed": false,
                    "id": "0b7e…",
                    "link_state": "disconnected"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Registered."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Register a paired button",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/referral-leads": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "A person who clicked an instructor's AlertRoster offer on a pewpros surface\nand agreed to be contacted. Signed like AlertRoster's own callbacks\n(`X-AlertRoster-Signature: t=<unix>,v1=<hmac-sha256 hex of \"<t>.<raw body>\">`,\nfive minutes either way), with `X-AlertRoster-Key: platform` (the shared\nplatform secret) or `partner` (that partner's own secret).\n\n**Idempotent on the partner and the email**: a repeat answers `200` with\nthe lead it already holds and re-sends nothing. A code naming no active\npartner answers `200 {\"status\":\"ignored\"}` rather than a refusal, so the\nsender's retries are never stranded. Nothing here pays anything; rewards\nstay purchase-only. `docs/REFERRAL_LEADS.md`.",
        "operationId": "referral_lead_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "consent_at": "2026-09-19T20:11:03Z",
                "consent_text": "By clicking, you agree that your name, email, and phone number will be shared with AlertRoster…",
                "email": "member@example.com",
                "first_name": "Casey",
                "last_name": "Rivera",
                "phone": "+17025550142",
                "referral_code": "SMITH-CCW",
                "resource_title": "Try AlertRoster",
                "sender": {
                  "host": "detroitarms.com",
                  "site_id": "9a12…",
                  "submission_id": 123
                },
                "sms_opt_in": false,
                "source": "community_post"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "lead_id": "5d0e…",
                  "status": "recorded"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "lead_signature": []
          }
        ],
        "summary": "Record a referral lead",
        "tags": [
          "referral-leads"
        ]
      }
    },
    "/api/v1/map/layers": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Every layer the account has drawn, by kind then name, with the kinds a\nlayer can be. A layer is a named set of one `kind` (`site`, `geofence`,\n`building`, `floor`, `hazard_area`) and is what a map styles by.\n`docs/MAP_LAYERS_API.md` §3.",
        "operationId": "map_layers",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "kinds": [
                    "site",
                    "geofence",
                    "building",
                    "floor",
                    "hazard_area"
                  ],
                  "layers": [
                    {
                      "description": null,
                      "id": "5d0a…",
                      "kind": "geofence",
                      "name": "Yard"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The account's map layers",
        "tags": [
          "maps"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`kind` is set here and never changes. Admin only.\n`docs/MAP_LAYERS_API.md` §3.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "map_create_layer",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "kind": "geofence",
                "name": "Yard"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "layer": {
                    "description": null,
                    "id": "5d0a…",
                    "kind": "geofence",
                    "name": "Yard"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Create a map layer",
        "tags": [
          "maps"
        ]
      }
    },
    "/api/v1/checkins/profile/photo": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The first of three calls: the server chooses the key and signs a `PUT`,\nthe device uploads straight to the bucket, and a third call makes the\nserver look at what actually arrived. Nothing renders until then, because\na presigned `PUT` is a licence to write arbitrary bytes.\n`docs/CHECKIN_API.md` §17.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_request_photo",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "byte_size": 184320,
                "content_type": "image/jpeg",
                "kind": "person",
                "taken_at": "2026-09-01"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "photo": {
                    "age_days": 5,
                    "id": "cc33…",
                    "kind": "person",
                    "taken_at": "2026-09-01",
                    "url": null
                  },
                  "upload_expires_at": "2026-09-06T17:12:11Z",
                  "upload_url": "https://…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Signed. Upload to `upload_url`, then confirm."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Mint a presigned upload for a photograph",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/records/coverage": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Was somebody on call, did people check in, and how fast did anyone\nanswer, across the range, as JSON. The same object the page renders.\n\nEvery figure is a count of rows written at the time, never a simulation\nof the current rota over past dates: `unrostered_pages` counts the\nmoments this system needed a responder and resolved to nobody, which is a\nnarrower claim than \"the rota had no gaps\" and is the true one.\n\nThree nulls mean something specific and a caller that flattens them will\nreport the opposite of the truth: `compliance_rate: null` is \"no\ndeadlines fell in this range\", not zero percent. `docs/RECORDS.md` §8\ndocuments each.\n\nSame range rules, same gates, as the incident list.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "records_coverage",
        "parameters": [
          {
            "description": "First day of the range, inclusive, as YYYY-MM-DD. Required.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "Last day of the range, inclusive, as YYYY-MM-DD. Required.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "coverage": {
                    "ack_seconds_median": 47,
                    "ack_seconds_worst": 512,
                    "acknowledged": 13,
                    "checkins_cancelled": 3,
                    "checkins_extended": 6,
                    "checkins_missed": 2,
                    "checkins_satisfied": 88,
                    "compliance_percent": 97.8,
                    "compliance_rate": 0.978,
                    "expired": 1,
                    "from": "2026-09-01T00:00:00Z",
                    "generated_at": "2026-10-01T06:00:00Z",
                    "incidents": 14,
                    "rostered_pages": 19,
                    "to": "2026-09-30T23:59:59Z",
                    "unacknowledged": 1,
                    "unrostered": [
                      {
                        "at": "2026-09-12T02:14:00Z",
                        "incident_id": "1d0c…",
                        "kind": "escalated",
                        "target": "nobody"
                      }
                    ],
                    "unrostered_pages": 1
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The coverage report over a date range",
        "tags": [
          "records"
        ]
      }
    },
    "/api/v1/auth/companions/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Revokes the companion family the phone minted, and ends any socket the\nWatch holds on it. Always `204`, idempotent, and the same for an id\nthat is somebody else's or nobody's; a stale token is accepted, because\nrevocation is never refused (`docs/AUTHENTICATION.md` §6).",
        "operationId": "auth_revoke_companion",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Revoke the caller's Apple Watch",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/handoffs/{id}/accept": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "From this moment the escalation path resolves to you for the handoff's window.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "handoff_accept",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "handoff": {
                    "id": "99ef…",
                    "status": "accepted"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Take the pager",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/chat/commands": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The built-ins first, then each installed app's, with its usage, for a\ncomposer's `/` menu. A person's token only. `docs/CHAT_API.md` §22.6.",
        "operationId": "v2_chat_command_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "commands": [
                    {
                      "app": null,
                      "description": "Page a ladder or a person",
                      "name": "page",
                      "usage": "/page <ladder> <message>  or  /page @person <message>"
                    },
                    {
                      "app": {
                        "id": "71cd…",
                        "name": "Triage bot"
                      },
                      "description": "Open a triage report",
                      "name": "triage",
                      "usage": "/triage [what]"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The slash commands you may run",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/escalation_policies/{id}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The list route's object, plus `would_wake` on every rung: the people that\nrung would page, resolved the way a firing rung is resolved, each with\nthe same `via` label the incident timeline records for a real page.\n\n**It is a live answer about the present, not a record.** It changes when\na rota rotates or somebody is retired, and what a rung *did* wake is on\nthe incident's timeline instead (`docs/INCIDENT_API.md` §16). Two\nunresolved cases are kept apart because they are different findings:\n`no_targets` is a rung that names nobody, `nobody` is a rung whose\ntargets resolve to no-one today.\n\n`at` answers the question for another instant (\"is this staffed on\nSunday night?\"), and a malformed one is a `422` rather than a silent\nanswer about now. `docs/ROUTING_API.md` §3.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "escalation_policy_show",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The instant to resolve each rung against, ISO 8601. Defaults to now.",
            "in": "query",
            "name": "at",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "escalation_policy": {
                    "id": "7b0e…",
                    "name": "Platform, out of hours",
                    "repeat_count": 1,
                    "resolved_at": "2026-09-17T18:04:11Z",
                    "rules": [
                      {
                        "ack_timeout_seconds": 300,
                        "id": "2d55…",
                        "position": 0,
                        "targets": [
                          {
                            "position": 0,
                            "schedule_id": "5e21…",
                            "type": "schedule"
                          }
                        ],
                        "would_wake": {
                          "unresolved": null,
                          "users": [
                            {
                              "user_id": "9a2b…",
                              "via": "schedule:5e21…:layer:1"
                            }
                          ]
                        }
                      }
                    ]
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "One ladder, with who each rung would wake now",
        "tags": [
          "routing"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/join": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Any member of the account. Already in it answers the same. A private\nchannel is joined only by invitation. `docs/CHAT_API.md` §4.8.",
        "operationId": "v2_chat_join",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "archived": false,
                    "archived_at": null,
                    "created_at": "2026-10-12T14:00:00Z",
                    "created_by_user_id": "9a2b…",
                    "default_kind": null,
                    "id": "c41d…",
                    "incident_id": null,
                    "kind": "channel",
                    "member_count": 4,
                    "member_user_ids": null,
                    "membership": {
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner"
                    },
                    "name": "ops",
                    "purpose": "",
                    "site_feature_id": null,
                    "topic": "North ridge search",
                    "visibility": "public"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Join a public channel",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}/reassign": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Moves the page to `user_id`, who is notified. The incident stays open:\nreassigning is not acknowledging on somebody else's behalf.",
        "operationId": "incident_reassign",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "user_id": "9a2b…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "assigned_user_id": "9a2b…",
                    "id": "4c1f…",
                    "status": "triggered"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Hand the incident to somebody else",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/escalation_policies": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Each policy with its rungs in position order, lowest first, and what each\nrung names: a person, or a rota to ask when it fires. `repeat_count` is\nhow many times the whole list runs **again** after its last rung, so `0`\nruns the rungs once.\n\nNobody is resolved here: the detail route answers who a rung would\nactually wake, because that is a read of the rota per rung.\nAdmin-only, for the reason `GET /api/v1/sources` gives.\n`docs/ROUTING_API.md` §3.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "escalation_policy_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "escalation_policies": [
                    {
                      "id": "7b0e…",
                      "name": "Platform, out of hours",
                      "repeat_count": 1,
                      "rules": [
                        {
                          "ack_timeout_seconds": 300,
                          "id": "2d55…",
                          "position": 0,
                          "targets": [
                            {
                              "position": 0,
                              "type": "user",
                              "user_id": "9a2b…"
                            },
                            {
                              "position": 1,
                              "schedule_id": "5e21…",
                              "type": "schedule"
                            }
                          ]
                        }
                      ]
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Every escalation ladder in the account",
        "tags": [
          "routing"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/actions": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`action_id` of an element the message shows now, with\n`selected_option` (a select's value) or `selected_date`\n(`YYYY-MM-DD`). A `/page` card's Acknowledge and Resolve are answered\nhere, as you; anything else an app posted is sent to that app, signed,\nand its answer may update the message in place, open a modal or say\nsomething to you. Answered as a command is. Members only. A person's\ntoken only. `docs/CHAT_API.md` §22.7.",
        "operationId": "v2_chat_command_press",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "action_id": "take"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "closed": false,
                  "ephemeral": null,
                  "message": {
                    "body": "Sam took pump-2",
                    "edited_at": null,
                    "id": "8e2a…"
                  },
                  "view": null
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Press a button, choose an option or a date",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/unarchive": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "By its owner or an admin of it, or an account admin.\n`docs/CHAT_API.md` §4.7.",
        "operationId": "v2_chat_unarchive",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "archived": false,
                    "id": "c41d…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Unarchive a channel",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/panics/{client_event_id}/positions": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The app control's twin of the button press stream: the same body, the\nsame answers, and the same stop, keyed by the panic's own\n`client_event_id` (`docs/BUTTON_API.md` §7.3).",
        "operationId": "panic_record_positions",
        "parameters": [
          {
            "description": "The client event id.",
            "in": "path",
            "name": "client_event_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "positions": [
                  {
                    "accuracy_m": 12.5,
                    "fix_at": "2026-10-01T18:01:02Z",
                    "latitude": 47.6062,
                    "longitude": -122.3321
                  }
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "dropped": 0,
                  "stored": 1,
                  "track": {
                    "distance_m": 50,
                    "final_interval_seconds": 60,
                    "final_lead_seconds": 900,
                    "interval_seconds": 180
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Stream positions for the incident a panic raised",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/follow": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "`docs/CHAT_API.md` §12.",
        "operationId": "v2_chat_message_unfollow",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "thread": {
                      "following": false
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Stop following a thread",
        "tags": [
          "chat"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "You are pushed its replies. A thread's root only. `docs/CHAT_API.md`\n§12.",
        "operationId": "v2_chat_message_follow",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "thread": {
                      "following": true
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Follow a thread",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/cases/{id}/media": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`taken_at`, `content_type` (`image/jpeg`, `image/png`, `image/heic`) and\n`byte_size` are required; `sighting_id` attaches it to a sighting on\nthis case. `PUT` the bytes to `upload.url`, then confirm. `503\nmedia_unavailable` when no bucket is configured. `docs/CASES_API.md` §7.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "case_create_media",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "byte_size": 240000,
                "content_type": "image/jpeg",
                "taken_at": "2026-09-30T12:00:00Z"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "media": {
                    "id": "c3f2…",
                    "sighting_id": null,
                    "taken_at": "2026-09-30T12:00:00Z"
                  },
                  "upload": {
                    "expires_at": "2026-10-05T19:10:00Z",
                    "method": "PUT",
                    "url": "https://…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "URL minted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Ask for a photograph upload URL",
        "tags": [
          "cases"
        ]
      }
    },
    "/api/v1/buttons/{id}/presses/{client_event_id}/positions": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The position stream a panic or duress press started, keyed by the\npress's own `client_event_id`, until its incident is resolved. Batches\nland on the press until the incident is raised and on the incident while\nit is open. Once it has closed the answer is `409 stopped` carrying\n`stop` (the press, the terminal status and `resolved_at`, never the\nincident); points taken before `resolved_at` are still stored. Identical\nfor a panic and a duress. Requires location consent\n(`docs/BUTTON_API.md` §7.3).",
        "operationId": "button_press_positions",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The client event id.",
            "in": "path",
            "name": "client_event_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "positions": [
                  {
                    "accuracy_m": 12.5,
                    "fix_at": "2026-09-30T08:07:02Z",
                    "latitude": 47.6062,
                    "longitude": -122.3321
                  }
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "dropped": 0,
                  "stored": 1,
                  "track": {
                    "distance_m": 50,
                    "final_interval_seconds": 60,
                    "final_lead_seconds": 900,
                    "interval_seconds": 180
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Stream positions for the incident a press raised",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/v1/checkins/{id}/arm": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Sets the deadline the miss is measured against. Optionally carries a\n`location` and a `details` object in one call, so a phone starting a walk\nmakes one request rather than three. Neither can fail the transition.\n`watch_button_ids` names the caller's phone-reported panic buttons to\nwatch with this check-in; it needs location consent, and a watch that\ncannot be tied refuses the whole arm (`409 watch_refused`, or `422` on\nthe ids). The server ends the watch on satisfy or cancel, and a miss\nholds it until the miss's incident closes (`docs/BUTTON_API.md` §5).",
        "operationId": "checkin_arm",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "deadline_at": "2026-09-06T18:15:00Z",
                "details": {
                  "destination_text": "the ridge",
                  "wearing": "red jacket"
                },
                "watch_button_ids": [
                  "0b7e…"
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "checkin": {
                    "deadline_at": "2026-09-06T18:15:00Z",
                    "id": "5f0f…",
                    "state": "armed"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Arm: start the clock",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/checkins/profile": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The half that does not change per walk: the vehicle, and the dated\nphotographs. `null` when you have typed nothing. `docs/CHECKIN_API.md` §16.",
        "operationId": "checkin_profile",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "profile": {
                    "photo": null,
                    "vehicle": {
                      "colour": "grey",
                      "make": "Subaru",
                      "model": "Outback",
                      "plate": "8XYZ123",
                      "year": 2019
                    },
                    "vehicle_photo": null
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Your reusable search description",
        "tags": [
          "checkins"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Refused with `409 consent_missing` without `:details` consent. It is a\n**refusal**, deliberately unlike the transitions: somebody filling in a\nform has asked a question and is owed an answer. The plate is encrypted\nat rest and nothing can query on it.\n\nAnswers `503 encryption_unavailable` when a plate is sent and the\ndeployment has configured no encryption key, which is an operator's problem\nrather than the caller's, like `503 media_unavailable` on the photo\nroutes. The unencrypted vehicle fields still save in that state, and so\ndoes clearing a plate.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_put_profile",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "vehicle_make": "Subaru",
                "vehicle_model": "Outback",
                "vehicle_plate": "8XYZ123"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "profile": {
                    "vehicle": {
                      "make": "Subaru",
                      "model": "Outback"
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Set your reusable search description",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/handoffs/{id}/decline": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The offer closes and the rota is unchanged. The offerer is told.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "handoff_decline",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "handoff": {
                    "id": "99ef…",
                    "status": "declined"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Refuse the pager",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v1/users/me/response_notes": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Free text a responder wants their response team to know: a membership\nnumber and its incident line, an attorney, medical notes. `text` is\n`null` when nothing is set. Takes a stale token, because an app caches\nthis for an SOS it may declare with no signal. `docs/DEVICE_API.md` §8b.",
        "operationId": "response_notes_show",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "response_notes": {
                    "max_length": 1000,
                    "text": "USCCA member 1234567, incident line 1-877-...",
                    "updated_at": "2026-09-19T19:00:00Z"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Read what you share with your response team",
        "tags": [
          "users"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Replaces the text. A blank `text` deletes it. Encrypted at rest; shown to\nyour account's responders only on an incident about you, and sent to\nGarmin Response when your app declares an SOS on your paired inReach.\n`422 invalid_request` over `max_length`; `503 encryption_unavailable`\nwhen the deployment has no key (clearing still works).\n`docs/DEVICE_API.md` §8b.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "response_notes_update",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "text": "USCCA member 1234567, incident line 1-877-..."
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "response_notes": {
                    "max_length": 1000,
                    "text": "USCCA member 1234567, incident line 1-877-...",
                    "updated_at": "2026-09-19T19:00:00Z"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Set what you share with your response team",
        "tags": [
          "users"
        ]
      }
    },
    "/api/v1/map/layers/{id}/features": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The FeatureCollection of `GET /api/v1/map/features`, for one layer, with\nthe same `bbox` and the same 5,000-feature bound (`413\ntoo_many_features`). `docs/MAP_LAYERS_API.md` §4.1.",
        "operationId": "map_features",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "`min_lon,min_lat,max_lon,max_lat` in WGS 84, as on `GET /api/v1/map/features`.",
            "in": "query",
            "name": "bbox",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "features": [],
                  "type": "FeatureCollection"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "One layer's features, as GeoJSON",
        "tags": [
          "maps"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`geometry` is a GeoJSON geometry in WGS 84: a Point, LineString,\nPolygon or their Multi forms, in two dimensions. An invalid polygon\n(self-intersecting, unclosed) is `422`. `place_id` ties it to one room\nin the places registry; `major` to every place on a building or floor.\nAdmin only. `docs/MAP_LAYERS_API.md` §4.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "map_create_feature",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "geometry": {
                  "coordinates": [
                    [
                      [
                        -97.1,
                        32.7
                      ],
                      [
                        -97.0,
                        32.7
                      ],
                      [
                        -97.0,
                        32.8
                      ],
                      [
                        -97.1,
                        32.7
                      ]
                    ]
                  ],
                  "type": "Polygon"
                },
                "name": "Gate",
                "properties": {
                  "note": "Badge in"
                }
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "feature": {
                    "id": "e81f…",
                    "type": "Feature"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Add a feature to a map layer",
        "tags": [
          "maps"
        ]
      }
    },
    "/api/v1/incidents/{id}/timeline": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Every append-only timeline entry for one incident, oldest first, open or\nclosed: what was triggered, which rung of the ladder fired and who it\nwoke, every page and its outcome, who acknowledged, silenced, reassigned\nor resolved. This is what an automation posting \"here is what happened\"\non resolve reads, and what an audit reads to answer \"who was paged and\nwhen\" months later.\n\nThe envelope (`seq`, `at`, `kind`, `status`, `actor_user_id`) is the\nstable part; `data` carries each kind's own facts as the entry recorded\nthem and may gain keys. Sort and dedup on `seq`, not on `at`: `seq` is\nassigned under the incident's row lock, and `at` can tie and can be\nbackdated. Unpaginated by design: see `docs/INCIDENT_API.md` §16, which\ndocuments every kind and its `data`.",
        "operationId": "incident_timeline",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "entries": [
                    {
                      "actor_user_id": null,
                      "at": "2026-09-17T18:04:11Z",
                      "data": {
                        "paged_user_ids": [
                          "9a2b…",
                          "1f3c…"
                        ],
                        "paged_via": [
                          "named",
                          "schedule:5e21…:layer:1"
                        ],
                        "policy_id": "7b0e…",
                        "rule_id": "2d55…",
                        "target": "policy_rule"
                      },
                      "kind": "triggered",
                      "seq": 1,
                      "status": "triggered"
                    },
                    {
                      "actor_user_id": "9a2b…",
                      "at": "2026-09-17T18:05:02Z",
                      "data": {
                        "within_local_grace": false
                      },
                      "kind": "acknowledged",
                      "seq": 2,
                      "status": "acknowledged"
                    }
                  ],
                  "incident_id": "4c1f…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Read what has happened to this incident",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/uploads/{file_id}/parts": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`part_numbers`, up to 100 at a time. Each URL takes one `PUT` of that\npart's bytes and answers its `ETag`, which completing needs. Ask as\nyou go: the URLs are short-lived. `docs/CHAT_API.md` §20.1.",
        "operationId": "v2_chat_file_parts",
        "parameters": [
          {
            "description": "The file id.",
            "in": "path",
            "name": "file_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "part_numbers": [
                  2,
                  3
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "parts": [
                    {
                      "expires_at": "…",
                      "method": "PUT",
                      "part_number": 2,
                      "url": "https://…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "URLs to send parts to",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/map/hazards": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Weather warnings, fires, earthquakes and advisories within `radius_km`\nof `lat`,`lon` (the middle of a map's view, never anybody's position),\nin the same item and source shape as the check-in briefing. Assembled on\ndemand and never stored. Every source consulted is listed with its\n`state`; check `complete` before showing an empty map as \"nothing is\nhappening\". An item with no `latitude` is area-wide: list it with its\n`area`, do not place it. Show each item's `source.attribution`.\n`400 invalid_point` for a missing or out-of-range point; `429\nrate_limited` with `retry-after` past 60 reads in 5 minutes per user,\nsince every read spends a budget all tenants share.\n`docs/MAP_LAYERS_API.md` §8.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "map_hazards",
        "parameters": [
          {
            "description": "Latitude of the point, WGS 84.",
            "in": "query",
            "name": "lat",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "description": "Longitude of the point, WGS 84.",
            "in": "query",
            "name": "lon",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "description": "How far around it to look. The service's default when absent; at most 200.",
            "in": "query",
            "name": "radius_km",
            "required": false,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "hazards": {
                    "complete": true,
                    "items": [
                      {
                        "headline": "M 4.1 - 12 km NE of Duvall",
                        "kind": "seismic",
                        "latitude": 47.79,
                        "longitude": -121.88,
                        "severity": "moderate",
                        "source": {
                          "key": "usgs",
                          "name": "USGS Earthquake Hazards Program"
                        }
                      }
                    ],
                    "point": {
                      "latitude": 47.61,
                      "longitude": -122.33
                    },
                    "radius_km": 50,
                    "sources": [
                      {
                        "answered": true,
                        "key": "usgs",
                        "state": "fresh"
                      }
                    ]
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "What the hazard feeds say around a point, for the map",
        "tags": [
          "maps"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/incident": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`policy_id` (a ladder) or `user_id` (a person), and an optional `title`\n(the message's words otherwise). It raises exactly as `/page` does, as\nyou: rung 0 of the ladder, or the incident handed to the person. The\nincident carries `chat_message_id`, its record a `chat_raised_from`\nentry with the message and its thread as they read now, and its live\ncard is posted in the message's thread. A refusal (a ladder with no\nrungs, a person nothing can page) is `422 not_raised` with the reason,\nand nothing is raised. A person's token only. `docs/CHAT_API.md`\n§24.3.",
        "operationId": "v2_chat_command_raise_incident",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "policy_id": "5c1e…",
                "title": "Pump 2 leaking into bay 3"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "id": "a6f0…",
                    "status": "triggered",
                    "title": "Pump 2 leaking into bay 3"
                  },
                  "message": {
                    "id": "8e2a…",
                    "thread_root_id": "7d10…"
                  },
                  "reached": "Primary (Sam Reyes)"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Raised."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Raise an incident from a message",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/{id}/satisfy": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "A timer goes idle; a daily rolls to its next occurrence. Send `code` when\nthe check-in requires one. Nothing in the response distinguishes a duress\nsatisfy from an ordinary one, and that is the design (`docs/CHECKIN_API.md`\n§12).",
        "operationId": "checkin_satisfy",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "code": "142857"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "checkin": {
                    "deadline_at": null,
                    "id": "5f0f…",
                    "state": "idle"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The one tap: \"I'm here\"",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/incidents/{id}/last_known_positions": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The last-known position of every inReach carried by somebody on this\nincident (the same people `POST /incidents/:id/locate` may ask), and\nhow old it is. `fix_at` is the unit's own time for the fix, not when we\nreceived it; show it beside the coordinates, and compute the age against\n`as_of` rather than the device clock. A unit that has never reported a\nfix has `position: null`, and a refresh from Garmin is requested in the\nbackground. Open incidents only: a resolved one answers `409\nincident_closed`. See `docs/INCIDENT_API.md` §18.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_last_known_positions",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "as_of": "2026-09-18T19:30:00Z",
                  "last_known_positions": [
                    {
                      "device_id": "c31f…",
                      "imei": "300434030000000",
                      "last_seen_at": "2026-09-18T19:02:40Z",
                      "low_battery": false,
                      "position": {
                        "fix_at": "2026-09-18T19:02:11Z",
                        "latitude": 43.80787,
                        "longitude": -70.16367
                      },
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "The positions."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Where each responder's inReach last reported from",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "A public channel, one you are in, or an incident's you can see. Anything\nelse is `404`. `docs/CHAT_API.md` §4.5.",
        "operationId": "v2_chat_show",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "archived": false,
                    "archived_at": null,
                    "created_at": "2026-10-12T14:00:00Z",
                    "created_by_user_id": "9a2b…",
                    "default_kind": null,
                    "id": "c41d…",
                    "incident_id": null,
                    "kind": "channel",
                    "member_count": 4,
                    "member_user_ids": null,
                    "membership": {
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner"
                    },
                    "name": "ops",
                    "purpose": "",
                    "site_feature_id": null,
                    "topic": "North ridge search",
                    "visibility": "public"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Read a conversation",
        "tags": [
          "chat"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "`name` (a channel's, by its owner or an admin of it, or an account\nadmin; never `#general`), `topic` and `purpose` (up to 250 characters,\nby any member but a guest). Each change is a `system` message in the\nconversation. `docs/CHAT_API.md` §4.6.",
        "operationId": "v2_chat_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "name": "ops-north",
                "topic": "North ridge search, sector 4"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "archived": false,
                    "archived_at": null,
                    "created_at": "2026-10-12T14:00:00Z",
                    "created_by_user_id": "9a2b…",
                    "default_kind": null,
                    "id": "c41d…",
                    "incident_id": null,
                    "kind": "channel",
                    "member_count": 4,
                    "member_user_ids": null,
                    "membership": {
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner"
                    },
                    "name": "ops",
                    "purpose": "",
                    "site_feature_id": null,
                    "topic": "North ridge search",
                    "visibility": "public"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Rename, or set the topic or purpose",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/cases/{id}/manage_token": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The old token stops working at once and the new one is returned once.\nThere is no way to read a manage token back. `docs/CASES_API.md` §4.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "case_rotate_manage_token",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "case": {
                    "id": "9b1e…"
                  },
                  "manage_token": "…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Replace the owner's manage token",
        "tags": [
          "cases"
        ]
      }
    },
    "/api/v1/incidents/{id}/search/beacon": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The loudest thing this product can do to somebody's phone, so it is gated\non the subject's beacon consent and, on a duress activation, on an\nexplicit `confirm_duress: true`. Only a literal `true` counts, so a client that\nsent the string `\"false\"` cannot light the phone of somebody under\ncoercion.\n\n`mode` is `steady`, `strobe` or `off`, and names the state rather than\ncarrying a boolean: \"off\" is a third thing rather than the absence of the\nother two. `docs/INCIDENT_API.md` §13.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_beacon",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "confirm_duress": true,
                "mode": "strobe"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "command": {
                    "id": "77ab…",
                    "kind": "beacon_strobe",
                    "status": "queued"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Command queued."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Light the subject's torch and sound their phone",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/members/{user_id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "By the channel's owner or an admin of it, or an account admin. Never\nfrom `#general`. `docs/CHAT_API.md` §4.9.",
        "operationId": "v2_chat_remove_member",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The user id.",
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "c41d…",
                  "members": [
                    {
                      "added_by_user_id": "9a2b…",
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner",
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Remove somebody from a channel",
        "tags": [
          "chat"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "`role` `admin`, `member` or `guest`, by the channel's owner or an admin\nof it, or an account admin. The owner's role is not changed here.\n`docs/CHAT_API.md` §4.9.",
        "operationId": "v2_chat_update_member",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The user id.",
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "role": "admin"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "c41d…",
                  "members": [
                    {
                      "added_by_user_id": "9a2b…",
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner",
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Change a channel member's role",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}/locate": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Asks the inReach of a responder on this incident (the assignee, anybody\nits current rung is waiting on, or anybody paged for it) for its\nposition over Iridium. Costs the customer's airtime and counts against\nthe monthly cap. Name the unit by `user_id` or `device_id`, not both.\nThe answer arrives on the incident's timeline as `locate_answered` when\nthe unit next checks its mail, or as `locate_failed` if the request did\nnot go. One unanswered locate per unit at a time: a second answers `409\nlocate_outstanding` with the first. See `docs/INCIDENT_API.md` §17.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_satellite_locate",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "user_id": "9a2b…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "locate": {
                    "device_id": "c31f…",
                    "id": "5d0e…",
                    "imei": "300434030000000",
                    "requested_at": "2026-09-18T19:02:11Z",
                    "status": "queued",
                    "user_id": "9a2b…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Locate queued."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Ask a responder's inReach where it is",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/search": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Messages in the channels, DMs and groups you can open now, newest first:\na public channel, or one you are an active member of, and nothing from\na conversation you have left. `q` is words, `\"quoted phrases\"` and\n`-word`, with `from:@name` (or `from:me`), `in:#channel`, `in:@name`,\n`has:file`, `has:link`, `has:pin`, `before:`, `after:`, `during:` a\n`YYYY-MM-DD` day (`during:` also a `YYYY-MM` month) and `is:thread`.\nA `from:` or `in:` that names nobody finds nothing. Each result is the\nmessage, its `highlight` (hits between U+E000 and U+E001), its\nconversation, and two messages either side in its timeline, so a client\njumps to its `seq`. `docs/CHAT_API.md` §21.",
        "operationId": "v2_chat_account_search",
        "parameters": [
          {
            "description": "The query, at most 500 characters.",
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Only messages before this `seq`: the `next_before_seq` answered.",
            "in": "query",
            "name": "before_seq",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "At most this many results, 1 to 50. Default 20.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "The IANA time zone the date modifiers are days in. Default UTC.",
            "in": "query",
            "name": "tz",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "has_more": false,
                  "next_before_seq": null,
                  "results": [
                    {
                      "context": {
                        "after": [],
                        "before": []
                      },
                      "conversation": {
                        "id": "c41d…",
                        "kind": "channel",
                        "name": "ops"
                      },
                      "highlight": "Generator fuel is low",
                      "message": {
                        "body": "Generator fuel is low",
                        "id": "8e2a…",
                        "kind": "text",
                        "seq": 41
                      }
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Search messages",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Oldest first, and only ever your own. Each carries its `details` (what\nyou said you were wearing and where you said you were going), so the\nscreen renders from one read. `docs/CHECKIN_API.md` §3.",
        "operationId": "checkin_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "checkins": [
                    {
                      "deadline_at": "2026-09-06T18:15:00Z",
                      "details": null,
                      "id": "5f0f…",
                      "kind": "timer",
                      "label": "Evening walk",
                      "require_code": false,
                      "state": "armed"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "List your own check-ins",
        "tags": [
          "checkins"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "A `timer` is the ad-hoc \"expect me by 6:15\"; a `daily` recurs at\n`local_time` in `time_zone`. Each check-in mints its own source, and\n`escalation_schedule_id` on that source decides who a miss pages.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "kind": "timer",
                "label": "Evening walk",
                "reminder_lead_seconds": 900
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "checkin": {
                    "id": "5f0f…",
                    "label": "Evening walk",
                    "state": "idle"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Create a check-in",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/schedules/{id}/on_call": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Resolves the layers, the overrides and the handoffs into a single answer.\nThis is the question the escalation path asks, exposed so a client can ask\nit too. See `docs/SCHEDULE_API.md` §4.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_on_call",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The instant to resolve at, ISO 8601. Defaults to now.",
            "in": "query",
            "name": "at",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "at": "2026-09-06T16:00:00Z",
                  "on_call": {
                    "user_id": "9a2b…",
                    "via": {
                      "position": 1,
                      "type": "layer"
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Who is on call right now",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v1/cases/{id}/sightings/{sighting_id}": {
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "`status` is `confirmed` or `discarded`. Only confirmed sightings steer a\nsearch, and the first one moves an open case to `sighted`.\n`docs/CASES_API.md` §6.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "case_review_sighting",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The sighting id.",
            "in": "path",
            "name": "sighting_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "status": "confirmed"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "sighting": {
                    "id": "40aa…",
                    "status": "confirmed"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Confirm or discard a sighting",
        "tags": [
          "cases"
        ]
      }
    },
    "/api/v1/places": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The rooms and zones a receiver advertises and a phone resolves. A phone\ncaches this so it can name a place it hears with **no network at all**,\nwhich is the point of the design: indoors a GPS fix carries tens of\nmetres of error, and a basement often has none. `place_uuid` is the\nother half of the identity: `null` until the first place exists.",
        "operationId": "place_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "place_uuid": "3f2a…",
                  "places": [
                    {
                      "building": "West",
                      "floor": "1",
                      "id": "7c1e…",
                      "major": 2,
                      "minor": 17,
                      "name": "Bay 3"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The account's places, and its venue UUID",
        "tags": [
          "incidents"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`major` is the building or floor and `minor` is the place; the pair is\nunique per account and is what the iBeacon frame carries. The account's\n`place_uuid` is minted on the first place and returned with it. Needs\nthe tier that carries on-site hardware; below it,\n`402 plan_feature_required`.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "place_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "building": "West",
                "floor": "1",
                "major": 2,
                "minor": 17,
                "name": "Bay 3"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "place": {
                    "id": "7c1e…",
                    "major": 2,
                    "minor": 17,
                    "name": "Bay 3"
                  },
                  "place_uuid": "3f2a…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Create a place",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/incidents/{id}/participants": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Each participant's `user_id` and why they are on it: `assignee`,\n`paged`, `subject` (the check-in's owner), `author` or `added`. Never the\nduress subject. `docs/INCIDENT_API.md` §23.5.",
        "operationId": "incident_message_participants",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident_id": "4c1f…",
                  "participants": [
                    {
                      "roles": [
                        "paged",
                        "author"
                      ],
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Who the incident's thread is for",
        "tags": [
          "incidents"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`user_id` of any member of the account who can see the incident:\n`201` when added, `200` when already on it, `422 unknown_user`\notherwise. Recorded on the timeline as `participant_added`.\n`docs/INCIDENT_API.md` §23.5.",
        "operationId": "incident_message_add_participant",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "user_id": "5f61…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "incident_id": "4c1f…",
                  "participants": [
                    {
                      "roles": [
                        "added"
                      ],
                      "user_id": "5f61…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Add somebody to the incident's thread",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/updates": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Every update that is yours after `since`, in `pts` order, at most\n`limit` (default 500, max 1,000) with `has_more`, and each author named\nonce in `users`. Continue from the `pts` answered. More than 5,000\nmissed, or `since` absent or 0, answers `too_long: true` with your\nconversations (each with `last_seq`) to re-sync by `seq` and the `pts`\nto continue from. `pts` rises but is not dense. `docs/CHAT_API.md` §9.",
        "operationId": "v2_chat_updates",
        "parameters": [
          {
            "description": "The last `pts` you applied. Absent or 0 is a first sync.",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "At most this many updates, 1 to 1,000. Default 500.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "has_more": false,
                  "pts": 1043,
                  "too_long": false,
                  "updates": [
                    {
                      "conversation_id": "c41d…",
                      "kind": "message",
                      "message": {
                        "body": "Sector 4 is clear.",
                        "id": "8e2a…",
                        "kind": "text",
                        "seq": 41
                      },
                      "pts": 1043,
                      "target_user_id": null
                    }
                  ],
                  "users": {
                    "9a2b…": {
                      "name": "Sam Searcher"
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "What you missed: the stream since a pts",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/detections/monitor/arm": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "From now on, if the phone stops reporting that its detector is running,\nor keeps reporting that it cannot sense motion, for longer than the\nwindow, the server raises an incident. `403 detection_not_enabled`\nwithout the opt-in (`docs/DETECTION_API.md` §5).",
        "operationId": "detection_arm",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "monitor": {
                    "armed": true
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Start watching the phone's detector",
        "tags": [
          "detections"
        ]
      }
    },
    "/api/v1/checkins/profile/photo/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Removes the object and the row.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_delete_photo",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a photograph",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/auth/logout": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Authenticated with the access token whose family it revokes, and a stale\none is accepted: revocation is never something to refuse. A client logs\nout by deregistering its device first and revoking second, so a phone\nwhose token lapsed does not end up signed out and still a push target.",
        "operationId": "auth_logout",
        "parameters": [],
        "responses": {
          "204": {
            "description": "Revoked."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Revoke this token family",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/leave": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Not `#general` (`422 general_channel`), and not a DM (`422\nunsupported`). `docs/CHAT_API.md` §4.8.",
        "operationId": "v2_chat_leave",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "archived": false,
                    "archived_at": null,
                    "created_at": "2026-10-12T14:00:00Z",
                    "created_by_user_id": "9a2b…",
                    "default_kind": null,
                    "id": "c41d…",
                    "incident_id": null,
                    "kind": "channel",
                    "member_count": 4,
                    "member_user_ids": null,
                    "membership": {
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner"
                    },
                    "name": "ops",
                    "purpose": "",
                    "site_feature_id": null,
                    "topic": "North ridge search",
                    "visibility": "public"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Leave a channel or a group",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/emoji/{name}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "An account admin. Reactions with it stay, as text.\n`docs/CHAT_API.md` §14.",
        "operationId": "v2_chat_account_delete_emoji",
        "parameters": [
          {
            "description": "The name.",
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Remove a custom emoji",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/receivers": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Hardware that lights, sounds, or relays a page. Their state and their enrolment.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "receiver_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "receivers": [
                    {
                      "certificate_expires_at": "2027-09-06T17:02:11Z",
                      "enrolled_at": "2026-09-06T17:02:11Z",
                      "hardware_id": "24:6f:28:aa:bb:cc",
                      "id": "bb22…",
                      "last_seen_at": "2026-09-06T17:40:00Z",
                      "model": "m5stack-basic",
                      "name": "Bay 3 beacon",
                      "scope": "account"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "List the account's receivers",
        "tags": [
          "receivers"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The claim is the one-time credential the device spends at\n`POST /receivers/enroll`, along with the `account_id` it belongs to. It is\nreturned once (`docs/RECEIVER_API.md` §3). A board the account has never\nseen needs the Lone Worker tier; below it, `403 plan_feature_required`.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "receiver_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "hardware_id": "24:6f:28:aa:bb:cc",
                "model": "m5stack-basic",
                "name": "Bay 3 beacon"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "account_id": "14a1…",
                  "claim_expires_at": "2026-09-07T17:02:11Z",
                  "claim_token": "…",
                  "receiver": {
                    "id": "bb22…",
                    "model": "m5stack-basic",
                    "name": "Bay 3 beacon"
                  },
                  "receiver_host": "receivers.alertroster.com",
                  "user_id": "9a2b…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created; the claim is in the response and will not be shown again."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Create a receiver and mint its claim",
        "tags": [
          "receivers"
        ]
      }
    },
    "/api/v1/map/layers/{id}/features/{feature_id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Admin only.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "map_delete_feature",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The feature id.",
            "in": "path",
            "name": "feature_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a map feature",
        "tags": [
          "maps"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Any of the create fields. Leaving `geometry` out keeps the shape. Admin only.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "map_update_feature",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The feature id.",
            "in": "path",
            "name": "feature_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "name": "Main gate"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "feature": {
                    "id": "e81f…",
                    "type": "Feature"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Edit a map feature",
        "tags": [
          "maps"
        ]
      }
    },
    "/api/v1/schedules/{id}/roster": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The same resolution as `on_call`, computed forward over a window so a\nclient can draw a rota rather than ask repeatedly.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_roster",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Start of the window, ISO 8601. Defaults to now.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "End of the window, ISO 8601. Defaults to seven days after `from`, and must be after it.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "from": "2026-09-06T16:00:00Z",
                  "segments": [
                    {
                      "ends_at": "2026-09-07T16:00:00Z",
                      "on_call": {
                        "user_id": "9a2b…",
                        "via": {
                          "position": 1,
                          "type": "layer"
                        }
                      },
                      "starts_at": "2026-09-06T16:00:00Z"
                    }
                  ],
                  "to": "2026-09-13T16:00:00Z"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The look-ahead: who is on call, and when, over a window",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/thread": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Replies oldest first after `after_seq`, at most `limit` (default 200,\nmax 500), with `has_more`. `404` when the message is not a root here.\n`docs/CHAT_API.md` §12.",
        "operationId": "v2_chat_message_thread",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Return replies with a `seq` greater than this. Default 0.",
            "in": "query",
            "name": "after_seq",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "At most this many replies, 1 to 500. Default 200.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "c41d…",
                  "has_more": false,
                  "replies": [
                    {
                      "id": "91c0…",
                      "thread_root_id": "8e2a…"
                    }
                  ],
                  "root": {
                    "id": "8e2a…",
                    "thread": {
                      "following": true,
                      "reply_count": 2
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "A thread: its root and replies",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/{id}/extend": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`expected_deadline_at`, when sent, must match the row, which is what\nmakes a lock-screen \"+15 minutes\" safe against a double tap and against\nextending a deadline a daily roll has already replaced.",
        "operationId": "checkin_extend",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "by_seconds": 900,
                "expected_deadline_at": "2026-09-06T18:15:00Z"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "checkin": {
                    "deadline_at": "2026-09-06T18:30:00Z",
                    "id": "5f0f…",
                    "state": "armed"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Push the deadline out",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/receivers/catalogue": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "What a provisioning screen offers, and what firmware each model expects.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "receiver_catalogue",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "receivers": [
                    {
                      "chip": "ESP32",
                      "firmware": null,
                      "id": "m5stack-basic",
                      "name": "M5Stack Basic",
                      "status": "tested"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The receiver models this account can enrol",
        "tags": [
          "receivers"
        ]
      }
    },
    "/api/v1/incidents/{id}/search": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Everything a responder looking for somebody can see: the captured trail,\nthe commands asked of the device, whether a fresh fix or the beacon is\navailable, and what the subject looks like. `docs/INCIDENT_API.md` §13.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_search",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "search": {
                    "beacon": {
                      "available": false,
                      "reason": "not_opted_in",
                      "state": "off"
                    },
                    "checkin_id": "5f0f…",
                    "commands": [],
                    "locate": {
                      "available": true,
                      "reason": null
                    },
                    "positions": [],
                    "subject": null,
                    "subject_user_id": "9a2b…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The search panel for a missed check-in",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/archive": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "By its owner or an admin of it, or an account admin. Never `#general`.\nAn archived channel is read-only until unarchived: posts and changes\nanswer `409 archived`. `docs/CHAT_API.md` §4.7.",
        "operationId": "v2_chat_archive",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "archived": true,
                    "id": "c41d…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Archive a channel",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}/plan/{item_id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "`revision` as on `PATCH`, here as a query parameter; a stale one is `409\nstale_revision`. The item leaves the plan; its history stays on the\ntimeline and the record. `docs/INCIDENT_API.md` §22.",
        "operationId": "incident_plan_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The item id.",
            "in": "path",
            "name": "item_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The item's revision the removal was made against. Required.",
            "in": "query",
            "name": "revision",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Remove a plan item, at the revision you last saw",
        "tags": [
          "incidents"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "`revision` is required: the item's revision the change was made\nagainst. Another is `409 stale_revision` with the item as it now\nstands, so two people editing at once see each other's change instead\nof overwriting it. Leaving `geometry` out keeps the shape; the kind is\nfixed. `docs/INCIDENT_API.md` §22.",
        "operationId": "incident_plan_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The item id.",
            "in": "path",
            "name": "item_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "assigned_user_id": "5f61…",
                "revision": 3
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "item": {
                    "id": "7d0e…",
                    "revision": 4
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Change a plan item, at the revision you last saw",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/incidents/{id}/acknowledge": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Stops the paging. A `POST` naming the transition, for the reason `/api/v1`'s is.",
        "operationId": "v2_incident_acknowledge",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "id": "4c1f…",
                    "status": "acknowledged"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "sync_key": []
          },
          {
            "account_token": []
          }
        ],
        "summary": "Acknowledge on behalf of the ticket",
        "tags": [
          "lane-b"
        ]
      }
    },
    "/api/v2/chat/me": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "`dnd.active` says whether Do Not Disturb is in force now, from\n`dnd.until` (a snooze) or `dnd.schedule` (a weekly window in your time\nzone). While it is, a chat push still comes, quietly: no sound, nothing\nlit. **It never quiets a page**: an incident wakes you whatever this\nsays. `status` is `null` once it has expired. `docs/CHAT_API.md` §11.2.",
        "operationId": "v2_chat_account_me",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "away": false,
                  "dnd": {
                    "active": false,
                    "schedule": {
                      "days": [
                        1,
                        2,
                        3,
                        4,
                        5
                      ],
                      "end": "07:00",
                      "start": "22:00",
                      "timezone": "America/Detroit"
                    },
                    "until": null
                  },
                  "status": {
                    "emoji": "🚒",
                    "expires_at": "2026-10-20T18:00:00Z",
                    "text": "On a call"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Your Do Not Disturb, away and status",
        "tags": [
          "chat"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Each field optional. `dnd_until` an ISO 8601 time or `null`;\n`dnd_schedule` `{timezone, start, end, days}` (`HH:MM`, crossing\nmidnight when `end` is not after `start`; `days` ISO weekdays the\nwindow starts on, 1 is Monday) or `null`; `away` a boolean; `status`\n`{emoji, text, expires_at}` (at most 64 and 100 characters) or `null`.\nAway and status are pushed to everybody's chat socket. Answers as `GET`.\n`docs/CHAT_API.md` §11.2.",
        "operationId": "v2_chat_account_update_me",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "dnd_until": "2026-10-20T22:00:00Z",
                "status": {
                  "emoji": "🚒",
                  "text": "On a call"
                }
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "away": false,
                  "dnd": {
                    "active": true,
                    "schedule": null,
                    "until": "2026-10-20T22:00:00Z"
                  },
                  "status": {
                    "emoji": "🚒",
                    "expires_at": null,
                    "text": "On a call"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Change your Do Not Disturb, away and status",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/buttons/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Stops watching it and removes it. Its event record and its source stay\n(`docs/BUTTON_API.md` §4).\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "button_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a button",
        "tags": [
          "buttons"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "`label` and `silence_window_seconds` (60 to 3600). A new window applies\nfrom the next sweep (`docs/BUTTON_API.md` §4).\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "button_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "label": "Right strap",
                "silence_window_seconds": 600
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "button": {
                    "id": "0b7e…",
                    "label": "Right strap",
                    "silence_window_seconds": 600
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Rename a button or change its silence window",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/reactions/{emoji}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "`emoji` in the path, URL-encoded. Not there is the same answer.\n`docs/CHAT_API.md` §14.",
        "operationId": "v2_chat_message_unreact",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The emoji.",
            "in": "path",
            "name": "emoji",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "body": "Sector 4 is clear.",
                    "deleted": false,
                    "edited_at": null,
                    "id": "8e2a…",
                    "pinned": false,
                    "reactions": [
                      {
                        "count": 2,
                        "emoji": "👍",
                        "user_ids": [
                          "9a2b…",
                          "5f61…"
                        ]
                      }
                    ],
                    "seq": 41,
                    "thread": null
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Take a reaction back",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/beacon": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "A client asks before it offers the capability at all.",
        "operationId": "checkin_beacon_status",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "beacon_opt_in": false
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Whether you have opted in to the beacon",
        "tags": [
          "checkins"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Withdrawing extinguishes a torch that is burning right now, which is why\nthe revoke is ungated on the same terms as location's.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_put_beacon_opt_in",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "opt_in": true
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "beacon_opt_in": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Grant or withdraw beacon consent",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/members": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The members now, oldest first, with their role and notification level.\nAn incident's conversation has none: who it is for is the incident's\nparticipants (`docs/INCIDENT_API.md` §23.5). `docs/CHAT_API.md` §4.9.",
        "operationId": "v2_chat_members",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "c41d…",
                  "members": [
                    {
                      "added_by_user_id": "9a2b…",
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner",
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Who is in a conversation",
        "tags": [
          "chat"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`user_id` of a member of the account, by any member but a guest. A group\nstays within nine people. Already in it answers the same.\n`docs/CHAT_API.md` §4.9.",
        "operationId": "v2_chat_add_member",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "user_id": "5f61…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "c41d…",
                  "members": [
                    {
                      "added_by_user_id": "9a2b…",
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": false,
                      "notification_level": "mentions",
                      "role": "owner",
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Add somebody to a channel or a group",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}/choose": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Records which of a question's numbered `options` the caller chose and\nresolves the incident; the agent's hook types that number, and the\nchoice is written back to the tracker issue. Offered in Approve's place\nwhen `available_actions` lists `choose`. `option` is an integer and\nmust be one of the incident's `options[].n`: `422 invalid_option`\notherwise, `422 not_offered` on an incident that is not a question.\n`409` when the incident closed or somebody decided first. See\n`docs/INCIDENT_API.md` §24.",
        "operationId": "incident_choose",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "note": "Keep the old column until the apps ship.",
                "option": 2
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "decision": {
                      "decided_at": "2026-10-07T14:03:00Z",
                      "decided_by_user_id": "9a2b…",
                      "decision": "choose",
                      "note": "Keep the old column until the apps ship.",
                      "option": 2
                    },
                    "id": "4c1f…",
                    "options": [
                      {
                        "label": "Drop the column now",
                        "n": 1
                      },
                      {
                        "label": "Keep it",
                        "n": 2
                      }
                    ],
                    "status": "resolved"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Choose: answer a dev-approval question with one of its options",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/detections/monitor/heartbeat": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "About every two minutes while armed, and at once when motion sensing\nbecomes available or unavailable. `sensing_state` is `active` or\n`unavailable`; the server stamps its own clock (`docs/DETECTION_API.md`\n§5).",
        "operationId": "detection_heartbeat",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "sensing_state": "active"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "monitor": {
                    "alarmed": false,
                    "armed": true,
                    "sensing_state": "active"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Report that the detector is running",
        "tags": [
          "detections"
        ]
      }
    },
    "/api/v1/cases/{id}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Sightings in `observed_at` order, every status, and `track`: the\nconfirmed ones as a trail with distance, direction and speed between\nthem, and the legs that contradict each other. Photographs are the\nconfirmed ones, each with a URL that lives minutes and its `taken_at`\nand `age_days`; a client that draws the image without its age is\nnon-conformant. `docs/CASES_API.md` §3.",
        "operationId": "case_show",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "case": {
                    "id": "9b1e…",
                    "status": "sighted"
                  },
                  "media": [
                    {
                      "age_days": 5,
                      "id": "c3f2…",
                      "taken_at": "2026-09-30T12:00:00Z",
                      "url": "https://…"
                    }
                  ],
                  "sightings": [
                    {
                      "id": "40aa…",
                      "observed_at": "2026-10-05T19:05:00Z",
                      "status": "confirmed"
                    }
                  ],
                  "track": {
                    "conflicts": [],
                    "legs": [],
                    "points": [
                      {
                        "observed_at": "2026-10-05T19:05:00Z",
                        "sighting_id": "40aa…"
                      }
                    ]
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "One case, with its sightings and photographs",
        "tags": [
          "cases"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Any detail, and the last-seen point as a `latitude` and `longitude`\npair. `status` may only become `recovered` or `closed`, and then\n`outcome` (`reunited`, `found_deceased`, `withdrawn`) is required. A\nfinished case refuses every change. `docs/CASES_API.md` §5.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "case_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "outcome": "reunited",
                "status": "recovered"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "case": {
                    "id": "9b1e…",
                    "outcome": "reunited",
                    "status": "recovered"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Change a case, or finish it",
        "tags": [
          "cases"
        ]
      }
    },
    "/api/v1/schedules/{id}/handoffs": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "An offer, not a fact: the recipient accepts or declines, and the pager\ndoes not move until they do. `docs/SCHEDULE_API.md` §5. Included from\nthe Lone Worker tier; below it, `403 plan_feature_required` (§11).\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_create_handoff",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "ends_at": "2026-09-07T00:00:00Z",
                "starts_at": "2026-09-06T18:00:00Z",
                "to_user_id": "9a2b…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "handoff": {
                    "id": "99ef…",
                    "status": "pending"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Offered."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Offer the pager to somebody",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v1/receivers/enroll": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "**Unauthenticated by construction**: the claim in the body *is* the\ncredential, which is why this route carries no `Authorization` header and\nis metered per client IP like the other unauthenticated sign-in routes.\nThe device sends a CSR and gets back a certificate it then uses for mTLS.\n`docs/RECEIVER_API.md` §4.",
        "operationId": "receiver_enroll",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "account_id": "14a1…",
                "claim_token": "…",
                "csr": "-----BEGIN CERTIFICATE REQUEST-----\n…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "ca_certificate": "-----BEGIN CERTIFICATE-----\n…",
                  "certificate": "-----BEGIN CERTIFICATE-----\n…",
                  "certificate_expires_at": "2027-09-06T17:02:11Z",
                  "receiver": {
                    "enrolled_at": "2026-09-06T17:02:11Z",
                    "id": "bb22…",
                    "name": "Bay 3 beacon"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Enrolled; the certificate and the CA that signed it are in the response."
          }
        },
        "security": [],
        "summary": "Spend a claim for a client certificate",
        "tags": [
          "receivers"
        ]
      }
    },
    "/api/v1/incidents/{id}/approve": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Records the caller's approval on an open dev-approval incident and\nresolves it; the decision is then written back to the tracker issue the\nagent was working. Offered only when `available_actions` lists\n`approve`. `409` when the incident closed or somebody decided first,\n`422` when it is not a dev-approval incident. See\n`docs/INCIDENT_API.md` §24.",
        "operationId": "incident_approve",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "note": "Go ahead, keep the migration reversible."
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "decision": {
                      "decided_at": "2026-10-07T14:03:00Z",
                      "decided_by_user_id": "9a2b…",
                      "decision": "approve",
                      "note": "Go ahead, keep the migration reversible."
                    },
                    "id": "4c1f…",
                    "status": "resolved"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Approve: answer a dev-approval incident yes",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/incidents/{id}/context": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "What the sources say **now** about the destination this incident's\nsubject stated **then**: the weather that closed in, the fire they\nwalked toward. The destination is the copy frozen when the miss raised;\nthe conditions are live.\n\nThe same object `GET /checkins/:id/briefing` returns, because the clients\nmerge the two into one model. `404 no_destination` on any incident with\nno frozen located destination, which is most of them. A source that is\ndown is reported in `sources` rather than failing the request, so check\n`complete` before telling a responder that nothing is happening.\n`docs/CHECKIN_API.md` §21.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_context",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "briefing": {
                    "assembled_at": "2026-09-15T21:14:02Z",
                    "complete": true,
                    "destination": {
                      "latitude": 47.7423,
                      "longitude": -121.9857,
                      "text": "the ridge above Duvall"
                    },
                    "items": [],
                    "lines": [
                      "Severe Thunderstorm Warning · Missoula, MT · National Weather Service · issued 12 min ago"
                    ],
                    "radius_km": 50,
                    "sources": [],
                    "stated_at": "2026-09-15T17:02:11Z"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Conditions at the destination a missing person named",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/handoffs/{id}/cancel": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Only the offerer can cancel, and only while the offer is still open.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "handoff_cancel",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "handoff": {
                    "id": "99ef…",
                    "status": "cancelled"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Withdraw an offer you made",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/incidents": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "For a caller that raised its event through Lane A, whose `202` carries an\nalert id and never an incident id. The source's open incident for\n`dedup_key`, otherwise its most recent one, so a decision that resolved\nit is still readable; `404` when the source has none. A lookup, not a\nlist: one incident, on the credential's source (an API token names it\nwith `source_id`). `docs/LANE_B_API.md` §5a.",
        "operationId": "v2_incident_lookup",
        "parameters": [
          {
            "description": "The dedup key the event was raised with.",
            "in": "query",
            "name": "dedup_key",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The source to look on. Required with an API token; ignored with an integration key.",
            "in": "query",
            "name": "source_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "dedup_key": "cb-herd:alertroster#575",
                    "id": "4c1f…",
                    "status": "resolved"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "sync_key": []
          },
          {
            "account_token": []
          }
        ],
        "summary": "Look up an incident by dedup key",
        "tags": [
          "lane-b"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The sync lane: the caller is a ticket system of record and gets the\nincident back, because it has somewhere to put it. Idempotent on\n`dedup_key`: the same key answers with the same incident rather than\nopening a second one.\n\n`priority` (`normal`, `high` or `emergency`) and `sound` (one of\n`chime`, `critical`, `high`, `mail`, `normal`, `ping`) are optional\nand decided at trigger: absent, the source's Default priority and Sound\nanswer, then the urgency and the priority's own tone. The source's\nLoudest priority caps the priority; an unknown sound plays the source's\ntone. `docs/LANE_B_API.md` §4.",
        "operationId": "v2_incident_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "dedup_key": "INC-4471",
                "priority": "high",
                "sound": "chime",
                "title": "Payment gateway timeouts",
                "urgency": "high"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "incident": {
                    "dedup_key": "INC-4471",
                    "id": "4c1f…",
                    "status": "triggered"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created, or the existing incident for this `dedup_key`."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "sync_key": []
          },
          {
            "account_token": []
          }
        ],
        "summary": "Open an incident, synchronously",
        "tags": [
          "lane-b"
        ]
      }
    },
    "/api/v1/places/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Receivers assigned to it keep their rows and lose the assignment, and\nare pushed a disabled config so a board stops advertising a room that\nno longer exists rather than transmitting it until somebody reboots it.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "place_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a place",
        "tags": [
          "incidents"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Including `major` and `minor`: a mis-keyed number is an ordinary\ncorrection, and every receiver assigned to the place is re-pushed its\nconfig so a board's frame and the registry cannot drift apart.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "place_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "building": "West",
                "name": "Bay 3 (loading)"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "place": {
                    "id": "7c1e…",
                    "major": 2,
                    "minor": 17,
                    "name": "Bay 3 (loading)"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Edit a place",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/schedules": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Every on-call schedule in the account.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "schedules": [
                    {
                      "id": "7714…",
                      "name": "Primary on-call",
                      "time_zone": "America/Denver"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "List schedules",
        "tags": [
          "schedules"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "A schedule carries the time zone its rotations are computed in. No tier\nlimits how many there are: the roster and the rotations on it are free on\nevery plan (`docs/SCHEDULE_API.md` §11).\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "schedule_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "name": "Primary on-call",
                "time_zone": "America/Denver"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "schedule": {
                    "id": "7714…",
                    "name": "Primary on-call"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Create a schedule",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/chat/settings": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "`edit_window_minutes` (`null`: no limit), `delete_others` (`admins`\nor `nobody`), the level a new membership starts at for a channel and\nfor a DM or group, whether DMs and groups show read receipts, and how\nlong somebody is away before their unread mentions are emailed (`null`:\nnever). `docs/CHAT_API.md` §11 and §18.",
        "operationId": "v2_chat_account_settings",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "default_channel_level": "mentions",
                  "default_dm_level": "all",
                  "delete_others": "admins",
                  "digest_after_hours": 24,
                  "edit_window_minutes": 60,
                  "read_receipts": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The account's chat settings",
        "tags": [
          "chat"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "An account admin. `edit_window_minutes` 1 to 10,080 or `null`;\n`delete_others` `admins` or `nobody`; `default_channel_level` and\n`default_dm_level` `all`, `mentions` or `none` (what a new membership\nstarts at; existing ones keep theirs); `read_receipts` a boolean;\n`digest_after_hours` 1 to 720 or `null`. `docs/CHAT_API.md` §11 and §18.",
        "operationId": "v2_chat_account_update_settings",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "delete_others": "nobody",
                "edit_window_minutes": 15,
                "read_receipts": false
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "default_channel_level": "mentions",
                  "default_dm_level": "all",
                  "delete_others": "nobody",
                  "digest_after_hours": 24,
                  "edit_window_minutes": 15,
                  "read_receipts": false
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Change the account's chat settings",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/checklist/items/{index}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Any member but a guest. `docs/CHAT_API.md` §19.5.",
        "operationId": "v2_chat_message_uncheck",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The index.",
            "in": "path",
            "name": "index",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "checklist": {
                      "items": [
                        {
                          "checked": false,
                          "index": 0
                        }
                      ]
                    },
                    "id": "8e2a…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Untick a checklist item",
        "tags": [
          "chat"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Any member but a guest. `index` from 0. Ticked already is the same\nanswer. `docs/CHAT_API.md` §19.5.",
        "operationId": "v2_chat_message_check",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The index.",
            "in": "path",
            "name": "index",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "checklist": {
                      "items": [
                        {
                          "checked": true,
                          "checked_by": "9a2b…",
                          "index": 0,
                          "text": "Fuel"
                        }
                      ],
                      "title": "Vehicle check"
                    },
                    "id": "8e2a…",
                    "kind": "checklist"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Tick a checklist item",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/map/features": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "A GeoJSON FeatureCollection of every feature on every layer, for an\naccount small enough to send whole. Each feature's `properties` carry\n`name`, `kind`, `layer_id`, `place_id` and `major` over whatever the\naccount stored. At most 5,000 features: past that it is `413\ntoo_many_features` with the `limit`, never a shorter collection, and\nthe client reads tiles or narrows with `bbox`. A malformed `bbox` is\n`400 invalid_bbox`. `docs/MAP_LAYERS_API.md` §4.1.",
        "operationId": "map_all_features",
        "parameters": [
          {
            "description": "`min_lon,min_lat,max_lon,max_lat` in WGS 84: only the features that\nintersect it. Not across the antimeridian.\n",
            "in": "query",
            "name": "bbox",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "features": [
                    {
                      "geometry": {
                        "coordinates": [
                          [
                            [
                              -97.1,
                              32.7
                            ],
                            [
                              -97.0,
                              32.7
                            ],
                            [
                              -97.0,
                              32.8
                            ],
                            [
                              -97.1,
                              32.7
                            ]
                          ]
                        ],
                        "type": "Polygon"
                      },
                      "id": "e81f…",
                      "properties": {
                        "kind": "geofence",
                        "layer_id": "5d0a…",
                        "name": "Gate"
                      },
                      "type": "Feature"
                    }
                  ],
                  "type": "FeatureCollection"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Every map feature, as GeoJSON",
        "tags": [
          "maps"
        ]
      }
    },
    "/api/v1/layers/{id}/restrictions": {
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "The windows within a week the layer covers, such as \"weekdays, nine to six\".\nThe whole set, for `members`' reason.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "layer_set_restrictions",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "restrictions": [
                  {
                    "day": "monday",
                    "from": "09:00:00",
                    "until": "18:00:00"
                  }
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "layer": {
                    "id": "aa11…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Set when a layer applies",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/membership": {
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Your own. `notification_level` `all`, `mentions` or `none`; `muted`\n`true` (until you unmute) or `false` (clears any mute);\n`muted_until` an ISO 8601 time to mute until then. Muting quiets chat\nonly; it never touches paging. `starred`, `section` (a name of your\nown, at most 40 characters, `null` to take it out of one) and\n`section_position` arrange your sidebar. A `membership` update on your stream\ntells your other devices. Answers the conversation. `403` when you are\nnot in it, `422 unsupported` on an incident's conversation.\n`docs/CHAT_API.md` §11.1.",
        "operationId": "v2_chat_membership",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "muted_until": "2026-10-21T07:00:00Z",
                "notification_level": "all"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "id": "c41d…",
                    "kind": "channel",
                    "membership": {
                      "joined_at": "2026-10-12T14:00:00Z",
                      "muted": true,
                      "muted_until": "2026-10-21T07:00:00Z",
                      "notification_level": "all",
                      "role": "member",
                      "section": "Field",
                      "section_position": 0,
                      "starred": true
                    },
                    "name": "ops"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Change your notifications in a conversation, and your sidebar",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}/plan": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The sectors, routes and measurements the search is run in, oldest\nfirst, each with its GeoJSON `geometry`, `label`, assignee and\n`revision`. A plan, never a position: the subject's positions are on\n`/search`. Removed items are left out. `docs/INCIDENT_API.md` §22.",
        "operationId": "incident_plan_index",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "items": [
                    {
                      "assigned_user_id": "9a2b…",
                      "geometry": {
                        "coordinates": [
                          [
                            [
                              -121.9,
                              47.7
                            ],
                            [
                              -121.8,
                              47.7
                            ],
                            [
                              -121.8,
                              47.8
                            ],
                            [
                              -121.9,
                              47.7
                            ]
                          ]
                        ],
                        "type": "Polygon"
                      },
                      "id": "7d0e…",
                      "kind": "sector",
                      "label": "Sector B",
                      "revision": 3
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The incident's search plan",
        "tags": [
          "incidents"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`kind` is `sector` (a Polygon or MultiPolygon), `route` (a LineString or\nMultiLineString) or `measurement` (a LineString or Polygon), in WGS 84.\nAn invalid shape is `422 invalid_item`; an assignee who is not a member\nwho can see the incident is `422 unknown_user`; a closed incident is\n`409 incident_closed`. Pushed to every board as `incident_plan_changed`.\n`docs/INCIDENT_API.md` §22.",
        "operationId": "incident_plan_create",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "assigned_user_id": "9a2b…",
                "geometry": {
                  "coordinates": [],
                  "type": "Polygon"
                },
                "kind": "sector",
                "label": "Sector B"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "item": {
                    "id": "7d0e…",
                    "kind": "sector",
                    "revision": 1
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Add a sector, route or measurement to the plan",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/user_groups": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Mentionable groups (`@nurses`), each with its members.\n`docs/CHAT_API.md` §18.",
        "operationId": "v2_chat_account_groups",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "user_groups": [
                    {
                      "handle": "nurses",
                      "id": "17aa…",
                      "name": "Nurses",
                      "user_ids": [
                        "9a2b…"
                      ]
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The account's user groups",
        "tags": [
          "chat"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "An account admin. `handle` (1 to 40 lowercase letters, digits, `-` or\n`_`), `name`, `user_ids`. Answers every group. `docs/CHAT_API.md` §18.",
        "operationId": "v2_chat_account_create_group",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "handle": "nurses",
                "name": "Nurses",
                "user_ids": [
                  "9a2b…"
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "user_groups": [
                    {
                      "handle": "nurses"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Create a user group",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/read": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`seq`: the last message you have seen. Only ever moves forward and\nnever past the last message; an older `seq` changes nothing. A move is a\n`read` update on your own stream, so your other devices clear the badge.\n`403` when you are not in it, `422 unsupported` on an incident's\nconversation, `422 invalid_request` without a valid `seq`.\n`docs/CHAT_API.md` §4.11.",
        "operationId": "v2_chat_read",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "seq": 41
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation_id": "c41d…",
                  "last_read_seq": 41
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Mark a conversation read",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/cases/{id}/media/{media_id}/confirm": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The server reads the object and records what is actually there. `422\nobject_missing` when the upload has not landed (try again);\n`too_large` or `unusable` delete the row. `docs/CASES_API.md` §7.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "case_confirm_media",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The media id.",
            "in": "path",
            "name": "media_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "media": {
                    "age_days": 5,
                    "id": "c3f2…",
                    "url": "https://…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Confirm an uploaded photograph",
        "tags": [
          "cases"
        ]
      }
    },
    "/api/v1/detections/open": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The pending window, or `null`. What the app shows when it opens from the\nprompt, or after a restart (`docs/DETECTION_API.md` §6).",
        "operationId": "detection_open",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "detection": {
                    "id": "7f3a…",
                    "state": "pending"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The caller's open detection window",
        "tags": [
          "detections"
        ]
      }
    },
    "/api/v1/map/layers/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Deletes the layer and every feature on it. Admin only.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "map_delete_layer",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a map layer",
        "tags": [
          "maps"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Changes `name` or `description`. `kind` is ignored. Admin only.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "map_update_layer",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "name": "North yard"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "layer": {
                    "id": "5d0a…",
                    "kind": "geofence",
                    "name": "North yard"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Rename a map layer",
        "tags": [
          "maps"
        ]
      }
    },
    "/api/v1/checkins/commands/{id}/ack": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "A `POST` naming the answer rather than a `PATCH` on the command: a device\nreports what happened, it does not edit a row. `outcome` is one of `ok`,\n`unsupported`, `denied` or `unavailable`.\n\nAccepted on a stale token, because a phone woken by a silent push has\nwhatever token it woke with, and a refresh in the middle of a search is a\nround trip nobody can afford. The answer is the same three-key device\npayload every command surface uses: no incident, no responder, no reason.",
        "operationId": "checkin_ack_command",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "outcome": "ok"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "command": {
                    "command_id": "77aa…",
                    "expires_at": "2026-09-06T17:12:11Z",
                    "kind": "locate"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Report what happened to a command",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/pin": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Any member but a guest. `docs/CHAT_API.md` §16.",
        "operationId": "v2_chat_message_unpin",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "pinned": false
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Unpin a message",
        "tags": [
          "chat"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Any member but a guest; said in the conversation as a system message.\n`docs/CHAT_API.md` §16.",
        "operationId": "v2_chat_message_pin",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "pinned": true
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Pin a message to its conversation",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/buttons/{id}/arm": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "From now on, if the link is not reported for longer than the silence\nwindow, or is reported disconnected for longer than it, the server\nraises an incident on the button's source. The clock starts at the\narming instant. Idempotent. A phone-reported button is watched only\nwith its owner's armed location check-in, named by `checkin_id`, and\nthe server ends the watch when that check-in ends; otherwise `409\nwatch_refused` with a stated `reason` (`docs/BUTTON_API.md` §5).",
        "operationId": "button_arm",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "checkin_id": "5f0f…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "button": {
                    "armed": true,
                    "armed_at": "2026-09-30T08:00:00Z",
                    "id": "0b7e…",
                    "watch": {
                      "active": true,
                      "checkin_id": "5f0f…",
                      "incident_id": null,
                      "reason": "checkin"
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Start watching the button",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/v1/layers/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "The layers beneath it apply where it used to.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "layer_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a layer",
        "tags": [
          "schedules"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Its name, its rotation, or where it sits in the stack.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "layer_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "name": "Weekdays (early)"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "layer": {
                    "id": "aa11…",
                    "name": "Weekdays (early)"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Reconfigure a layer",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v1/checkins/{id}": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Its source is left alone; it may carry incident history.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_delete",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Delete a check-in",
        "tags": [
          "checkins"
        ]
      },
      "patch": {
        "callbacks": {},
        "deprecated": false,
        "description": "Label, reminder lead, a daily's zone or time, and the escalation\nschedule. `kind` is immutable and the armed state moves only through the\ntransitions.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_update",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "label": "Evening walk with the dog"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "checkin": {
                    "id": "5f0f…",
                    "label": "Evening walk with the dog"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Reconfigure a check-in",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/handoffs": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "What somebody has offered you, and what you have offered and not heard\nback on. Narrow with `status`.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "handoff_index",
        "parameters": [
          {
            "description": "One of `pending`, `accepted`, `declined` or `cancelled`.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "enum": [
                "pending",
                "accepted",
                "declined",
                "cancelled"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "handoffs": [
                    {
                      "id": "99ef…",
                      "status": "pending",
                      "to_user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Handoffs waiting on you",
        "tags": [
          "schedules"
        ]
      }
    },
    "/api/v2/chat/views/{view_id}/submit": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`values`: `{block_id: value}` for the modal's inputs. Only the person\nit was opened for, within an hour, once. A required field left empty\nor a value the field does not take is `422 invalid_values` with\n`errors` by `block_id`, as are the app's own errors; the modal stays\nopen. Otherwise it closes (`closed: true`) or the app replaces it\n(`view`). `docs/CHAT_API.md` §22.8.",
        "operationId": "v2_chat_command_submit",
        "parameters": [
          {
            "description": "The view id.",
            "in": "path",
            "name": "view_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "values": {
                  "sector": "north",
                  "what": "pump 2 seal leaking"
                }
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "closed": true,
                  "ephemeral": null,
                  "message": null,
                  "view": null
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Submit a modal",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "What a responder's list screen is built from. `docs/INCIDENT_API.md` §2\nstates the latency budget this route is held to, because the list is what\na phone opens to while a page is still sounding.",
        "operationId": "incident_index",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "incidents": [
                    {
                      "description": "5xx rate 12% over 5 min, threshold 2%",
                      "emergency": true,
                      "id": "4c1f…",
                      "priority": "emergency",
                      "status": "triggered",
                      "title": "api-gateway 5xx above threshold",
                      "triggered_at": "2026-09-06T17:02:11Z",
                      "urgency": "high"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "List incidents",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/emoji": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Reacted with as `:name:`. `docs/CHAT_API.md` §14.",
        "operationId": "v2_chat_account_emoji",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "emoji": [
                    {
                      "image_url": "https://…/ack.png",
                      "name": "ack"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The account's custom emoji",
        "tags": [
          "chat"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "An account admin. `name` (1 to 32 lowercase letters, digits, `_`, `+`\nor `-`) and an https `image_url`. `docs/CHAT_API.md` §14.",
        "operationId": "v2_chat_account_create_emoji",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "image_url": "https://example.com/ack.png",
                "name": "ack"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "image_url": "https://example.com/ack.png",
                  "name": "ack"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Created."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Add a custom emoji",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/places/observations": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "What a phone heard, in one request. **Batched on purpose**: a phone\nthat was in a basement flushes a backlog when it surfaces, and that\nmust be one request rather than forty. A triple naming no place yet is\n**stored, not discarded**: it is still a record of where somebody was,\nand `POST /places` names the backlog when the room finally exists. A\n`uuid` that is not this account's venue is another site heard through a\nwall and is counted, not kept. Rides the `docs/CHECKIN_API.md` §13\nlocation consent; `403 location_consent_required` without it.",
        "operationId": "place_observations",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "observations": [
                  {
                    "kind": "enter",
                    "major": 2,
                    "minor": 17,
                    "observed_at": "2026-09-19T14:02:11Z",
                    "rssi": -71,
                    "uuid": "3f2a…"
                  }
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "foreign_venue": 0,
                  "rejected": 1,
                  "resolved": 9,
                  "stored": 12,
                  "unresolved": 3
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Record a batch of place sightings",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/panics": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "A press with no Flic and no inReach: the app's on-screen panic. Same\nbody, answers and retry rules as a button press. `gesture: \"hold\"` is a\nsilent duress: the roster is paged as an emergency and the presser's own\ndevices never are. Nothing in the body refuses it\n(`docs/BUTTON_API.md` §7.1, §7.2). An optional `position` and the\n`track` answer work as on a button press. `origin` is `phone` (the\ndefault) or `watch` for the Apple Watch app; it changes what the roster\nis told and nothing the presser receives.",
        "operationId": "panic_create",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "client_event_id": "6d1f0c52-…",
                "gesture": "hold",
                "origin": "watch",
                "position": {
                  "accuracy_m": 12.5,
                  "fix_at": "2026-10-01T17:59:58Z",
                  "latitude": 47.6062,
                  "longitude": -122.3321,
                  "reporter": "apple_watch"
                },
                "pressed_at": "2026-10-01T18:00:00Z"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "event_id": "a41c…",
                  "status": "accepted",
                  "track": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Stored and on its way to a page, or already stored."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Panic from the app's own control",
        "tags": [
          "buttons"
        ]
      }
    },
    "/api/v1/incidents/{id}/satellite_media": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Sends a photo to the Plus inReach of a responder on this incident, over\nIridium: a photo another responder sent from the field\n(`{\"field_media\": <media_id>}`, the `media_id` of a `field_media`\ntimeline entry), or the dated photograph of the person or vehicle the\nsearch panel shows (`{\"checkin_photo\": <photo_id>}`). Name the unit by\n`user_id` or `device_id`, not both; `caption` is optional and at most 160\ncharacters. Costs the customer's airtime and counts against the monthly\ncap. The outcome arrives on the timeline as `media_sent`, or as\n`media_failed` with `carried`: Garmin refuses a unit that is not a Plus\nradio, and that refusal is how it is reported. `404 media_not_found` for\na source that is not on this incident; the locate's refusals answer\n`409` as they do there. See `docs/INCIDENT_API.md` §20.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_satellite_media",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "caption": "Missing since 14:00, red jacket",
                "source": {
                  "checkin_photo": "0f6e…"
                },
                "user_id": "9a2b…"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "media": {
                    "device_id": "c31f…",
                    "id": "5d0e…",
                    "imei": "300434030000000",
                    "requested_at": "2026-09-21T19:02:11Z",
                    "status": "queued",
                    "user_id": "9a2b…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Send queued."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Send a photo from this incident to a responder's inReach",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v1/auth/request_link": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Emails a sign-in link and a short login code to `email`. Answers `202`\nwhether or not the address belongs to anybody: the response must not be a\nway to ask which email addresses have accounts.\n\nOptional `client` (`\"android\"` or `\"ios\"`) leads the email with the\ncode rather than the website link, because a phone's short path in is the\ncode and the link signs the recipient into the web app instead of the one\nthey asked from. Omit it, or send anything else, and the email is the\nlink-first one it has always been; an unrecognised value is never a\n`400`. Nothing else about the request or the response changes.\nSee `docs/AUTHENTICATION.md` §4.",
        "operationId": "auth_request_link",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "email": "ada@example.com"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "example": {},
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Accepted. Sent if the address is known; the response is the same either way."
          }
        },
        "security": [],
        "summary": "Request a magic link",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/checkins/details": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "How a client learns whether to bother offering the form at all.",
        "operationId": "checkin_details_consent_status",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "details_opt_in": false
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Whether you have opted in to a search description",
        "tags": [
          "checkins"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Withdrawing deletes what was already stored: the description, the\nvehicle, and the photographs. Ungated on the account flag for the reason\nlocation's revoke is.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_put_details_consent",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "opt_in": true
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "details_opt_in": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Grant or withdraw search-description consent",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v1/incidents/{id}/media/{media_id}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The bytes behind a `field_media` timeline entry: a photo or voice clip a\nresponder sent from a Plus inReach, attached to this incident. `media_id`\nis the entry's `data.media_id`. The body is the file itself, with its own\n`content-type` (`image/avif` and `audio/ogg` are what Garmin sends);\nany type outside the known image and audio types is served as an\n`application/octet-stream` download instead. A voice clip's transcription\nis on the entry, not here. `404 media_not_found` for an id that is not on\nthis incident; `410 media_gone` when the stored copy can no longer be\nread. See `docs/INCIDENT_API.md` §19.",
        "operationId": "incident_media",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The media id.",
            "in": "path",
            "name": "media_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Read a photo or voice clip sent from the field",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/saved": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Newest saved first, each with its message and reminder.\n`docs/CHAT_API.md` §16.",
        "operationId": "v2_chat_account_saved",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "saved": [
                    {
                      "message": {
                        "id": "8e2a…"
                      },
                      "remind_at": null,
                      "reminded_at": null,
                      "saved_at": "…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Your saved messages",
        "tags": [
          "chat"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "`message_id` of any message you can read, an incident's included, and\nan optional future `remind_at`: an ordinary push reminds you then.\nSaving again moves the reminder. `docs/CHAT_API.md` §16.",
        "operationId": "v2_chat_account_save",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "message_id": "8e2a…",
                "remind_at": "2026-10-14T08:00:00Z"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "message_id": "8e2a…",
                  "remind_at": "2026-10-14T08:00:00Z"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Saved."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Save a message for later",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/profile/photo/{id}/confirm": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "The server `HEAD`s the object and believes what it finds rather than what\nthe upload claimed. Only after this does the photograph get a URL, and\nit is handed out with its date and never without it, because a six-month-old\nphotograph presented as current sends people looking for somebody in a\ncoat they no longer own.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_confirm_photo",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "photo": {
                    "age_days": 5,
                    "id": "cc33…",
                    "kind": "person",
                    "taken_at": "2026-09-01",
                    "url": "https://…"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Confirm an uploaded photograph",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/incidents/{incident_id}": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The conversation of an incident you can see, made the first time it is\nasked for. Its messages are the incident's thread, read and posted\nthrough `/api/v2/chat/conversations/:id/messages` or through\n`docs/INCIDENT_API.md` §23 alike. `404` for an incident you cannot see.\n`docs/CHAT_API.md` §4.4.",
        "operationId": "v2_chat_incident",
        "parameters": [
          {
            "description": "The incident id.",
            "in": "path",
            "name": "incident_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversation": {
                    "id": "e7a0…",
                    "incident_id": "4c1f…",
                    "kind": "incident"
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "An incident's thread, as a conversation",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/{id}/require_code": {
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Refused with `409 no_code_set` if the caller has no check-in code yet: a\nflag that could be turned on without one would lock somebody out of their\nown check-in.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_require_code",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "require_code": true
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "checkin": {
                    "id": "5f0f…",
                    "require_code": true
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Require a code to satisfy or cancel this check-in",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/poll/vote": {
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "`options`: the indexes you choose, replacing any earlier vote; `[]`\ntakes it back. One unless the poll is `multiple`. A closed poll is\n`409 poll_closed`. `docs/CHAT_API.md` §19.4.",
        "operationId": "v2_chat_message_vote",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "options": [
                  1
                ]
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "message": {
                    "id": "8e2a…",
                    "kind": "poll",
                    "poll": {
                      "closed": false,
                      "my_votes": [
                        1
                      ],
                      "options": [
                        {
                          "count": 0,
                          "index": 0,
                          "text": "Me"
                        },
                        {
                          "count": 1,
                          "index": 1,
                          "text": "Not me"
                        }
                      ],
                      "question": "Who can cover the 0600 handoff?"
                    }
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Vote in a poll",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/checkins/code": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "Any check-in that required it stops requiring it.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_delete_code",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "code_set": false,
                  "duress_code_set": false
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Clear your check-in code",
        "tags": [
          "checkins"
        ]
      },
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "The only thing any surface ever says about either code. Neither is\nrendered anywhere, and `docs/CHECKIN_API.md` §11 states that as a\ncontract rather than a current fact.",
        "operationId": "checkin_code_status",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "code_set": true,
                  "duress_code_set": false
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Whether a check-in code and a duress code are set",
        "tags": [
          "checkins"
        ]
      },
      "put": {
        "callbacks": {},
        "deprecated": false,
        "description": "Optionally sets a duress code in the same call. Both travel through one\nchangeset because the rule that matters most about them, that they\ndiffer, can only be checked with both plaintexts in hand.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "checkin_put_code",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "code": "142857",
                "duress_code": "271828"
              },
              "schema": {
                "additionalProperties": true,
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "code_set": true,
                  "duress_code_set": true
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Set or replace your check-in code",
        "tags": [
          "checkins"
        ]
      }
    },
    "/api/v2/chat/conversations/{id}/messages/{message_id}/audio": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "A short-lived URL to `GET` the audio of a `voice_note` message you can\nread. Mint one per play; never store it. `503 media_unavailable` when\nno media bucket is configured. `docs/CHAT_API.md` §19.7.",
        "operationId": "v2_chat_message_audio",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "The message id.",
            "in": "path",
            "name": "message_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "expires_at": "2026-10-14T14:36:50Z",
                  "url": "https://…"
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "A voice note's audio",
        "tags": [
          "chat"
        ]
      }
    },
    "/api/v1/incidents/{id}/report": {
      "delete": {
        "callbacks": {},
        "deprecated": false,
        "description": "The link stops answering on the next request. `204` whether or not one\nwas live: somebody saying \"take that page down\" needs the page down, not\na `404` about a link that was already gone. `docs/INCIDENT_API.md` §14.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_delete_report",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Withdrawn."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Withdraw the report link",
        "tags": [
          "incidents"
        ]
      },
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "`{\"report\": null}` when nothing has been shared. `view_count` and\n`last_viewed_at` answer the question a roster member actually has while a\nsearch is running (has anybody opened this?) without reading the\ntimeline. `docs/INCIDENT_API.md` §14.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_report",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "report": {
                    "expires_at": "2026-09-14T18:14:02Z",
                    "id": "b41c…",
                    "url": "https://alertroster.com/r/…",
                    "view_count": 3
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The keyed link to this incident's responder report",
        "tags": [
          "incidents"
        ]
      },
      "post": {
        "callbacks": {},
        "deprecated": false,
        "description": "Mints the capability URL a roster member hands to a search team, and\nreturns the one that already exists rather than a second. There is one\nlive link per incident, so sharing twice cannot invalidate a QR code\nalready printed and carried. `201` on a fresh mint, `200` on the link\nthat was already there.\n\n**The response body is a credential.** Anyone holding that URL can read\nthe subject's photograph, description and captured positions with no\nlogin, which is why this route demands a current access token and why the\nlink is revocable, expiring and logged. `docs/INCIDENT_API.md` §14.\n\n**Requires a current access token.** The five-minute grace the rest of `/api/v1` allows does not apply here: this route changes who gets paged, and nobody needs to do that in the five minutes before a refresh completes. A lapsed token answers `401`; refresh and retry.",
        "operationId": "incident_create_report",
        "parameters": [
          {
            "description": "The resource's identifier.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "example": {
                  "report": {
                    "expires_at": "2026-09-14T18:14:02Z",
                    "id": "b41c…",
                    "url": "https://alertroster.com/r/…",
                    "view_count": 0
                  }
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Shared."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "Share a missing-person report with responders outside the roster",
        "tags": [
          "incidents"
        ]
      }
    },
    "/api/v2/chat/switcher": {
      "get": {
        "callbacks": {},
        "deprecated": false,
        "description": "Conversations and people whose name, or a word of it, starts with `q`\n(a leading `#` or `@` is ignored): channels you can open, your DMs and\ngroups with somebody who matches, and the account's live people, at\nmost 10 of each, your own channels first. `docs/CHAT_API.md` §21.5.",
        "operationId": "v2_chat_account_switcher",
        "parameters": [
          {
            "description": "The prefix, at most 64 characters.",
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "example": {
                  "conversations": [
                    {
                      "id": "c41d…",
                      "kind": "channel",
                      "member": true,
                      "member_user_ids": null,
                      "name": "ops"
                    }
                  ],
                  "people": [
                    {
                      "name": "Dana Dispatch",
                      "user_id": "9a2b…"
                    }
                  ]
                },
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "description": "Missing, malformed, or expired credential."
          }
        },
        "security": [
          {
            "access_token": []
          }
        ],
        "summary": "The quick switcher",
        "tags": [
          "chat"
        ]
      }
    }
  },
  "security": [],
  "servers": [
    {
      "description": "This server",
      "url": "/",
      "variables": {}
    },
    {
      "url": "https://om.alertroster.com",
      "variables": {}
    }
  ],
  "tags": [
    {
      "description": "Signing in and staying signed in. See `docs/AUTHENTICATION.md` in the repository.",
      "name": "auth"
    },
    {
      "description": "Registering a phone as a push target. See `docs/DEVICE_API.md` in the repository.",
      "name": "devices"
    },
    {
      "description": "The page itself: read it, acknowledge, resolve, reassign. See `docs/INCIDENT_API.md` in the repository.",
      "name": "incidents"
    },
    {
      "description": "A heartbeat for a person: arm, extend, satisfy, cancel. See `docs/CHECKIN_API.md` in the repository.",
      "name": "checkins"
    },
    {
      "description": "Bluetooth panic buttons: register, arm, report the link, press. See `docs/BUTTON_API.md` in the repository.",
      "name": "buttons"
    },
    {
      "description": "Fall and no-motion detection: opt in, the detector's heartbeat, report, cancel. See `docs/DETECTION_API.md` in the repository.",
      "name": "detections"
    },
    {
      "description": "On-call schedules, who is on call, handoffs and overrides. See `docs/SCHEDULE_API.md` in the repository.",
      "name": "schedules"
    },
    {
      "description": "Hardware receivers: claim, enrol, and the certificate that follows. See `docs/RECEIVER_API.md` in the repository.",
      "name": "receivers"
    },
    {
      "description": "The map an account draws on: sites, geofences, buildings and floors, hazard areas. See `docs/MAP_LAYERS_API.md` in the repository.",
      "name": "maps"
    },
    {
      "description": "Missing-animal cases: open one, attach and review sightings, add dated photographs. See `docs/CASES_API.md` in the repository.",
      "name": "cases"
    },
    {
      "description": "What raises events, and the ladders an unanswered incident walks. See `docs/ROUTING_API.md` in the repository.",
      "name": "routing"
    },
    {
      "description": "What happened over a range: the closed incidents, the coverage report, the raw export. See `docs/RECORDS.md` in the repository.",
      "name": "records"
    },
    {
      "description": "The responders in an account. See `docs/AUTHENTICATION.md` in the repository.",
      "name": "users"
    },
    {
      "description": "Team chat: channels, DMs, groups, and an incident's thread as a conversation. See `docs/CHAT_API.md` in the repository.",
      "name": "chat"
    },
    {
      "description": "The async firehose a monitor fires events at. See `docs/LANE_A_API.md` in the repository.",
      "name": "lane-a"
    },
    {
      "description": "People who asked about AlertRoster on an instructor's offer, posted by the referral platform. See `docs/REFERRAL_LEADS.md` in the repository.",
      "name": "referral-leads"
    },
    {
      "description": "The synchronous surface a ticket system of record calls. See `docs/LANE_B_API.md` in the repository.",
      "name": "lane-b"
    }
  ]
}