Skip to content

REST reference

Generated at build time from docs/api/openapi.yaml (Chat Server API, version 0.2.0). Do not edit this page: change the document. Body schemas: Schemas; webhook delivery, signatures and retries: webhooks.

REST API of the team chat with agents that its instance operator hosts.

Normative REST contract of the chat server (spec-first, ADR 0013).

Conventions (names, time, IDs, errors, pagination, idempotency, concurrency, rate limits, versioning) are in docs/spec/06-api.md. Every operation names its authorization action in x-authz-action (catalogue docs/spec/05-actions.md) and its rate-limit class in x-rate-limit-class. The WebSocket gateway is described in asyncapi.yaml; its frame and event schemas live in components.schemas of this file.

The server never sends JSON null; an absent member means "no value". Clients ignore unknown members, unknown enum values and unknown event types.

License: Apache-2.0

Servers

URL Description
/api/v1 Relative to the instance origin.

Discovery

Public metadata, keys and problem types. Health probes are not part of this API (internal listener).

getDiscovery

GET /instance/discovery

Public instance metadata

  • Security: none
  • x-authz-action: instance.discovery.read
  • x-rate-limit-class: rl.public_auth

Responses:

Status Description Content Headers
200 OK. application/json: Discovery Correlation-Id, RateLimit, RateLimit-Policy
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "instance_id": "0192f4a0-7b1c-7db7-89b9-2fe4c48dcb3e",
  "setup_required": false,
  "api_versions": [
    "v1"
  ],
  "spec_version": "1.0.0",
  "gateway": {
    "url": "/api/v1/gateway",
    "protocol_versions": [
      1
    ]
  },
  "branding": {
    "product_name": "Team Chat",
    "accent_color": "loch",
    "logo_url": "/api/v1/instance/branding/logo"
  },
  "auth_providers": [
    {
      "id": "0192f4a0-7b1c-7474-8636-4dbb076ee0db",
      "kind": "oidc",
      "name": "Company SSO"
    }
  ],
  "jwks_uri": "/api/v1/instance/jwks",
  "webhook_keys_uri": "/api/v1/instance/webhook-keys"
}

getJwks

GET /instance/jwks

Public keys for access and invocation tokens

  • Security: none
  • x-authz-action: instance.discovery.read
  • x-rate-limit-class: rl.public_auth

Responses:

Status Description Content Headers
200 OK. application/jwk-set+json: Jwks Correlation-Id, RateLimit, RateLimit-Policy
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "keys": [
    {}
  ]
}

getWebhookKeys

GET /instance/webhook-keys

Public keys for webhook signatures

  • Security: none
  • x-authz-action: instance.discovery.read
  • x-rate-limit-class: rl.public_auth

Responses:

Status Description Content Headers
200 OK. application/json: WebhookKeys Correlation-Id, RateLimit, RateLimit-Policy
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "keys": [
    {
      "kid": "whk-2026-10",
      "public_key": "whpk_MCowBQYDK2VwAyEA6h3uZ0Q4i1Yv1o1Wg8bQq3c0o8bq9oQm3Kc8n3m3v0I=",
      "state": "next"
    }
  ]
}

GET /instance/branding/logo

Download the instance logo

Serves the variant medium of the logo (longest edge file.thumbnail.medium_px, re-encoded by the server without metadata, 12 3.7 and 7.3), never the original. Answers 404 while no logo is set and while the logo file is not deliverable (pending, blocked, failed or deleted) or has no variant medium, always with the same status, body and headers. The response carries Content-Disposition: inline, Cache-Control: no-store, ETag and Repr-Digest over the variant and Access-Control-Allow-Origin: * without credentials; Range is ignored.

  • Security: none
  • x-authz-action: instance.discovery.read
  • x-rate-limit-class: rl.public_auth

Responses:

Status Description Content Headers
200 OK. image/*: string (binary) Correlation-Id, RateLimit, RateLimit-Policy
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

getProblemType

GET /problems/{code}

Documentation of a problem type

  • Security: none
  • x-authz-action: instance.discovery.read
  • x-rate-limit-class: rl.public_auth

Parameters:

Name In Type Required Description
code path string yes Pattern ^[a-z0-9_]+$. Example: version_conflict.

Responses:

Status Description Content Headers
200 OK. application/json: ProblemType Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "code": "version_conflict",
  "status": 412,
  "title": "Version conflict",
  "description": "Support team"
}

submitCspReport

POST /csp-reports

Accept a CSP violation report of the web console

Endpoint of report-to csp and of Reporting-Endpoints: csp="/api/v1/csp-reports" on every console response (19-security 5 rule 6, R-AZ-33). Public, because browsers send reports without cookies in many cases; a console cookie is not checked by the CSRF guard here, the action changes nothing. Accepts the Reporting API format (application/reports+json, an array of reports) and the legacy report-uri format (application/csp-report), both limited by http.max_json_body_bytes. The server stores no report; it logs only the effective directive, the disposition and the origin of the blocked URL and counts bothy.console.csp_violations. Members it does not read are ignored.

  • Security: none
  • x-authz-action: console.csp_report
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: telemetry

Request body (required): application/reports+json: CspReportList
application/csp-report: CspReportLegacy

Reporting API
[
  {
    "type": "csp-violation",
    "age": 10,
    "url": "https://chat.example.com/console/",
    "body": {
      "documentURL": "https://chat.example.com/console/",
      "blockedURL": "https://cdn.example.com/x.js",
      "effectiveDirective": "script-src-elem",
      "disposition": "enforce"
    }
  }
]
Legacy report-uri
{
  "csp-report": {
    "document-uri": "https://chat.example.com/console/",
    "blocked-uri": "inline",
    "effective-directive": "script-src-elem",
    "disposition": "enforce"
  }
}

Responses:

Status Description Content Headers
204 Report accepted (also when it names nothing the server logs). Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
415 UnsupportedMediaType: Problem codes: unsupported_media_type. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Auth

Login flows, token refresh with DPoP, logout and step-up.

beginOidcLogin

POST /auth/oidc/begin

Start an OIDC login

  • Security: none
  • x-authz-action: auth.login.begin
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Request body (required): application/json: OidcBeginRequest

Request
{
  "provider_id": "0192f4a0-7b1c-7b3c-87cd-dea30414c03e",
  "app_redirect_uri": "com.example.teamchat:/login",
  "client_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
}

Responses:

Status Description Content Headers
200 OK. application/json: OidcBeginResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "login_attempt_id": "0192f4a0-7b1c-74de-8f28-b1bfbb9fa235",
  "authorization_url": "https://login.example.com/authorize?client_id=chat&state=s1",
  "expires_at": "2026-10-10T09:30:00.000Z"
}

handleOidcCallback

GET /auth/oidc/callback

OIDC redirect target of the identity provider

Exchanges the code at the provider and verifies the ID token. It stores only the verified external identity in the login flow; mapping, linking and provisioning happen at completeOidcLogin (08, 2.2). Then it redirects to app_redirect_uri with the query parameters login_code (one-time, valid auth.server_code_ttl) and login_attempt_id. After the flow was found, every failure redirects with error and login_attempt_id; error is one of access_denied (the provider sent an error), login_failed (a check failed) and flow_expired. An unknown or expired state gets 400 without a redirect.

  • Security: none
  • x-authz-action: auth.login.begin
  • x-rate-limit-class: rl.public_auth

Parameters:

Name In Type Required Description
state query string yes State from the authorization request.
iss query string no Issuer of the authorization response (RFC 9207). Required when the provider announces authorization_response_iss_parameter_supported.
code query string no Authorization code.
error query string no Error code from the provider.

Responses:

Status Description Content Headers
302 Redirect to app_redirect_uri with login_code and login_attempt_id, or with error and login_attempt_id. Correlation-Id, RateLimit, RateLimit-Policy, Location
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

completeOidcLogin

POST /auth/oidc/complete

Finish an OIDC login and register the device

  • Security: none
  • x-authz-action: auth.login.complete
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string no As DpopProof; not for client = console.

Request body (required): application/json: OidcCompleteRequest

Request
{
  "login_code": "lc_8f2d1c",
  "client_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
  "device": {
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "name": "Alex iPhone",
    "platform": "ios",
    "app_version": "1.4.0",
    "public_jwk": {},
    "alg": "ES256"
  }
}

Responses:

Status Description Content Headers
200 ConsoleLogin: Console session (08, 7.5). application/json: ConsoleSession Correlation-Id, Set-Cookie
201 Created. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "oidc",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex iPhone",
    "platform": "ios",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

loginWithTrustedHeader

POST /auth/trusted-header/login

Log in with the identity header of a trusted reverse proxy

Only enabled when the server listens on loopback and a trusted_header provider is active; otherwise 404.

  • Security: none
  • x-authz-action: auth.login.complete
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string no As DpopProof; not for client = console.

Request body (required): application/json: TrustedHeaderLoginRequest

Request
{
  "device": {
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "name": "Alex iPhone",
    "platform": "ios",
    "app_version": "1.4.0",
    "public_jwk": {},
    "alg": "ES256"
  }
}

Responses:

Status Description Content Headers
200 ConsoleLogin: Console session (08, 7.5). application/json: ConsoleSession Correlation-Id, Set-Cookie
201 Created. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "oidc",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex iPhone",
    "platform": "ios",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

beginPasskeyLogin

POST /auth/passkey/begin

Start a passkey login

Starts a passkey login. The ceremony state is stored on the server (auth_challenges) and is valid once for auth.login_flow_ttl. Only people with an active identity of the local driver can log in with a passkey. For an unknown login name the options carry one decoy credential ID derived by HMAC, so the answer reveals no accounts.

  • Security: none
  • x-authz-action: auth.login.begin
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Request body (required): application/json: PasskeyLoginBeginRequest

Request
{
  "login_name": "alex"
}

Responses:

Status Description Content Headers
200 OK. application/json: WebAuthnChallenge Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "public_key": {},
  "expires_at": "2026-10-10T09:30:00.000Z"
}

completePasskeyLogin

POST /auth/passkey/complete

Finish a passkey login and register the device

Completes a passkey login with a DPoP proof of the device key. A new device stays pending until approved; a known active device stays active. Every rejection gives the same 401 body.

  • Security: none
  • x-authz-action: auth.login.complete
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string no As DpopProof; not for client = console.

Request body (required): application/json: PasskeyLoginCompleteRequest

Request
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "credential": {},
  "device": {
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "name": "Alex iPhone",
    "platform": "ios",
    "app_version": "1.4.0",
    "public_jwk": {},
    "alg": "ES256"
  }
}

Responses:

Status Description Content Headers
200 ConsoleLogin: Console session (08, 7.5). application/json: ConsoleSession Correlation-Id, Set-Cookie
201 Created. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "oidc",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex iPhone",
    "platform": "ios",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

beginEnrollment

POST /auth/enroll/begin

Start the first passkey registration with an enrollment code

Starts the first passkey registration with an enrollment code of purpose first_login or recovery. The code is checked but not redeemed; the stored challenge keeps a reference to it. Every rejected code gives 401.

  • Security: none
  • x-authz-action: auth.login.begin
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Request body (required): application/json: EnrollBeginRequest

Request
{
  "enrollment_code": "en_4KX9-2MQA"
}

Responses:

Status Description Content Headers
200 OK. application/json: WebAuthnChallenge Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "public_key": {},
  "expires_at": "2026-10-10T09:30:00.000Z"
}

completeEnrollment

POST /auth/enroll/complete

Register the first passkey and log in

Registers the first passkey and logs in; the enrollment code of the challenge is redeemed in the same transaction and the device becomes active. A failed verification counts as a failed attempt of the code. Every rejection gives 401.

  • Security: none
  • x-authz-action: auth.login.complete
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string yes DPoP proof (RFC 9449) signed with the device key that the new tokens will be bound to.

Request body (required): application/json: EnrollCompleteRequest

Request
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "credential": {},
  "passkey_name": "Laptop",
  "device": {
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "name": "Alex iPhone",
    "platform": "ios",
    "app_version": "1.4.0",
    "public_jwk": {},
    "alg": "ES256"
  }
}

Responses:

Status Description Content Headers
201 Created. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "oidc",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex iPhone",
    "platform": "ios",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

redeemEnrollmentCode

POST /auth/enroll/redeem

Redeem an enrollment code with device keys and log in

Redeems an enrollment code without a passkey; the redeeming device becomes active (08, 3.2). Every rejected code (unknown, used, expired, exhausted, wrong purpose, person not active) gets the same 401 body. Code and device keys are checked in one transaction; a failed attempt with a matching code counts against auth.enrollment_code_max_attempts.

  • Security: none
  • x-authz-action: auth.login.complete
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string yes DPoP proof (RFC 9449) signed with the device key that the new tokens will be bound to.

Request body (required): application/json: EnrollRedeemRequest

Request
{
  "enrollment_code": "en_EXAMPLE",
  "device": {
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "name": "Alex iPhone",
    "platform": "ios",
    "app_version": "1.4.0",
    "public_jwk": {},
    "alg": "ES256"
  }
}

Responses:

Status Description Content Headers
201 Created. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "enrollment_code",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex iPhone",
    "platform": "ios",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

beginPairing

POST /auth/pairing/begin

Start a device pairing without login

The new device registers its public keys and shows the returned code. An active device of the same person approves it with approvePairing (08, 5.3).

  • Security: none
  • x-authz-action: auth.login.begin
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string yes DPoP proof (RFC 9449) signed with the device key that the new tokens will be bound to.

Request body (required): application/json: PairingBeginRequest

Request
{
  "device": {
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "name": "Alex Laptop",
    "platform": "macos",
    "app_version": "1.4.0",
    "public_jwk": {},
    "alg": "ES256",
    "step_up_key": {
      "public_jwk": {},
      "alg": "ES256"
    }
  }
}

Responses:

Status Description Content Headers
201 Created. application/json: PairingStarted Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "pairing_id": "0192f4a0-7b1c-7e21-8f3a-5b6c7d8e9f10",
  "pairing_code": "7KQ2-M9XD",
  "expires_at": "2026-10-10T09:35:00.000Z"
}

completePairing

POST /auth/pairing/complete

Collect the tokens of an approved pairing

The DPoP proof must be signed with the dpop key registered at beginPairing; a proof signed by another key rejects the pairing. Before approval the answer is 202 with the status; after expiry or rejection 410.

  • Security: none
  • x-authz-action: auth.login.complete
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string yes DPoP proof (RFC 9449) signed with the device key that the new tokens will be bound to.

Request body (required): application/json: PairingCompleteRequest

Request
{
  "pairing_id": "0192f4a0-7b1c-7e21-8f3a-5b6c7d8e9f10"
}

Responses:

Status Description Content Headers
201 Created. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
202 Not yet approved. application/json: PairingStatus Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "device_pairing",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex Laptop",
    "platform": "macos",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

loginWithPassword

POST /auth/password/login

Log in with local password and TOTP

Fallback for local accounts. 404 when auth.local_password_enabled is false. A new device stays pending until approved (08, 5.2). Unknown names, wrong passwords and locked accounts give the same 401.

  • Security: none
  • x-authz-action: auth.login.complete
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string no As DpopProof; not for client = console.

Request body (required): application/json: PasswordLoginRequest

Request
{
  "login_name": "alex",
  "password": "example-password",
  "totp_code": "492039",
  "device": {
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "name": "Alex iPhone",
    "platform": "ios",
    "app_version": "1.4.0",
    "public_jwk": {},
    "alg": "ES256"
  }
}

Responses:

Status Description Content Headers
200 ConsoleLogin: Console session (08, 7.5). application/json: ConsoleSession Correlation-Id, Set-Cookie
201 Created. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "oidc",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex iPhone",
    "platform": "ios",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

refreshToken

POST /auth/token/refresh

Rotate the refresh token

The DPoP proof must use the device key of the session. Reuse of an already rotated token revokes the token family and the session (session_revoked), except within auth.refresh_reuse_grace with the same key. In maintenance mode (server.maintenance_mode = read_only, ADR 0065) the server issues a new access token and returns the same refresh token, without rotation.

  • Security: none
  • x-authz-action: auth.token.refresh
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Parameters:

Name In Type Required Description
DPoP header string yes DPoP proof (RFC 9449) signed with the device key that the new tokens will be bound to.

Request body (required): application/json: TokenRefreshRequest

Request
{
  "refresh_token": "rt_q2Z0"
}

Responses:

Status Description Content Headers
200 OK. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "oidc",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex iPhone",
    "platform": "ios",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

logout

POST /auth/logout

End the current session

Parameters:

Name In Type Required Description
X-Console-Request header string no CSRF header of the console (SEC-CORS-4). Values: 1.

Responses:

Status Description Content Headers
204 No content. Correlation-Id, Set-Cookie, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

createStepUpChallenge

POST /auth/step-up/challenge

Create a step-up challenge

Parameters:

Name In Type Required Description
X-Console-Request header string no CSRF header of the console (SEC-CORS-4). Values: 1.

Responses:

Status Description Content Headers
200 OK. application/json: StepUpChallenge Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "challenge": "Zm9vYmFyYmF6",
  "expires_at": "2026-10-10T09:30:00.000Z"
}

completeStepUpWithPasskey

POST /auth/step-up/passkey

Confirm step-up with a passkey

Completes a step-up with a passkey assertion over the step-up challenge. A passkey of another person fails and counts toward auth.step_up_fail_limit.

Parameters:

Name In Type Required Description
X-Console-Request header string no CSRF header of the console (SEC-CORS-4). Values: 1.

Request body (required): application/json: StepUpPasskeyRequest

Request
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "credential": {}
}

Responses:

Status Description Content Headers
200 StepUpDone: OK; a console session gets a new cookie (08, 7.5). application/json: StepUpResult Correlation-Id, Set-Cookie
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

completeStepUpWithDeviceKey

POST /auth/step-up/device-key

Confirm step-up with the device key after user verification

Request body (required): application/json: StepUpDeviceKeyRequest

Request
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "signature": "eyJhbGciOiJFUzI1NiJ9.eyJjIjoiWm05dlltRnlZbUY2In0.sig"
}

Responses:

Status Description Content Headers
200 OK. application/json: StepUpResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "step_up_at": "2026-10-10T09:30:00.000Z",
  "valid_until": "2026-10-10T09:30:00.000Z"
}

stepUpWithPassword

POST /auth/step-up/password

Console step-up with password and TOTP

Parameters:

Name In Type Required Description
X-Console-Request header string no CSRF header of the console (SEC-CORS-4). Values: 1.

Request body (required): application/json: StepUpPasswordRequest

Responses:

Status Description Content Headers
200 StepUpDone: OK; a console session gets a new cookie (08, 7.5). application/json: StepUpResult Correlation-Id, Set-Cookie
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

beginStepUpOidcReauth

POST /auth/step-up/oidc

Start a console step-up with OIDC

Parameters:

Name In Type Required Description
X-Console-Request header string no CSRF header of the console (SEC-CORS-4). Values: 1.

Request body (required): application/json: StepUpOidcBeginRequest

Responses:

Status Description Content Headers
200 OK. application/json: OidcBeginResponse Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

completeStepUpOidcReauth

POST /auth/step-up/oidc/complete

Finish a console step-up with OIDC

Parameters:

Name In Type Required Description
X-Console-Request header string no CSRF header of the console (SEC-CORS-4). Values: 1.

Request body (required): application/json: IdentityLinkComplete

Responses:

Status Description Content Headers
200 StepUpDone: OK; a console session gets a new cookie (08, 7.5). application/json: StepUpResult Correlation-Id, Set-Cookie
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

getConsoleSession

GET /console/session

Read the console session

Responses:

Status Description Content Headers
200 ConsoleLogin: Console session (08, 7.5). application/json: ConsoleSession Correlation-Id, Set-Cookie
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

endViewAs

DELETE /console/session/view-as

End the stored view as person

Parameters:

Name In Type Required Description
X-Console-Request header string no CSRF header of the console (SEC-CORS-4). Values: 1.

Responses:

Status Description Content Headers
204 No content. Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Me

The calling principal: profile, credentials, mentions, personal templates.

getMe

GET /me

Read the calling principal

Responses:

Status Description Content Headers
200 OK. application/json: Me Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "principal": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "is_owner": false,
  "email": "alex@example.com",
  "locale": "de",
  "time_zone": "Europe/Berlin",
  "permission_version": 1
}

updateMyProfile

PATCH /me/profile

Change own profile

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ProfileUpdate

Request
{
  "display_name": "Alex",
  "locale": "de",
  "time_zone": "Europe/Berlin"
}

Responses:

Status Description Content Headers
200 OK. application/json: User Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "handle": "sam",
  "display_name": "Sam",
  "status": "active",
  "is_owner": false,
  "locale": "en",
  "time_zone": "Europe/Berlin",
  "created_at": "2026-10-10T09:30:00.000Z"
}

setMyAvatar

PUT /me/avatar

Upload own avatar

Only for people; nothing of the body is read before authorize allowed the action. Checks in this order (12 3.7): the first part is file (400 validation_failed); the declared type is JPEG, PNG or WebP (415 unsupported_media_type, with reason file_type_denied for a type in file.denied_mime_types); the part holds at most the smaller of file.max_upload_bytes and file.upload_part_bytes (413 payload_too_large) and at least one byte, and no further part follows (400 validation_failed); open sessions (429) and free space of the file system driver (503 unavailable with reason storage_full). The new file is linked at once (avatar_file_id) and replaces the previous avatar; it becomes deliverable later, after scan and metadata removal, and until then file downloads answer 409 file_not_ready.

Request body (required): multipart/form-data: ImageUpload

Responses:

Status Description Content Headers
200 OK. application/json: User Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
415 UnsupportedMediaType: Problem codes: unsupported_media_type. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "handle": "sam",
  "display_name": "Sam",
  "status": "active",
  "is_owner": false,
  "locale": "en",
  "time_zone": "Europe/Berlin",
  "created_at": "2026-10-10T09:30:00.000Z"
}

deleteMyAvatar

DELETE /me/avatar

Remove own avatar

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

getMyCredentials

GET /me/credentials

List own identities and passkeys

Responses:

Status Description Content Headers
200 OK. application/json: CredentialOverview Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "identities": [
    {
      "id": "0192f4a0-7b1c-7dd2-83b9-528d363b749b",
      "provider_id": "0192f4a0-7b1c-7b3c-87cd-dea30414c03e",
      "provider_kind": "oidc",
      "subject": "alex",
      "issuer": "https://login.example.com",
      "linked_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "passkeys": [
    {
      "id": "0192f4a0-7b1c-7ad4-8a99-f31c00005918",
      "name": "Laptop",
      "backup_eligible": false,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "local_password_set": false,
  "totp_enrolled": false
}

POST /me/identities/begin

Start linking another identity

Request body (required): application/json: IdentityLinkBegin

Request
{
  "provider_id": "0192f4a0-7b1c-7b3c-87cd-dea30414c03e",
  "app_redirect_uri": "com.example.teamchat:/link",
  "client_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
}

Responses:

Status Description Content Headers
200 OK. application/json: OidcBeginResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "login_attempt_id": "0192f4a0-7b1c-74de-8f28-b1bfbb9fa235",
  "authorization_url": "https://login.example.com/authorize?client_id=chat&state=s1",
  "expires_at": "2026-10-10T09:30:00.000Z"
}

POST /me/identities/complete

Finish linking another identity

Request body (required): application/json: IdentityLinkComplete

Request
{
  "login_code": "lc_8f2d1c",
  "client_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
}

Responses:

Status Description Content Headers
201 Created. application/json: Identity Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7dd2-83b9-528d363b749b",
  "provider_id": "0192f4a0-7b1c-7b3c-87cd-dea30414c03e",
  "provider_kind": "oidc",
  "subject": "alex",
  "issuer": "https://login.example.com",
  "linked_at": "2026-10-10T09:30:00.000Z"
}

beginPasskeyRegistration

POST /me/passkeys/begin

Start registering a passkey

Responses:

Status Description Content Headers
200 OK. application/json: WebAuthnChallenge Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "public_key": {},
  "expires_at": "2026-10-10T09:30:00.000Z"
}

completePasskeyRegistration

POST /me/passkeys/complete

Finish registering a passkey

Request body (required): application/json: PasskeyRegisterComplete

Request
{
  "challenge_id": "0192f4a0-7b1c-747c-835d-13eca158d3c0",
  "credential": {},
  "name": "Laptop"
}

Responses:

Status Description Content Headers
201 Created. application/json: Passkey Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7ad4-8a99-f31c00005918",
  "name": "Laptop",
  "backup_eligible": false,
  "created_at": "2026-10-10T09:30:00.000Z"
}

setMyLocalCredential

PUT /me/local-credential

Set local password and enroll TOTP

Needs a local identity (else 409 conflict) and auth.local_password_enabled (else 403 feature_disabled). Step-up is required once the password path is established (TOTP confirmed, 07 4.2 step 8). The TOTP URI in the response is shown once; the call is a PUT and stores no response.

Request body (required): application/json: LocalCredentialSet

Request
{
  "password": "example-password"
}

Responses:

Status Description Content Headers
200 OK. application/json: LocalCredentialResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "password_set": true,
  "totp_enabled": false,
  "totp_secret_uri": "otpauth://totp/Team%20Chat:alex?secret=JBSWY3DPEHPK3PXP"
}

listMyMentions

GET /me/mentions

List own mentions

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: MentionItemPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "message": {
        "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
        "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
        "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
        "thread_seq": 42,
        "author": {
          "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
          "kind": "user",
          "handle": "alex",
          "display_name": "Alex"
        },
        "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
        "origin": "human",
        "kind": "text",
        "content_md": "@support-agent the invoice export fails since this morning.",
        "content_format": 1,
        "silent": false,
        "attachments": [
          {
            "position": 1,
            "file": {
              "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
              "size_bytes": 48213,
              "mime_type": "image/png",
              "original_name": "screenshot.png",
              "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
              "purpose": "attachment",
              "upload_state": "complete",
              "scan_status": "clean",
              "transcript_status": "none",
              "thumbnails": [
                {
                  "variant": "small",
                  "mime_type": "image/jpeg",
                  "width": 320,
                  "height": 180
                }
              ],
              "created_at": "2026-10-10T09:30:00.000Z"
            }
          }
        ],
        "mention_ids": [
          "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
        ],
        "reactions": [
          {
            "emoji": "👍",
            "count": 3
          }
        ],
        "pinned": false,
        "components": [
          {
            "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
            "custom_id": "approve-refund",
            "type": "button",
            "definition": {},
            "position": 1,
            "single_use": true,
            "restricted_to": "any",
            "state": "active",
            "version": 3
          }
        ],
        "version": 3,
        "created_at": "2026-10-10T09:30:00.000Z"
      },
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

listMyTemplates

GET /me/templates

List own personal templates

Personal templates of the caller, without a channel context. Channel templates come from listTemplates.

Responses:

Status Description Content Headers
200 OK. application/json: TemplateList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-777d-8541-d21a5b1c8fe4",
      "scope": "personal",
      "name": "Escalation",
      "content_md": "Please escalate this ticket to second level.",
      "version": 3
    }
  ]
}

createPersonalTemplate

POST /me/templates

Create a personal template

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: TemplateCreate

Request
{
  "name": "Escalation",
  "content_md": "Please escalate this ticket to second level."
}

Responses:

Status Description Content Headers
201 Created. application/json: Template Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-777d-8541-d21a5b1c8fe4",
  "scope": "personal",
  "name": "Escalation",
  "content_md": "Please escalate this ticket to second level.",
  "version": 3
}

Users

People and owners.

listUsers

GET /users

List people

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
q query string no Prefix match on handle or display name.
status query UserStatus no Filter by status.

Responses:

Status Description Content Headers
200 OK. application/json: UserPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "handle": "sam",
      "display_name": "Sam",
      "status": "active",
      "is_owner": false,
      "locale": "en",
      "time_zone": "Europe/Berlin",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createUser

POST /users

Create a person

With local_account the server creates the local identity (subject = handle) and a first_login enrollment code. The code is a one-time secret: a replay with the same Idempotency-Key answers 409 conflict with reason one_time_secret (06, 7).

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: UserCreate

Request
{
  "handle": "robin",
  "display_name": "Robin",
  "email": "robin@example.com",
  "locale": "de",
  "time_zone": "Europe/Berlin"
}

Responses:

Status Description Content Headers
201 Created. application/json: UserCreated Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "user": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "handle": "sam",
    "display_name": "Sam",
    "status": "active",
    "is_owner": false,
    "locale": "en",
    "time_zone": "Europe/Berlin",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

getUser

GET /users/{user_id}

Read a person

Parameters:

Name In Type Required Description
user_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: User Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "handle": "sam",
  "display_name": "Sam",
  "status": "active",
  "is_owner": false,
  "locale": "en",
  "time_zone": "Europe/Berlin",
  "created_at": "2026-10-10T09:30:00.000Z"
}

updateUser

PATCH /users/{user_id}

Change another person's profile

Parameters:

Name In Type Required Description
user_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: UserUpdate

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: User Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "handle": "sam",
  "display_name": "Sam",
  "status": "active",
  "is_owner": false,
  "locale": "en",
  "time_zone": "Europe/Berlin",
  "created_at": "2026-10-10T09:30:00.000Z"
}

disableUser

POST /users/{user_id}/disable

Disable a person

Parameters:

Name In Type Required Description
user_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
200 OK. application/json: User Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "handle": "sam",
  "display_name": "Sam",
  "status": "active",
  "is_owner": false,
  "locale": "en",
  "time_zone": "Europe/Berlin",
  "created_at": "2026-10-10T09:30:00.000Z"
}

enableUser

POST /users/{user_id}/enable

Enable a person

Parameters:

Name In Type Required Description
user_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
200 OK. application/json: User Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "handle": "sam",
  "display_name": "Sam",
  "status": "active",
  "is_owner": false,
  "locale": "en",
  "time_zone": "Europe/Berlin",
  "created_at": "2026-10-10T09:30:00.000Z"
}

createEnrollmentCode

POST /users/{user_id}/enrollment-codes

Issue an enrollment code

Issues a code for an active person: first_login for a person with a local identity and no device yet, recovery for a person with a local identity and a device, identity_link for a person without a local identity (08, 3.2). Issuing ends every other unused code of the person. The code is a one-time secret: a replay with the same Idempotency-Key answers 409 conflict with reason one_time_secret instead of repeating it (06, 7).

Parameters:

Name In Type Required Description
user_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
201 Created. application/json: EnrollmentCode Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "code": "en_4KX9-2MQA",
  "purpose": "first_login",
  "expires_at": "2026-10-10T09:30:00.000Z"
}

getUserCredentials

GET /users/{user_id}/credentials

List identities and passkeys of a person

Parameters:

Name In Type Required Description
user_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: CredentialOverview Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "identities": [
    {
      "id": "0192f4a0-7b1c-7dd2-83b9-528d363b749b",
      "provider_id": "0192f4a0-7b1c-7b3c-87cd-dea30414c03e",
      "provider_kind": "oidc",
      "subject": "alex",
      "issuer": "https://login.example.com",
      "linked_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "passkeys": [
    {
      "id": "0192f4a0-7b1c-7ad4-8a99-f31c00005918",
      "name": "Laptop",
      "backup_eligible": false,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "local_password_set": false,
  "totp_enrolled": false
}

unlinkIdentity

DELETE /users/{user_id}/identities/{identity_id}

Unlink an identity

Parameters:

Name In Type Required Description
user_id path Uuid yes
identity_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

revokePasskey

DELETE /users/{user_id}/passkeys/{passkey_id}

Revoke a passkey

Parameters:

Name In Type Required Description
user_id path Uuid yes
passkey_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

listOwners

GET /owners

List owners

Responses:

Status Description Content Headers
200 OK. application/json: OwnerList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "user": {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "kind": "user",
        "handle": "alex",
        "display_name": "Alex"
      },
      "granted_at": "2026-10-10T09:30:00.000Z",
      "reason": "Requested by the space lead"
    }
  ]
}

addOwner

POST /owners

Make a person owner

Optional resolve_i1 runs the guided flow (05 rule 1.6, 10 section 11): the listed agents are authorized with agent.billing_mode.set and switched to organization first, in the same transaction as the change; I1 is checked before the commit, and either both parts commit or none.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: OwnerAdd

Request
{
  "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "reason": "Second owner as deputy"
}

Responses:

Status Description Content Headers
201 Created. application/json: Owner Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "user": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "granted_at": "2026-10-10T09:30:00.000Z",
  "reason": "Requested by the space lead"
}

revokeOwner

POST /owners/{user_id}/revoke

Remove the owner role

Fails with last_owner when no other active owner remains and with i1_violation when I1 would break.

Parameters:

Name In Type Required Description
user_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Devices

Devices, sessions and push targets.

listUserDevices

GET /users/{user_id}/devices

List devices of a person

Parameters:

Name In Type Required Description
user_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: DevicePage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "name": "Alex iPhone",
      "platform": "ios",
      "state": "active",
      "app_version": "1.4.0",
      "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

listUserSessions

GET /users/{user_id}/sessions

List sessions of a person

Parameters:

Name In Type Required Description
user_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: SessionPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
      "auth_method": "oidc",
      "created_at": "2026-10-10T09:30:00.000Z",
      "expires_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

listMyDevices

GET /me/devices

List own devices

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: DevicePage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "name": "Alex iPhone",
      "platform": "ios",
      "state": "active",
      "app_version": "1.4.0",
      "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

approvePairing

POST /me/devices/pairings

Approve a device pairing with its code

Called from an active device of the person, with step-up. Creates the new device as active for the calling person; the new device collects its tokens with completePairing within auth.pairing_code_ttl, otherwise it is revoked. A code that matches no open pairing answers 404 and ends the step-up of the calling session, so every further attempt needs a new confirmation with biometrics.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: PairingApprove

Request
{
  "pairing_code": "7KQ2-M9XD"
}

Responses:

Status Description Content Headers
201 Created. application/json: Device Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
  "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "name": "Alex Laptop",
  "platform": "macos",
  "state": "active",
  "created_at": "2026-10-10T09:30:00.000Z"
}

getDevice

GET /devices/{device_id}

Read a device

A pending device polls this to learn when it was approved.

Parameters:

Name In Type Required Description
device_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Device Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
  "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "name": "Alex iPhone",
  "platform": "ios",
  "state": "active",
  "app_version": "1.4.0",
  "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
  "created_at": "2026-10-10T09:30:00.000Z"
}

approveDevice

POST /devices/{device_id}/approve

Approve a pending device

The approving person types the verification code shown on the pending device (08, 5.2). A wrong code revokes the pending device; the answer is then 200 with state revoked, because the request had an effect.

Parameters:

Name In Type Required Description
device_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: DeviceApprove

Request
{
  "verification_code": "042517"
}

Responses:

Status Description Content Headers
200 OK. application/json: Device Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
  "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "name": "Alex iPhone",
  "platform": "ios",
  "state": "active",
  "app_version": "1.4.0",
  "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
  "created_at": "2026-10-10T09:30:00.000Z"
}

revokeDevice

POST /devices/{device_id}/revoke

Revoke a device

Closes its gateway connections with 4012 and revokes its sessions.

Parameters:

Name In Type Required Description
device_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
200 OK. application/json: Device Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
  "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "name": "Alex iPhone",
  "platform": "ios",
  "state": "active",
  "app_version": "1.4.0",
  "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
  "created_at": "2026-10-10T09:30:00.000Z"
}

registerPush

POST /me/devices/current/push-registrations

Register a push target for the current device

Registers the push target of the caller's own active device in the caller's session and returns the preview token of the registration exactly once (13, 6.4 and 13). The row binds the person, the device and the session. A known (provider, token) is taken over: its row is deleted, whoever it belonged to, so the token stops reaching its former owner; the other active registrations of this device with the same provider and app_id end with disabled_reason token_invalid (one current token per app installation). Every new registration rotates the preview token. unifiedpush and wns give 400 validation_failed with errors[].code not_enabled; apns or fcm without a configured adapter on this instance give 403 feature_disabled with reason push_provider_disabled; a principal without a session (API tokens, agents, apps) gives 403 forbidden with reason step_up_not_possible; a pending device gives 403 device_pending. The preview token is a one-time secret: a replay with the same Idempotency-Key answers 409 conflict with reason one_time_secret (06, 7), and the app registers again with a new key. A second concurrent registration of the same token can answer 409 conflict.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: PushRegistrationCreate

Request
{
  "provider": "fcm",
  "token": "EXAMPLE-device-token-a1b2",
  "app_id": "com.example.teamchat"
}

Responses:

Status Description Content Headers
201 Created. application/json: PushRegistrationCreated Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-72f6-893c-a890548910a3",
  "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
  "provider": "fcm",
  "environment": "production",
  "app_id": "com.example.teamchat",
  "created_at": "2026-10-10T09:30:00.000Z",
  "preview_token": "bothy_pvw_EXAMPLEpushpreviewtoken00000000000000000000_4Z1L0A"
}

unregisterPush

DELETE /push-registrations/{registration_id}

Remove a push target

Deletes a registration of the caller (13, 13). The token is free for a later registration and the preview token of the registration is worthless from then on. A registration of another person and an unknown one give the same 404.

Parameters:

Name In Type Required Description
registration_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

getPushPreview

GET /push/preview

Load the preview of a notification

Called by the notification extension with the preview token of the push registration (Authorization: DPoP <token>) and a DPoP proof of the device key whose ath is the hash of the preview token; no other operation accepts the token, and no other credential works here (13, 6.4; R-PN-07). Checks in this order: the parameter kind; exactly one Authorization value with the scheme DPoP; the form, kind pvw and checksum of the token without a database access; an active registration with the token; the session of the registration, whose device must be the device of the registration; the DPoP proof against the key of that session (DPoP-Nonce as on every DPoP request); then message.read on the message and push.deliver on its thread with the rights of the moment of the fetch. A missing, malformed or unknown token, a deactivated registration, a session that is unknown or belongs to another device and a wrong proof give 401; while the registration is still active, a session, device or person that is no longer active (for example an expired session) gives 401 session_revoked. auth.logout, device.revoke and user.disable deactivate the registration in their own transaction, so after them the token itself answers 401. No right, a deleted or an unknown message give 404, identical to each other. The answer follows notify.preview_mode of the person (13, 6.4 table): full with names, excerpt (text without Markdown, mentions as names, at most notify.preview_max_chars), attachment_count and image_url (a fetch ticket for the small thumbnail of the first image); names with the four names only; none only kind, thread_id, message_id and badge.

  • Security: pushPreviewToken
  • x-authz-action: message.read
  • x-rate-limit-class: rl.read

Parameters:

Name In Type Required Description
nid query Uuid yes Notification ID from the push.
message_id query Uuid yes Message of the notification.
kind query NotificationKind yes Kind of the notification, copied from the push payload (k, 13, 6.1 and 6.2). The server keeps no record of a hint, so the kind selects only the labels on the device; the answer echoes it. Only the kinds that point at a message are allowed; security and admin give 400 validation_failed with errors[].code invalid at #query/kind, before the token is checked.

Responses:

Status Description Content Headers
200 OK. application/json: PushPreview Correlation-Id, RateLimit, RateLimit-Policy, DPoP-Nonce
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "kind": "mention",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "badge": 3,
  "space_name": "Support",
  "channel_name": "tickets",
  "thread_title": "Invoice export fails",
  "sender_display_name": "Alex",
  "excerpt": "Sam can you check the export?"
}

listMySessions

GET /me/sessions

List own sessions

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: SessionPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
      "auth_method": "oidc",
      "created_at": "2026-10-10T09:30:00.000Z",
      "expires_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createExtensionSession

POST /me/sessions/extensions

Create a child session for an app extension

Creates a child session of the calling app session for the notification or share extension, with its own refresh family on the same device key (08, 7.4). An active child of the same component is replaced. The refresh token is shown once; the request carries no Idempotency-Key because a repeat only replaces the child.

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: session.extension.create
  • x-rate-limit-class: rl.write
  • x-idempotency-exempt: auth_flow

Request body (required): application/json: ExtensionSessionCreate

Request
{
  "client_component": "share_ext"
}

Responses:

Status Description Content Headers
201 Created. application/json: TokenResponse Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "access_token": "eyJhbGciOiJFZERTQSJ9.e30.sig",
  "token_type": "DPoP",
  "expires_in": 900,
  "refresh_token": "rt_q2Z0",
  "refresh_expires_at": "2026-10-10T09:30:00.000Z",
  "session": {
    "id": "0192f4a0-7b1c-75c3-8a09-bf22e12411b6",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "auth_method": "oidc",
    "client_component": "share_ext",
    "created_at": "2026-10-10T09:30:00.000Z",
    "expires_at": "2026-10-10T09:30:00.000Z"
  },
  "device": {
    "id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Alex iPhone",
    "platform": "ios",
    "state": "active",
    "app_version": "1.4.0",
    "key_thumbprint": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

revokeSession

POST /sessions/{session_id}/revoke

End a session

Parameters:

Name In Type Required Description
session_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Tokens

API tokens of agents, apps and personal tools.

listTokens

GET /principals/{principal_id}/tokens

List API tokens of a principal

Parameters:

Name In Type Required Description
principal_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: ApiTokenPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-703d-85ae-fdc884c55554",
      "principal_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "name": "Adapter production",
      "token_prefix": "bothy_agt_EXAMPL",
      "scopes": [],
      "dpop_jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
      "expires_at": "2027-10-10T00:00:00.000Z",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createToken

POST /principals/{principal_id}/tokens

Create an API token

Kind follows the principal (agt agent, app app, pat person, 08 section 12). A personal token only for oneself and only with the flag tokens.personal_enabled. A token for an app needs an active installation (else 409 conflict with reason app_not_installed, also while the app is suspended); its scopes are the requested subset of the granted scopes of the installation, or all of them when scopes is absent or empty, and a scope the installation does not grant gives 400 validation_failed at /scopes/<i>. An app request needs the scope of its action in the token and in the installation. The secret is shown once; a replay with the same Idempotency-Key answers 409 conflict with reason one_time_secret (06, 7).

Parameters:

Name In Type Required Description
principal_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ApiTokenCreate

Request
{
  "name": "Adapter production",
  "dpop_jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
  "expires_at": "2027-10-10T00:00:00.000Z"
}

Responses:

Status Description Content Headers
201 Created. application/json: ApiTokenCreated Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "token": {
    "id": "0192f4a0-7b1c-703d-85ae-fdc884c55554",
    "principal_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "name": "Adapter production",
    "token_prefix": "bothy_agt_EXAMPL",
    "scopes": [],
    "dpop_jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I",
    "expires_at": "2027-10-10T00:00:00.000Z",
    "created_at": "2026-10-10T09:30:00.000Z"
  },
  "secret": "bothy_agt_EXAMPLEOnlyNotARealTokenForTheChecksumTests_3NymP3"
}

revokeToken

DELETE /tokens/{token_id}

Revoke an API token

Parameters:

Name In Type Required Description
token_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Groups

Groups of people as grant subjects.

listGroups

GET /groups

List groups

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
member_id query Uuid no Only groups with this member.

Responses:

Status Description Content Headers
200 OK. application/json: GroupPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7abf-88a6-0fbb818f7405",
      "name": "Support",
      "description": "Support team",
      "source": "local",
      "member_count": 1,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createGroup

POST /groups

Create a group

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: GroupCreate

Request
{
  "name": "Support"
}

Responses:

Status Description Content Headers
201 Created. application/json: Group Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7abf-88a6-0fbb818f7405",
  "name": "Support",
  "description": "Support team",
  "source": "local",
  "member_count": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

getGroup

GET /groups/{group_id}

Read a group

Parameters:

Name In Type Required Description
group_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Group Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7abf-88a6-0fbb818f7405",
  "name": "Support",
  "description": "Support team",
  "source": "local",
  "member_count": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

deleteGroup

DELETE /groups/{group_id}

Delete a group and revoke its grants

Parameters:

Name In Type Required Description
group_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

updateGroup

PATCH /groups/{group_id}

Rename a group

Parameters:

Name In Type Required Description
group_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: GroupUpdate

Request
{
  "name": "Support"
}

Responses:

Status Description Content Headers
200 OK. application/json: Group Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7abf-88a6-0fbb818f7405",
  "name": "Support",
  "description": "Support team",
  "source": "local",
  "member_count": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

listGroupMembers

GET /groups/{group_id}/members

List members

Parameters:

Name In Type Required Description
group_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: GroupMemberPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "user": {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "kind": "user",
        "handle": "alex",
        "display_name": "Alex"
      },
      "added_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

addGroupMember

POST /groups/{group_id}/members

Add a member

Optional resolve_i1 runs the guided flow (05 rule 1.6, 10 section 11): the listed agents are authorized with agent.billing_mode.set and switched to organization first, in the same transaction as the change; I1 is checked before the commit, and either both parts commit or none.

Parameters:

Name In Type Required Description
group_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: GroupMemberAdd

Request
{
  "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc"
}

Responses:

Status Description Content Headers
201 Created. application/json: GroupMember Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "user": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "added_at": "2026-10-10T09:30:00.000Z"
}

removeGroupMember

DELETE /groups/{group_id}/members/{user_id}

Remove a member

Parameters:

Name In Type Required Description
group_id path Uuid yes
user_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Access

Grants, grant preview, who has access, view as person.

viewAsUser

GET /users/{user_id}/view-as

See the instance as a person sees it

Owner only, with step-up and audit. Returns the spaces and channels the person sees, with level and the end of the view (authz.view_as_max_duration). The person's direct messages stay invisible (SR6). In M1 the view lives only within this request (07, 9.2).

Parameters:

Name In Type Required Description
user_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: ViewAsSnapshot Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "user": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "expires_at": "2026-10-10T09:45:00.000Z",
  "spaces": [
    {
      "space": {
        "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
        "name": "Support",
        "sort_key": "a0",
        "version": 3,
        "created_at": "2026-10-10T09:30:00.000Z"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ]
    }
  ],
  "channels": [
    {
      "channel": {
        "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
        "kind": "text",
        "name": "tickets",
        "topic": "Customer tickets",
        "sort_key": "a1",
        "read_only": false,
        "operator": {
          "mode": "inherit"
        },
        "version": 3,
        "settings_version": 1,
        "created_at": "2026-10-10T09:30:00.000Z"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ]
    }
  ]
}

listGrants

GET /grants

List grants of a target or subject

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
target_kind query TargetKind no Target kind.
target_id query Uuid no Target ID.
subject_kind query GrantSubjectKind no Subject kind.
subject_id query Uuid no Subject ID.
include_revoked query boolean no Include revoked and expired grants.

Responses:

Status Description Content Headers
200 OK. application/json: GrantPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-727f-86bd-90fe7bdb3024",
      "subject_kind": "user",
      "subject_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "target_kind": "instance",
      "level": "read",
      "capabilities": [
        "approve_actions"
      ],
      "reason": "Support team works in this space",
      "granted_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "granted_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createGrant

POST /grants

Create a grant

Optional resolve_i1 runs the guided flow (05 rule 1.6, 10 section 11): the listed agents are authorized with agent.billing_mode.set and switched to organization first, in the same transaction as the change; I1 is checked before the commit, and either both parts commit or none.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: GrantCreate

Request
{
  "subject_kind": "user",
  "subject_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "target_kind": "instance",
  "level": "read",
  "reason": "Support team works in this space"
}
Switch the operator to organization first (guided flow)
{
  "subject_kind": "user",
  "subject_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "target_kind": "channel",
  "target_id": "0192f4a0-7b1c-7a3d-9f1e-2b4c6d8e0a12",
  "level": "trigger",
  "reason": "Sam works in the research notes",
  "resolve_i1": {
    "switch_to_organization": [
      "0192f4a0-7b1c-7c55-8e21-3f5a7b9d1c34"
    ],
    "reason": "Sam triggers the assistant too"
  }
}

Responses:

Status Description Content Headers
201 Created. application/json: Grant Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-727f-86bd-90fe7bdb3024",
  "subject_kind": "user",
  "subject_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "target_kind": "instance",
  "level": "read",
  "capabilities": [
    "approve_actions"
  ],
  "reason": "Support team works in this space",
  "granted_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "granted_at": "2026-10-10T09:30:00.000Z"
}

previewGrant

POST /grants/preview

Show what a grant would change

Dry run of createGrant (action access.preview): affected principals, level changes and invariant violations. No step-up needed; the transaction is rolled back, nothing is stored. The caller needs read access to the target (else 404) and owner or manage on it (else 403); limits of delegation give 200 with allowed: false and denial_reason. text is in the caller's language (de or en, else de) with dates in the caller's time zone (07, 9.3). With resolve_i1 the preview is a dry run of the whole guided flow: every listed agent needs access.preview with the target action agent.billing_mode.set (owner, no step-up; an unknown or invisible agent gives 404), the agents are switched to organization before the grant, and text names each agent the request would switch.

Request body (required): application/json: GrantCreate

Request
{
  "subject_kind": "user",
  "subject_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "target_kind": "instance",
  "level": "read",
  "reason": "Support team works in this space"
}

Responses:

Status Description Content Headers
200 OK. application/json: GrantPreview Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "allowed": true,
  "effects": [
    {
      "principal": {
        "id": "0192f4a0-7b1c-733c-835c-6d67630008cd",
        "kind": "user",
        "handle": "sam",
        "display_name": "Sam"
      },
      "target_kind": "channel",
      "target_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "before_level": "none",
      "after_level": "trigger",
      "capabilities_added": []
    }
  ],
  "invariant_violations": [],
  "hints": [
    {
      "code": "read_horizon",
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "principal_id": "0192f4a0-7b1c-733c-835c-6d67630008cd",
      "channel_id": "0192f4a0-7b1c-7c2a-8e1d-41a6b2c3d4e5"
    }
  ],
  "text": "Sam gets the level \"Trigger\" in channel Marketing/Kampagnen until 2026-12-31.\nSam can then: read and write messages, create threads, trigger agent Texter.\nUpload files: no. Confirm approval cards: no.\nNote: Texter also reads Marketing/Intern. Sam may not read Marketing/Intern but can learn its contents through Texter.",
  "text_locale": "en"
}

getGrant

GET /grants/{grant_id}

Read a grant

Parameters:

Name In Type Required Description
grant_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Grant Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-727f-86bd-90fe7bdb3024",
  "subject_kind": "user",
  "subject_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "target_kind": "instance",
  "level": "read",
  "capabilities": [
    "approve_actions"
  ],
  "reason": "Support team works in this space",
  "granted_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "granted_at": "2026-10-10T09:30:00.000Z"
}

revokeGrant

POST /grants/{grant_id}/revoke

Revoke a grant

Parameters:

Name In Type Required Description
grant_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
200 OK. application/json: Grant Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-727f-86bd-90fe7bdb3024",
  "subject_kind": "user",
  "subject_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "target_kind": "instance",
  "level": "read",
  "capabilities": [
    "approve_actions"
  ],
  "reason": "Support team works in this space",
  "granted_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "granted_at": "2026-10-10T09:30:00.000Z"
}

explainSpaceAccess

GET /spaces/{space_id}/access

Who has access to a space

Every principal with access and the chain of sources (direct, group, inherited, operator, via agent, blocked by a guard rule). An entry only through an agent has level none; disabled principals are marked inactive (07, 9.1).

Parameters:

Name In Type Required Description
space_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: AccessExplanation Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "target_kind": "space",
  "target_id": "0192f4a0-7b1c-7fd5-831e-d4370e087874",
  "entries": [
    {
      "principal": {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "kind": "user",
        "handle": "alex",
        "display_name": "Alex"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ],
      "sources": [
        {
          "kind": "owner"
        }
      ]
    }
  ]
}

explainChannelAccess

GET /channels/{channel_id}/access

Who has access to a channel

Every principal with access and the chain of sources (direct, group, inherited, operator, direct-message participant, via agent, blocked by a guard rule). An entry only through an agent has level none; disabled principals are marked inactive (07, 9.1).

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: AccessExplanation Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "target_kind": "space",
  "target_id": "0192f4a0-7b1c-7fd5-831e-d4370e087874",
  "entries": [
    {
      "principal": {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "kind": "user",
        "handle": "alex",
        "display_name": "Alex"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ],
      "sources": [
        {
          "kind": "owner"
        }
      ]
    }
  ]
}

listPermissionHints

GET /access/hints

List the permission hints

The list "Permission hints" of 07 section 9.5, computed from the permission state that authorize uses: h1_read_horizon for every agent, person of its trigger set and channel of its read horizon the person cannot read (07 section 6), grant_to_disabled for grants whose subject is disabled, trigger_blocked for trigger grants whose triggering SR2 or SR3 blocks on every operated channel they reach, agent_personal for agents in mode personal with their trigger set. Ordered by kind in this order, then by agent, person and channel, by grant ID or by agent ID. Without space_id the instance (owners); with it the space (owner or manage), limited to its agents, channels and grants. A space the caller cannot read gives 404, readable without manage 403. Hints never name content; labels carries the names of the principals, groups, spaces and channels of the page.

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
space_id query Uuid no Only the hints of this space; without it the whole instance (owners only).
kind query PermissionHintKind no Only hints of this kind.

Responses:

Status Description Content Headers
200 OK. application/json: PermissionHintPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "kind": "h1_read_horizon",
      "agent_id": "0192f4a0-7b1c-7a11-8c2e-1d4e5f6a7b8c",
      "person_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bd",
      "space_id": "0192f4a0-7b1c-7fd5-831e-d4370e087874",
      "channel_id": "0192f4a0-7b1c-7c33-9e4f-2a3b4c5d6e7f"
    }
  ],
  "labels": {
    "principals": [
      {
        "id": "0192f4a0-7b1c-7a11-8c2e-1d4e5f6a7b8c",
        "kind": "agent",
        "handle": "texter",
        "display_name": "Texter"
      },
      {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bd",
        "kind": "user",
        "handle": "sam",
        "display_name": "Sam"
      }
    ],
    "groups": [],
    "spaces": [
      {
        "id": "0192f4a0-7b1c-7fd5-831e-d4370e087874",
        "name": "Marketing"
      }
    ],
    "channels": [
      {
        "id": "0192f4a0-7b1c-7c33-9e4f-2a3b4c5d6e7f",
        "space_id": "0192f4a0-7b1c-7fd5-831e-d4370e087874",
        "name": "Intern"
      }
    ]
  }
}

listExpiringAccess

GET /access/expiring

List the access that expires soon

The list "Expiring soon" of 07 section 9.4: grants that are not revoked and memberships that are not removed (of groups that are not deleted) whose expires_at lies within authz.expiry_reminder_lead from now, and for owners the API tokens of agents and apps that are not revoked and expire within the same lead (never personal tokens, never a token value), ordered by expiry, then kind, then ID. "Extend" is a revocation plus a new grant with a new reason (07 section 2.5), a token is renewed by creating a new one and revoking the old one. Without space_id the instance (owners); with it the space (owner or manage): only grants on the space and its channels and memberships of groups that hold such a grant, no tokens. A space the caller cannot read gives 404, readable without manage 403.

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
space_id query Uuid no Only the access within this space; without it the whole instance (owners only).

Responses:

Status Description Content Headers
200 OK. application/json: ExpiringAccessPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "kind": "membership",
      "expires_at": "2026-10-12T09:30:00.000Z",
      "membership_id": "0192f4a0-7b1c-7b22-8d3e-4f5a6b7c8d9e",
      "group_id": "0192f4a0-7b1c-7e44-9a5b-6c7d8e9f0a1b",
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bd"
    }
  ],
  "labels": {
    "principals": [
      {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bd",
        "kind": "user",
        "handle": "sam",
        "display_name": "Sam"
      }
    ],
    "groups": [
      {
        "id": "0192f4a0-7b1c-7e44-9a5b-6c7d8e9f0a1b",
        "name": "Support"
      }
    ],
    "spaces": [],
    "channels": []
  }
}

Admin

Instance settings, branding, feature flags, keys, identity providers.

PUT /instance/branding/logo

Upload the logo

Owner with fresh step-up; nothing of the body is read before authorize allowed the action. Checks in this order (12 3.7): the first part is file (400 validation_failed); the declared type is JPEG, PNG or WebP (415 unsupported_media_type, with reason file_type_denied for a type in file.denied_mime_types); the part holds at most the smaller of file.max_upload_bytes and file.upload_part_bytes (413 payload_too_large) and at least one byte, and no further part follows (400 validation_failed); open sessions (429) and free space of the file system driver (503 unavailable with reason storage_full). The new file is linked at once and replaces the previous logo; it becomes deliverable later, after scan and metadata removal, and until then getBrandingLogo answers 404. Last write wins; no If-Match (06 8).

Request body (required): multipart/form-data: ImageUpload

Responses:

Status Description Content Headers
200 OK. application/json: Branding Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
415 UnsupportedMediaType: Problem codes: unsupported_media_type. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "product_name": "Team Chat",
  "accent_color": "loch",
  "version": 3
}

DELETE /instance/branding/logo

Remove the logo

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

getInstance

GET /instance

Instance settings for clients

Responses:

Status Description Content Headers
200 OK. application/json: InstanceInfo Correlation-Id, RateLimit, RateLimit-Policy, ETag
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "instance_id": "0192f4a0-7b1c-7db7-89b9-2fe4c48dcb3e",
  "branding": {
    "product_name": "Team Chat",
    "accent_color": "loch",
    "version": 3
  },
  "locale_default": "de",
  "spec_version": "1.0.0",
  "features": [
    {
      "key": "dm.enabled",
      "enabled": true
    }
  ],
  "limits": {
    "message_max_content_bytes": 262144,
    "message_max_attachments": 10,
    "file_max_upload_bytes": 104857600,
    "thread_title_max_chars": 200,
    "voice_max_duration_ms": 900000
  }
}

listInstanceSettings

GET /instance/settings

List all instance settings

Responses:

Status Description Content Headers
200 OK. application/json: InstanceSettingList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "key": "locale.default",
      "value": true,
      "version": 3,
      "updated_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

putInstanceSetting

PUT /instance/settings/{key}

Set an instance setting

Parameters:

Name In Type Required Description
key path string yes Pattern ^[a-z0-9_]+(\.[a-z0-9_]+)*$. Example: locale.default.
If-Match header string no Optional ETag; when given, a mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: InstanceSettingPut

Request
{
  "value": true
}

Responses:

Status Description Content Headers
200 OK. application/json: InstanceSetting Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "key": "locale.default",
  "value": true,
  "version": 3,
  "updated_at": "2026-10-10T09:30:00.000Z"
}

updateBranding

PUT /instance/branding

Change branding

Parameters:

Name In Type Required Description
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: BrandingUpdate

Request
{
  "product_name": "Team Chat",
  "accent_color": "loch"
}

Responses:

Status Description Content Headers
200 OK. application/json: Branding Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "product_name": "Team Chat",
  "accent_color": "loch",
  "version": 3
}

listFeatureFlags

GET /feature-flags

List feature flags

Responses:

Status Description Content Headers
200 OK. application/json: FeatureFlagList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "key": "voice.enabled",
      "kind": "option",
      "description": "Voice messages with transcription",
      "default": false,
      "module": "files",
      "orphaned": false,
      "enabled": true,
      "rollout": {},
      "version": 3
    }
  ]
}

putFeatureFlag

PUT /feature-flags/{key}

Set a feature flag

Parameters:

Name In Type Required Description
key path string yes Pattern ^[a-z0-9_]+(\.[a-z0-9_]+)*$. Example: locale.default.
If-Match header string no Optional ETag; when given, a mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: FeatureFlagPut

Request
{
  "enabled": true,
  "reason": "Pilot with the support team"
}

Responses:

Status Description Content Headers
200 OK. application/json: FeatureFlag Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "key": "voice.enabled",
  "kind": "option",
  "description": "Voice messages with transcription",
  "default": false,
  "module": "files",
  "orphaned": false,
  "enabled": true,
  "rollout": {},
  "version": 3
}

rotateSigningKey

POST /signing-keys/rotate

Rotate a server signing key

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: SigningKeyRotate

Request
{
  "purpose": "access_token",
  "mode": "scheduled",
  "reason": "Scheduled rotation"
}

Responses:

Status Description Content Headers
200 OK. application/json: SigningKeyRotation Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "purpose": "access_token",
  "new_kid": "inv-2026-11",
  "previous_kid": "inv-2026-10",
  "previous_not_after": "2026-10-10T09:30:00.000Z"
}

listIdentityProviders

GET /identity-providers

List identity providers

Responses:

Status Description Content Headers
200 OK. application/json: IdentityProviderList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7e26-89e1-d4e246452fb8",
      "kind": "oidc",
      "name": "Company SSO",
      "config": {},
      "enabled": true,
      "allow_provisioning": false
    }
  ]
}

createIdentityProvider

POST /identity-providers

Add an identity provider

Adds an identity provider (08, 2.6). A trusted_header provider that would be enabled (the default) while the public listener is not bound to a loopback address is refused with 409 conflict, reason: trusted_header_requires_loopback and a hint naming server.listen_addr (08, 2.4 rule 1).

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: IdentityProviderCreate

Request
{
  "kind": "oidc",
  "name": "Company SSO",
  "config": {}
}

Responses:

Status Description Content Headers
201 Created. application/json: IdentityProvider Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7e26-89e1-d4e246452fb8",
  "kind": "oidc",
  "name": "Company SSO",
  "config": {},
  "enabled": true,
  "allow_provisioning": false
}

getIdentityProvider

GET /identity-providers/{provider_id}

Read an identity provider

Parameters:

Name In Type Required Description
provider_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: IdentityProvider Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7e26-89e1-d4e246452fb8",
  "kind": "oidc",
  "name": "Company SSO",
  "config": {},
  "enabled": true,
  "allow_provisioning": false
}

deleteIdentityProvider

DELETE /identity-providers/{provider_id}

Remove an identity provider

Fails with conflict while identities are linked; disable it instead.

Parameters:

Name In Type Required Description
provider_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

updateIdentityProvider

PATCH /identity-providers/{provider_id}

Change an identity provider

Changes an identity provider; absent members stay. Setting enabled to true on a trusted_header provider while the public listener is not bound to a loopback address is refused with 409 conflict, reason: trusted_header_requires_loopback and a hint naming server.listen_addr (08, 2.4 rule 1). Disabling a provider ends the sessions of its identities (08, 3.3).

Parameters:

Name In Type Required Description
provider_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: IdentityProviderUpdate

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: IdentityProvider Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7e26-89e1-d4e246452fb8",
  "kind": "oidc",
  "name": "Company SSO",
  "config": {},
  "enabled": true,
  "allow_provisioning": false
}

Spaces

Spaces and their default operator.

listSpaces

GET /spaces

List visible spaces

Responses:

Status Description Content Headers
200 OK. application/json: SpaceViewList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "space": {
        "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
        "name": "Support",
        "sort_key": "a0",
        "version": 3,
        "created_at": "2026-10-10T09:30:00.000Z"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ]
    }
  ]
}

createSpace

POST /spaces

Create a space

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: SpaceCreate

Request
{
  "name": "Research",
  "icon": "flask",
  "color": "heather"
}

Responses:

Status Description Content Headers
201 Created. application/json: Space Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
  "name": "Support",
  "icon": "headset",
  "color": "moss",
  "sort_key": "a0",
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}

getSpace

GET /spaces/{space_id}

Read a space

Parameters:

Name In Type Required Description
space_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: SpaceView Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "space": {
    "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "name": "Support",
    "icon": "headset",
    "color": "moss",
    "sort_key": "a0",
    "version": 3,
    "created_at": "2026-10-10T09:30:00.000Z"
  },
  "level": "read",
  "capabilities": [
    "approve_actions"
  ]
}

updateSpace

PATCH /spaces/{space_id}

Change name, icon or color

Parameters:

Name In Type Required Description
space_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: SpaceUpdate

Request
{
  "name": "Research"
}

Responses:

Status Description Content Headers
200 OK. application/json: Space Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
  "name": "Support",
  "icon": "headset",
  "color": "moss",
  "sort_key": "a0",
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}

moveSpace

POST /spaces/{space_id}/move

Change the global position of a space

Parameters:

Name In Type Required Description
space_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: MovePosition

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: Space Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
  "name": "Support",
  "icon": "headset",
  "color": "moss",
  "sort_key": "a0",
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}

archiveSpace

POST /spaces/{space_id}/archive

Archive a space

Final; there is no unarchive. Every channel of the space becomes read-only for everyone, owners included; reading stays for those who could read before. Archiving is a permission change with access.changed; archived spaces leave listSpaces (07, 4.5).

Parameters:

Name In Type Required Description
space_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
200 OK. application/json: Space Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
  "name": "Support",
  "icon": "headset",
  "color": "moss",
  "sort_key": "a0",
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}

setSpaceOperator

PUT /spaces/{space_id}/operator

Set the default operator of a space

Optional resolve_i1 runs the guided flow (05 rule 1.6, 10 section 11): the listed agents are authorized with agent.billing_mode.set and switched to organization first, in the same transaction as the change; I1 is checked before the commit, and either both parts commit or none.

Parameters:

Name In Type Required Description
space_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: OperatorSet

Request
{
  "mode": "inherit",
  "reason": "Support agent takes over"
}

Responses:

Status Description Content Headers
200 OK. application/json: Space Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
  "name": "Support",
  "icon": "headset",
  "color": "moss",
  "sort_key": "a0",
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}

Channels

Channels, behavior, operator, project binding, tags, templates, direct messages.

listSpaceChannels

GET /spaces/{space_id}/channels

List visible channels of a space

Parameters:

Name In Type Required Description
space_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: ChannelViewList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "channel": {
        "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
        "kind": "text",
        "name": "tickets",
        "topic": "Customer tickets",
        "sort_key": "a1",
        "read_only": false,
        "operator": {
          "mode": "inherit"
        },
        "version": 3,
        "settings_version": 1,
        "created_at": "2026-10-10T09:30:00.000Z"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ]
    }
  ]
}

createChannel

POST /spaces/{space_id}/channels

Create a channel

Parameters:

Name In Type Required Description
space_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ChannelCreate

Request
{
  "kind": "text",
  "name": "tickets"
}

Responses:

Status Description Content Headers
201 Created. application/json: Channel Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "text",
  "name": "tickets",
  "topic": "Customer tickets",
  "sort_key": "a1",
  "read_only": false,
  "operator": {
    "mode": "inherit"
  },
  "version": 3,
  "settings_version": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

getChannel

GET /channels/{channel_id}

Read a channel

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: ChannelView Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "channel": {
    "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "kind": "text",
    "name": "tickets",
    "topic": "Customer tickets",
    "sort_key": "a1",
    "read_only": false,
    "operator": {
      "mode": "inherit"
    },
    "version": 3,
    "settings_version": 1,
    "created_at": "2026-10-10T09:30:00.000Z"
  },
  "level": "read",
  "capabilities": [
    "approve_actions"
  ]
}

updateChannel

PATCH /channels/{channel_id}

Change name or topic

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ChannelUpdate

Request
{
  "name": "tickets"
}

Responses:

Status Description Content Headers
200 OK. application/json: Channel Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "text",
  "name": "tickets",
  "topic": "Customer tickets",
  "sort_key": "a1",
  "read_only": false,
  "operator": {
    "mode": "inherit"
  },
  "version": 3,
  "settings_version": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

moveChannel

POST /channels/{channel_id}/move

Change the position of a channel in its space

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: MovePosition

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: Channel Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "text",
  "name": "tickets",
  "topic": "Customer tickets",
  "sort_key": "a1",
  "read_only": false,
  "operator": {
    "mode": "inherit"
  },
  "version": 3,
  "settings_version": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

archiveChannel

POST /channels/{channel_id}/archive

Archive a channel

Final; there is no unarchive. The channel becomes read-only for everyone, owners included (403 channel_read_only with reason: channel_archived); reading stays for those who could read before. Archiving is a permission change with access.changed; archived channels leave listSpaceChannels (07, 4.5).

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
200 OK. application/json: Channel Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "text",
  "name": "tickets",
  "topic": "Customer tickets",
  "sort_key": "a1",
  "read_only": false,
  "operator": {
    "mode": "inherit"
  },
  "version": 3,
  "settings_version": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

getChannelBehavior

GET /channels/{channel_id}/behavior

Read prompt, skills and mention rules

The ETag is settings_version.

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: ChannelBehavior Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "require_mention": false,
  "thread_require_mention": false,
  "free_response": false,
  "auto_thread": false,
  "allow_mentioned_agents": false,
  "history_backfill_limit": 20,
  "prompt": "Answer support tickets politely. Ask before closing a ticket.",
  "skills": [
    "support-triage"
  ],
  "settings_version": 1
}

putChannelBehavior

PUT /channels/{channel_id}/behavior

Change prompt, skills and mention rules

Parameters:

Name In Type Required Description
channel_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ChannelBehaviorPut

Request
{
  "require_mention": false,
  "thread_require_mention": false,
  "free_response": false,
  "auto_thread": false,
  "allow_mentioned_agents": false,
  "history_backfill_limit": 20,
  "prompt": "Answer support tickets politely.",
  "skills": [
    "support-triage"
  ]
}

Responses:

Status Description Content Headers
200 OK. application/json: ChannelBehavior Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "require_mention": false,
  "thread_require_mention": false,
  "free_response": false,
  "auto_thread": false,
  "allow_mentioned_agents": false,
  "history_backfill_limit": 20,
  "prompt": "Answer support tickets politely. Ask before closing a ticket.",
  "skills": [
    "support-triage"
  ],
  "settings_version": 1
}

setChannelOperator

PUT /channels/{channel_id}/operator

Set or inherit the operator of a channel

Optional resolve_i1 runs the guided flow (05 rule 1.6, 10 section 11): the listed agents are authorized with agent.billing_mode.set and switched to organization first, in the same transaction as the change; I1 is checked before the commit, and either both parts commit or none.

Parameters:

Name In Type Required Description
channel_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: OperatorSet

Request
{
  "mode": "inherit",
  "reason": "Support agent takes over"
}

Responses:

Status Description Content Headers
200 OK. application/json: Channel Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "text",
  "name": "tickets",
  "topic": "Customer tickets",
  "sort_key": "a1",
  "read_only": false,
  "operator": {
    "mode": "inherit"
  },
  "version": 3,
  "settings_version": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

setChannelReadOnly

PUT /channels/{channel_id}/read-only

Switch the read-only state of a channel

Write-protected for every principal including owners; only a running import writes (05, rule 1.8). Switching on cancels active runs in the channel. The imported channel of a source that is neither completed nor failed is controlled by its ownership list only: 409 conflict with reason import_lead_controls (use setImportLead).

Parameters:

Name In Type Required Description
channel_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ChannelReadOnlySet

Request
{
  "read_only": true,
  "reason": "Channel is mirrored from the old system"
}

Responses:

Status Description Content Headers
200 OK. application/json: Channel Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "text",
  "name": "tickets",
  "topic": "Customer tickets",
  "sort_key": "a1",
  "read_only": true,
  "operator": {
    "mode": "inherit"
  },
  "version": 4,
  "settings_version": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

putProjectBinding

PUT /channels/{channel_id}/project-binding

Bind a forum to a project

Parameters:

Name In Type Required Description
channel_id path Uuid yes
If-Match header string no Optional ETag; when given, a mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ProjectBindingPut

Request
{
  "workspace_ref": "website",
  "repository_url": "https://git.example.com/team/website",
  "default_branch": "main",
  "reason": "Website project moves to this forum"
}

Responses:

Status Description Content Headers
200 OK. application/json: ProjectBinding Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "workspace_ref": "website",
  "repository_url": "https://git.example.com/team/website",
  "default_branch": "main",
  "runner_config": {},
  "ready": false,
  "version": 3
}

deleteProjectBinding

DELETE /channels/{channel_id}/project-binding

Remove the project binding

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

listForumTags

GET /channels/{channel_id}/tags

List forum tags

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: ForumTagList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7f24-8f76-a5de0ed16c6f",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "name": "bug",
      "color": "rowan",
      "sort_key": "a0",
      "restricted": false
    }
  ]
}

createForumTag

POST /channels/{channel_id}/tags

Create a forum tag

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ForumTagCreate

Request
{
  "name": "bug",
  "color": "rowan"
}

Responses:

Status Description Content Headers
201 Created. application/json: ForumTag Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f24-8f76-a5de0ed16c6f",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "name": "bug",
  "color": "rowan",
  "sort_key": "a0",
  "restricted": false
}

deleteForumTag

DELETE /channels/{channel_id}/tags/{tag_id}

Delete a forum tag

Parameters:

Name In Type Required Description
channel_id path Uuid yes
tag_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

updateForumTag

PATCH /channels/{channel_id}/tags/{tag_id}

Change a forum tag

Parameters:

Name In Type Required Description
channel_id path Uuid yes
tag_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ForumTagUpdate

Request
{
  "name": "bug"
}

Responses:

Status Description Content Headers
200 OK. application/json: ForumTag Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f24-8f76-a5de0ed16c6f",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "name": "bug",
  "color": "rowan",
  "sort_key": "a0",
  "restricted": false
}

moveForumTag

POST /channels/{channel_id}/tags/{tag_id}/move

Change the position of a forum tag

Sets sort_key relative to sibling tags of the same forum; bumps the channel version and writes channel.updated like every tag change (03 forum_tags).

Parameters:

Name In Type Required Description
channel_id path Uuid yes
tag_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: MovePosition

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: ForumTag Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7f24-8f76-a5de0ed16c6f",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "name": "bug",
  "color": "rowan",
  "sort_key": "a0",
  "restricted": false
}

listTemplates

GET /channels/{channel_id}/templates

List own and channel templates

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: TemplateList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-777d-8541-d21a5b1c8fe4",
      "scope": "personal",
      "name": "Escalation",
      "content_md": "Please escalate this ticket to second level.",
      "version": 3
    }
  ]
}

createChannelTemplate

POST /channels/{channel_id}/templates

Create a channel template

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: TemplateCreate

Request
{
  "name": "Escalation",
  "content_md": "Please escalate this ticket to second level."
}

Responses:

Status Description Content Headers
201 Created. application/json: Template Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-777d-8541-d21a5b1c8fe4",
  "scope": "personal",
  "name": "Escalation",
  "content_md": "Please escalate this ticket to second level.",
  "version": 3
}

deleteTemplate

DELETE /templates/{template_id}

Delete a template

Parameters:

Name In Type Required Description
template_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

updateTemplate

PATCH /templates/{template_id}

Change a template

Parameters:

Name In Type Required Description
template_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: TemplateUpdate

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: Template Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-777d-8541-d21a5b1c8fe4",
  "scope": "personal",
  "name": "Escalation",
  "content_md": "Please escalate this ticket to second level.",
  "version": 3
}

listMyDms

GET /me/dms

List own direct message channels

Responses:

Status Description Content Headers
200 OK. application/json: ChannelViewList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "channel": {
        "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
        "kind": "text",
        "name": "tickets",
        "topic": "Customer tickets",
        "sort_key": "a1",
        "read_only": false,
        "operator": {
          "mode": "inherit"
        },
        "version": 3,
        "settings_version": 1,
        "created_at": "2026-10-10T09:30:00.000Z"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ]
    }
  ]
}

createDm

POST /dms

Open a direct message channel

Returns the existing channel with 200 when the same participants already have one. 403 feature_disabled when dm.enabled is off.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: DmCreate

Request
{
  "participant_ids": [
    "0192f4a0-7b1c-7324-80b6-deddeed437e3"
  ]
}

Responses:

Status Description Content Headers
201 Created. application/json: Channel Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "text",
  "name": "tickets",
  "topic": "Customer tickets",
  "sort_key": "a1",
  "read_only": false,
  "operator": {
    "mode": "inherit"
  },
  "version": 3,
  "settings_version": 1,
  "created_at": "2026-10-10T09:30:00.000Z"
}

leaveDm

POST /channels/{channel_id}/leave

Leave a direct message channel

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Threads

Threads, titles, done state, moving, tags, agent sessions.

listChannelThreads

GET /channels/{channel_id}/threads

List threads or forum posts of a channel

Parameters:

Name In Type Required Description
channel_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
state query ThreadState no Filter by state.
tag_id query Uuid no Only threads with this tag.
sort query ForumSort no Sort order, newest first.

Responses:

Status Description Content Headers
200 OK. application/json: ThreadPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "thread",
      "title": "Invoice export fails",
      "title_source": "auto",
      "state": "open",
      "last_message_seq": 5301,
      "last_activity_at": "2026-10-10T09:30:00.000Z",
      "message_count": 1,
      "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3,
      "tag_ids": [
        "0192f4a0-7b1c-712d-8017-1dad64203598"
      ]
    }
  ]
}

createThread

POST /channels/{channel_id}/threads

Create a forum post or a thread from a message

A first_message uses its client_msg_id for idempotency; without it, send Idempotency-Key. A first_message with kind = voice follows the rules of createMessage (pointers with the prefix /first_message); a voice file whose upload or scan has not ended answers 409 file_not_ready, a blocked or failed file 409 file_blocked, and neither thread nor message is stored.

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ThreadCreate

Request
{
  "title": "Invoice export fails"
}

Responses:

Status Description Content Headers
201 Created. application/json: ThreadCreated Correlation-Id, RateLimit, RateLimit-Policy
200 Replay: the thread created by an earlier request with the same first_message.client_msg_id or Idempotency-Key. application/json: ThreadCreated Correlation-Id, RateLimit, RateLimit-Policy, Idempotent-Replay
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "thread": {
    "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "kind": "thread",
    "title": "Invoice export fails",
    "title_source": "auto",
    "state": "open",
    "last_message_seq": 5301,
    "last_activity_at": "2026-10-10T09:30:00.000Z",
    "message_count": 1,
    "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "created_at": "2026-10-10T09:30:00.000Z",
    "version": 3,
    "tag_ids": [
      "0192f4a0-7b1c-712d-8017-1dad64203598"
    ]
  }
}
Response
{
  "thread": {
    "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "kind": "thread",
    "title": "Invoice export fails",
    "title_source": "auto",
    "state": "open",
    "last_message_seq": 5301,
    "last_activity_at": "2026-10-10T09:30:00.000Z",
    "message_count": 1,
    "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "created_at": "2026-10-10T09:30:00.000Z",
    "version": 3,
    "tag_ids": [
      "0192f4a0-7b1c-712d-8017-1dad64203598"
    ]
  }
}

getThread

GET /threads/{thread_id}

Read a thread

Parameters:

Name In Type Required Description
thread_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Thread Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "thread",
  "title": "Invoice export fails",
  "title_source": "auto",
  "state": "open",
  "last_message_seq": 5301,
  "last_activity_at": "2026-10-10T09:30:00.000Z",
  "message_count": 1,
  "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3,
  "tag_ids": [
    "0192f4a0-7b1c-712d-8017-1dad64203598"
  ]
}

setThreadTitle

PUT /threads/{thread_id}/title

Set the title

Every principal except the thread's operator agent sets title_source = manual. The operator agent may only replace an auto title, which stays auto; on a manual title it gets 409 title_manual.

Parameters:

Name In Type Required Description
thread_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ThreadTitlePut

Request
{
  "title": "Invoice export fails for March"
}

Responses:

Status Description Content Headers
200 OK. application/json: Thread Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "thread",
  "title": "Invoice export fails",
  "title_source": "auto",
  "state": "open",
  "last_message_seq": 5301,
  "last_activity_at": "2026-10-10T09:30:00.000Z",
  "message_count": 1,
  "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3,
  "tag_ids": [
    "0192f4a0-7b1c-712d-8017-1dad64203598"
  ]
}

closeThread

POST /threads/{thread_id}/close

Mark a thread as done

Parameters:

Name In Type Required Description
thread_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
200 OK. application/json: Thread Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "thread",
  "title": "Invoice export fails",
  "title_source": "auto",
  "state": "open",
  "last_message_seq": 5301,
  "last_activity_at": "2026-10-10T09:30:00.000Z",
  "message_count": 1,
  "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3,
  "tag_ids": [
    "0192f4a0-7b1c-712d-8017-1dad64203598"
  ]
}

reopenThread

POST /threads/{thread_id}/reopen

Reopen a thread

Parameters:

Name In Type Required Description
thread_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
200 OK. application/json: Thread Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "thread",
  "title": "Invoice export fails",
  "title_source": "auto",
  "state": "open",
  "last_message_seq": 5301,
  "last_activity_at": "2026-10-10T09:30:00.000Z",
  "message_count": 1,
  "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3,
  "tag_ids": [
    "0192f4a0-7b1c-712d-8017-1dad64203598"
  ]
}

moveThread

POST /threads/{thread_id}/move

Move a thread to another channel

Only to channels with the same effective operator; otherwise operator_mismatch.

Parameters:

Name In Type Required Description
thread_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ThreadMove

Request
{
  "target_channel_id": "0192f4a0-7b1c-77d1-8cf4-a695a7985d2f",
  "reason": "Belongs to billing"
}

Responses:

Status Description Content Headers
200 OK. application/json: Thread Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-77d1-8cf4-a695a7985d2f",
  "kind": "thread",
  "title": "Invoice export fails",
  "title_source": "auto",
  "state": "open",
  "last_message_seq": 5301,
  "last_activity_at": "2026-10-10T09:30:00.000Z",
  "message_count": 1,
  "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3,
  "moved_at": "2026-10-10T09:30:00.000Z",
  "tag_ids": []
}

setThreadTags

PUT /threads/{thread_id}/tags

Set forum tags of a thread

Parameters:

Name In Type Required Description
thread_id path Uuid yes
If-Match header string no Optional ETag; when given, a mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ThreadTagsPut

Request
{
  "tag_ids": [
    "0192f4a0-7b1c-712d-8017-1dad64203598"
  ]
}

Responses:

Status Description Content Headers
200 OK. application/json: Thread Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "kind": "thread",
  "title": "Invoice export fails",
  "title_source": "auto",
  "state": "open",
  "last_message_seq": 5301,
  "last_activity_at": "2026-10-10T09:30:00.000Z",
  "message_count": 1,
  "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3,
  "tag_ids": [
    "0192f4a0-7b1c-712d-8017-1dad64203598"
  ]
}

listAgentSessions

GET /threads/{thread_id}/agent-sessions

List current and earlier agent sessions

Parameters:

Name In Type Required Description
thread_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: AgentSessionList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-741b-8617-885056753dc0",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "external_session_ref": "sess-7f3a",
      "is_current": true,
      "started": true,
      "model": "model-large",
      "cost": {
        "amount_micros": 1250000,
        "currency": "USD",
        "is_estimate": true
      },
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3
    }
  ]
}

resetAgentSession

POST /threads/{thread_id}/agent-sessions/reset

Start a new agent session in the thread

Ends the current session of the thread with end_reason = reset and returns the ended row; the next run gets session_mode = new (09, 9.2). A run in progress keeps its session. Without a current session 409 conflict with reason no_current_session.

Parameters:

Name In Type Required Description
thread_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
201 Created. application/json: AgentSession Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-741b-8617-885056753dc0",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "external_session_ref": "sess-7f3a",
  "is_current": false,
  "started": true,
  "model": "model-large",
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "created_at": "2026-10-10T09:30:00.000Z",
  "ended_at": "2026-10-10T10:05:00.000Z",
  "end_reason": "reset",
  "version": 3
}

bindAgentSession

POST /threads/{thread_id}/agent-sessions/bind

Bind an existing external session

Compare-and-swap over the current session of the thread (09, 9.4); nothing changes on a 409. reason session_changed when expected_current_session_id does not name the current session, session_bound_elsewhere when the reference is current in another thread without take_over. With take_over the permission is checked in that thread too. The next run gets session_mode = bind.

Parameters:

Name In Type Required Description
thread_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: AgentSessionBind

Request
{
  "external_session_ref": "sess-7f3a"
}

Responses:

Status Description Content Headers
201 Created. application/json: AgentSession Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-741b-8617-885056753dc0",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "external_session_ref": "sess-7f3a",
  "is_current": true,
  "started": true,
  "model": "model-large",
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3
}

Messages

Messages, history, edits, reactions, pins.

listPins

GET /threads/{thread_id}/pins

List pinned messages

Parameters:

Name In Type Required Description
thread_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: PinList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "pinned_by": "0192f4a0-7b1c-72de-8fae-dfbd3e36ff9a",
      "pinned_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

listThreadMessages

GET /threads/{thread_id}/messages

Read thread history

At most one of before_seq, after_seq, around_seq. Without any, returns the newest page. Gaps in thread_seq mean missing data, tombstones fill deleted positions.

Parameters:

Name In Type Required Description
thread_id path Uuid yes
before_seq query integer (int64) no Messages with thread_seq below this value.
after_seq query integer (int64) no Messages with thread_seq above this value.
around_seq query integer (int64) no Messages centered on this value.
limit query PageLimit no Page size.

Responses:

Status Description Content Headers
200 OK. application/json: MessagePage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "thread_seq": 42,
      "author": {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "kind": "user",
        "handle": "alex",
        "display_name": "Alex"
      },
      "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
      "origin": "human",
      "kind": "text",
      "content_md": "@support-agent the invoice export fails since this morning.",
      "content_format": 1,
      "silent": false,
      "attachments": [
        {
          "position": 1,
          "file": {
            "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
            "size_bytes": 48213,
            "mime_type": "image/png",
            "original_name": "screenshot.png",
            "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
            "purpose": "attachment",
            "upload_state": "complete",
            "scan_status": "clean",
            "transcript_status": "none",
            "thumbnails": [
              {
                "variant": "small",
                "mime_type": "image/jpeg",
                "width": 320,
                "height": 180
              }
            ],
            "created_at": "2026-10-10T09:30:00.000Z"
          }
        }
      ],
      "mention_ids": [
        "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
      ],
      "reactions": [
        {
          "emoji": "👍",
          "count": 3
        }
      ],
      "pinned": false,
      "components": [
        {
          "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
          "custom_id": "approve-refund",
          "type": "button",
          "definition": {},
          "position": 1,
          "single_use": true,
          "restricted_to": "any",
          "state": "active",
          "version": 3
        }
      ],
      "version": 3,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "has_more_before": false,
  "has_more_after": false
}

createMessage

POST /threads/{thread_id}/messages

Send a message

Idempotent by (author, client_msg_id): a repeat with the same body returns the original with 200 and Idempotent-Replay: true; with a different body 422 idempotency_key_reuse. Sending into a closed thread reopens it. Agent invocation and follow-ups are evaluated after storing; denial sets trigger_state = failed with trigger_state_reason. When the message triggers an agent while one of its attachments is not final (scan or check still running), the agent invocation waits until all attachments are final or until file.invocation_hold_max has passed; trigger_state stays received meanwhile. A voice message (kind = voice, 12 8.1) needs one ready audio attachment: a file whose upload or scan has not ended answers 409 file_not_ready, a blocked or failed file 409 file_blocked, and nothing is stored. A voice message that triggers an agent without a transcription path gets trigger_state = failed with voice_unsupported (09, 13); with the server transcript (voice.transcription_mode = service) the invocation waits until the transcript is done or failed, at most voice.transcript_hold_max.

Parameters:

Name In Type Required Description
thread_id path Uuid yes

Request body (required): application/json: MessageCreate

Request
{
  "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
  "content_md": "@support-agent the invoice export fails since this morning."
}

Responses:

Status Description Content Headers
201 Created. application/json: Message Correlation-Id, RateLimit, RateLimit-Policy
200 Replay: the original created by an earlier request with the same client_msg_id. application/json: Message Correlation-Id, RateLimit, RateLimit-Policy, Idempotent-Replay
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "thread_seq": 42,
  "author": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
  "origin": "human",
  "kind": "text",
  "content_md": "@support-agent the invoice export fails since this morning.",
  "content_format": 1,
  "silent": false,
  "attachments": [
    {
      "position": 1,
      "file": {
        "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
        "size_bytes": 48213,
        "mime_type": "image/png",
        "original_name": "screenshot.png",
        "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "purpose": "attachment",
        "upload_state": "complete",
        "scan_status": "clean",
        "transcript_status": "none",
        "thumbnails": [
          {
            "variant": "small",
            "mime_type": "image/jpeg",
            "width": 320,
            "height": 180
          }
        ],
        "created_at": "2026-10-10T09:30:00.000Z"
      }
    }
  ],
  "mention_ids": [
    "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
  ],
  "reactions": [
    {
      "emoji": "👍",
      "count": 3
    }
  ],
  "pinned": false,
  "components": [
    {
      "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
      "custom_id": "approve-refund",
      "type": "button",
      "definition": {},
      "position": 1,
      "single_use": true,
      "restricted_to": "any",
      "state": "active",
      "version": 3
    }
  ],
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}
Response
{
  "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "thread_seq": 42,
  "author": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
  "origin": "human",
  "kind": "text",
  "content_md": "@support-agent the invoice export fails since this morning.",
  "content_format": 1,
  "silent": false,
  "attachments": [
    {
      "position": 1,
      "file": {
        "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
        "size_bytes": 48213,
        "mime_type": "image/png",
        "original_name": "screenshot.png",
        "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "purpose": "attachment",
        "upload_state": "complete",
        "scan_status": "clean",
        "transcript_status": "none",
        "thumbnails": [
          {
            "variant": "small",
            "mime_type": "image/jpeg",
            "width": 320,
            "height": 180
          }
        ],
        "created_at": "2026-10-10T09:30:00.000Z"
      }
    }
  ],
  "mention_ids": [
    "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
  ],
  "reactions": [
    {
      "emoji": "👍",
      "count": 3
    }
  ],
  "pinned": false,
  "components": [
    {
      "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
      "custom_id": "approve-refund",
      "type": "button",
      "definition": {},
      "position": 1,
      "single_use": true,
      "restricted_to": "any",
      "state": "active",
      "version": 3
    }
  ],
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}

getMessage

GET /messages/{message_id}

Read a message

Parameters:

Name In Type Required Description
message_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Message Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "thread_seq": 42,
  "author": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
  "origin": "human",
  "kind": "text",
  "content_md": "@support-agent the invoice export fails since this morning.",
  "content_format": 1,
  "silent": false,
  "attachments": [
    {
      "position": 1,
      "file": {
        "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
        "size_bytes": 48213,
        "mime_type": "image/png",
        "original_name": "screenshot.png",
        "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "purpose": "attachment",
        "upload_state": "complete",
        "scan_status": "clean",
        "transcript_status": "none",
        "thumbnails": [
          {
            "variant": "small",
            "mime_type": "image/jpeg",
            "width": 320,
            "height": 180
          }
        ],
        "created_at": "2026-10-10T09:30:00.000Z"
      }
    }
  ],
  "mention_ids": [
    "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
  ],
  "reactions": [
    {
      "emoji": "👍",
      "count": 3
    }
  ],
  "pinned": false,
  "components": [
    {
      "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
      "custom_id": "approve-refund",
      "type": "button",
      "definition": {},
      "position": 1,
      "single_use": true,
      "restricted_to": "any",
      "state": "active",
      "version": 3
    }
  ],
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}

deleteMessage

DELETE /messages/{message_id}

Delete a message

Idempotent; an already deleted message also gives 204. Moderation of other people's messages needs manage.

Parameters:

Name In Type Required Description
message_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

updateMessage

PATCH /messages/{message_id}

Edit own message

If-Match carries the expected version. A deleted message gives 410 message_deleted.

Parameters:

Name In Type Required Description
message_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: MessageUpdate

Request
{
  "content_md": "@support-agent the invoice export fails since 08:00."
}

Responses:

Status Description Content Headers
200 OK. application/json: Message Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "thread_seq": 42,
  "author": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
  "origin": "human",
  "kind": "text",
  "content_md": "@support-agent the invoice export fails since this morning.",
  "content_format": 1,
  "silent": false,
  "attachments": [
    {
      "position": 1,
      "file": {
        "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
        "size_bytes": 48213,
        "mime_type": "image/png",
        "original_name": "screenshot.png",
        "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "purpose": "attachment",
        "upload_state": "complete",
        "scan_status": "clean",
        "transcript_status": "none",
        "thumbnails": [
          {
            "variant": "small",
            "mime_type": "image/jpeg",
            "width": 320,
            "height": 180
          }
        ],
        "created_at": "2026-10-10T09:30:00.000Z"
      }
    }
  ],
  "mention_ids": [
    "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
  ],
  "reactions": [
    {
      "emoji": "👍",
      "count": 3
    }
  ],
  "pinned": false,
  "components": [
    {
      "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
      "custom_id": "approve-refund",
      "type": "button",
      "definition": {},
      "position": 1,
      "single_use": true,
      "restricted_to": "any",
      "state": "active",
      "version": 3
    }
  ],
  "version": 3,
  "created_at": "2026-10-10T09:30:00.000Z"
}

listMessageRevisions

GET /messages/{message_id}/revisions

Read earlier versions

Parameters:

Name In Type Required Description
message_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: MessageRevisionList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "revision": 1,
      "content_md": "@support-agent the invoice export fails.",
      "edited_by": "0192f4a0-7b1c-72e5-8bdc-9774dd9ce26f",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

listReactions

GET /messages/{message_id}/reactions

List who reacted

Parameters:

Name In Type Required Description
message_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
emoji query string no Only this emoji.

Responses:

Status Description Content Headers
200 OK. application/json: ReactionPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "emoji": "👍",
      "principal": {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "kind": "user",
        "handle": "alex",
        "display_name": "Alex"
      },
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

addReaction

PUT /messages/{message_id}/reactions/{emoji}

Add own reaction

Parameters:

Name In Type Required Description
message_id path Uuid yes
emoji path string yes Example: %F0%9F%91%8D.

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

removeReaction

DELETE /messages/{message_id}/reactions/{emoji}

Remove own reaction

Parameters:

Name In Type Required Description
message_id path Uuid yes
emoji path string yes Example: %F0%9F%91%8D.

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

pinMessage

PUT /messages/{message_id}/pin

Pin a message

Parameters:

Name In Type Required Description
message_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

unpinMessage

DELETE /messages/{message_id}/pin

Unpin a message

Parameters:

Name In Type Required Description
message_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Interactions

Buttons, selects and forms on messages.

createInteraction

POST /components/{component_id}/interactions

Use a button, select or form

Single-use components accept exactly one interaction; later ones get 409 component_used. Idempotent by (principal, client_interaction_id).

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: interaction.create
  • x-rate-limit-class: rl.interaction
  • x-idempotency-exempt: client_id

Parameters:

Name In Type Required Description
component_id path Uuid yes

Request body (required): application/json: InteractionCreate

Request
{
  "client_interaction_id": "0192f4a0-7b1c-704d-8f46-22a420803f92"
}

Responses:

Status Description Content Headers
201 Created. application/json: Interaction Correlation-Id, RateLimit, RateLimit-Policy
200 Replay: the original created by an earlier request with the same client_interaction_id. application/json: Interaction Correlation-Id, RateLimit, RateLimit-Policy, Idempotent-Replay
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-77f5-8fe4-151103a7b8b5",
  "component_id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
  "custom_id": "approve-refund",
  "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "principal_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "client_interaction_id": "0192f4a0-7b1c-704d-8f46-22a420803f92",
  "values": {},
  "state": "received",
  "created_at": "2026-10-10T09:30:00.000Z"
}
Response
{
  "id": "0192f4a0-7b1c-77f5-8fe4-151103a7b8b5",
  "component_id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
  "custom_id": "approve-refund",
  "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "principal_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "client_interaction_id": "0192f4a0-7b1c-704d-8f46-22a420803f92",
  "values": {},
  "state": "received",
  "created_at": "2026-10-10T09:30:00.000Z"
}

updateComponent

PATCH /components/{component_id}

Disable or change an own component

Parameters:

Name In Type Required Description
component_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ComponentUpdate

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: Component Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
  "custom_id": "approve-refund",
  "type": "button",
  "definition": {},
  "position": 1,
  "single_use": true,
  "restricted_to": "any",
  "state": "active",
  "version": 3
}

Files

Upload sessions, downloads, thumbnails, transcripts.

createUpload

POST /channels/{channel_id}/uploads

Start an upload

Checks in this order (12, 3.1): size against file.max_upload_bytes (413 payload_too_large), quota file.quota_bytes_per_principal (409 conflict with reason quota_exceeded), open sessions (429), free space of the file system driver (503 unavailable with reason storage_full). A denied type answers 415 unsupported_media_type with reason file_type_denied.

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: UploadCreate

Request
{
  "name": "screenshot.png",
  "size_bytes": 48213,
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "declared_mime_type": "image/png"
}

Responses:

Status Description Content Headers
201 Created. application/json: UploadSession Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
415 UnsupportedMediaType: Problem codes: unsupported_media_type. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "file_id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
  "mode": "direct",
  "part_size_bytes": 1,
  "parts": [
    {
      "part_number": 1,
      "url": "/api/v1/uploads/0192f4a0-7b1c-7000-8a00-000000000501/parts/1",
      "headers": [
        {
          "name": "Content-Type",
          "value": "application/octet-stream"
        }
      ]
    }
  ],
  "expires_at": "2026-10-10T09:30:00.000Z"
}

uploadPart

PUT /uploads/{file_id}/parts/{part_number}

Upload one part in direct mode

Parts can be sent in parallel and in any order (12, 3.2). The same part number with the same Content-Digest answers 200 without new work; with another digest 409 conflict with reason part_conflict. Wrong length or digest: 400 validation_failed with errors[].code part_digest_mismatch, nothing is stored. An expired session answers 410 gone.

Parameters:

Name In Type Required Description
file_id path Uuid yes
part_number path integer yes Minimum 1.
Content-Digest header string yes RFC 9530 digest of the part with the member sha-256, e.g. sha-256=:<base64>:; other members are ignored.

Request body (required): application/octet-stream: string (binary)

Responses:

Status Description Content Headers
200 OK. application/json: UploadPartResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "part_number": 1,
  "etag": "\"3858f62230ac3c915f300c664312c11f\""
}

completeUpload

POST /uploads/{file_id}/complete

Finish an upload

Closes the session and queues the job files.scan, which checks size and SHA-256, detects the MIME type and runs the malware scan. The file is downloadable after scan_status is clean or skipped. parts is checked against the confirmed parts: a duplicate or out-of-range number gives 400, another etag 409 conflict with reason part_conflict. A completed session answers 200 with the file again. Missing parts answer 409 conflict with reason upload_incomplete; an expired session answers 410 gone (12, 3.4 and 3.6).

Parameters:

Name In Type Required Description
file_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: UploadComplete

Request
{
  "parts": [
    {
      "part_number": 1,
      "etag": "\"3858f62230ac3c915f300c664312c11f\""
    }
  ]
}

Responses:

Status Description Content Headers
200 OK. application/json: File Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "size_bytes": 48213,
  "mime_type": "image/png",
  "original_name": "screenshot.png",
  "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "purpose": "attachment",
  "upload_state": "complete",
  "scan_status": "clean",
  "transcript_status": "none",
  "thumbnails": [
    {
      "variant": "small",
      "mime_type": "image/jpeg",
      "width": 320,
      "height": 180
    }
  ],
  "created_at": "2026-10-10T09:30:00.000Z"
}

getUpload

GET /uploads/{file_id}

Read the state of an own upload

Confirmed parts of an own upload, so a client can resume after a network loss (12, 3.2). upload_state is pending for an open session without a confirmed part, uploading with at least one, complete once completed. An aborted or expired session answers 410 gone.

Parameters:

Name In Type Required Description
file_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: UploadState Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "file_id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
  "upload_state": "uploading",
  "part_size_bytes": 8388608,
  "completed_parts": [
    {
      "part_number": 1,
      "etag": "\"9b2cf535f27731c974343645a3985328\""
    }
  ],
  "expires_at": "2026-10-10T09:30:00.000Z"
}

abortUpload

DELETE /uploads/{file_id}

Abort an upload

Ends an open own session: its parts are deleted, the file becomes upload_state failed and file.updated goes to the uploader. An aborted or expired session answers 204 again; a completed one 409 invalid_state_transition.

Parameters:

Name In Type Required Description
file_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

getFile

GET /files/{file_id}

Read file metadata

The header ETag is the version of the transcript of the file, derived from its status, source, language and text (03 R-DM-48, 12 8.2); getTranscript sends the same value, and submitTranscript expects it in If-Match.

Parameters:

Name In Type Required Description
file_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: File Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "size_bytes": 48213,
  "mime_type": "image/png",
  "original_name": "screenshot.png",
  "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "purpose": "attachment",
  "upload_state": "complete",
  "scan_status": "clean",
  "transcript_status": "none",
  "thumbnails": [
    {
      "variant": "small",
      "mime_type": "image/jpeg",
      "width": 320,
      "height": 180
    }
  ],
  "created_at": "2026-10-10T09:30:00.000Z"
}

deleteFile

DELETE /files/{file_id}

Delete an unattached file

Deletes an own file that is not attached. A file the caller already deleted answers 204 as well; an unknown, foreign or purged file answers 404 not_found. An attached file answers 409 conflict with reason file_attached (delete the message instead); an avatar, logo or export file answers 409 conflict with reason purpose_not_deletable. The objects and the row of the file are removed within privacy.object_delete_delay.

Parameters:

Name In Type Required Description
file_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

downloadFile

GET /files/{file_id}/content

Download a file

Answers 200 with the bytes (supports Range); there are no presigned GET URLs (ADR 0048). Media players without DPoP use a ticket (createFileTicket) in the query parameter ticket instead of Authorization. 409 file_not_ready while the scan is pending, 409 file_blocked for blocked or failed files; without read access always 404 (12, 9.3). Exactly one byte range gives 206, several ranges are ignored (200 with the whole file), a range outside the file gives 416. Types outside the inline list of 12 9.3 (HTML, SVG, PDF and every other type) are sent as application/octet-stream with Content-Disposition: attachment, nosniff and the sandbox CSP. An Authorization header wins over a ticket parameter. Pass-through via the server only (ADR 0048).

Parameters:

Name In Type Required Description
file_id path Uuid yes
ticket query string no Fetch ticket of createFileTicket (security scheme fileTicket, 12 9.2). Accepted only by downloadFile and downloadThumbnail; ignored when the request carries Authorization. A bearer secret: never logged.
Range header string no One byte range (RFC 9110 section 14), for example bytes=0-1023, bytes=1024- or bytes=-500. Exactly one range gives 206; several ranges and invalid values are ignored (200); a range that starts at or after the end gives 416 (12, 9.3).
If-Range header string no Applies Range only when equal to the current strong ETag; any other value, an HTTP date included, gives the whole variant (200).

Responses:

Status Description Content Headers
200 The whole file (12, 9.3; ADR 0048). application/octet-stream: string (binary)
image/jpeg: string (binary)
image/png: string (binary)
image/gif: string (binary)
audio/mp4: string (binary)
audio/mpeg: string (binary)
video/mp4: string (binary)
Correlation-Id, RateLimit, RateLimit-Policy, Content-Disposition, Content-Security-Policy, Cross-Origin-Resource-Policy, Cache-Control, ETag, Repr-Digest, Accept-Ranges
206 Exactly one byte range of the file (12, 9.3; ADR 0048). application/octet-stream: string (binary)
image/jpeg: string (binary)
image/png: string (binary)
image/gif: string (binary)
audio/mp4: string (binary)
audio/mpeg: string (binary)
video/mp4: string (binary)
Correlation-Id, RateLimit, RateLimit-Policy, Content-Disposition, Content-Security-Policy, Cross-Origin-Resource-Policy, Cache-Control, ETag, Repr-Digest, Accept-Ranges, Content-Range
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 FileConflict: Problem codes: file_not_ready, file_blocked. application/problem+json: Problem Correlation-Id, Retry-After
416 RangeNotSatisfiable: Problem codes: range_not_satisfiable. application/problem+json: Problem Correlation-Id, Content-Range
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

downloadThumbnail

GET /files/{file_id}/thumbnails/{variant}

Download a thumbnail

Accepts a fetch ticket in the query parameter ticket like downloadFile (push preview image_url, ADR 0048). 409 file_not_ready or file_blocked as for downloadFile; a variant the file does not have gives 404. Thumbnails are always inline with their own type; range, headers and caching as for downloadFile (12, 9.3).

Parameters:

Name In Type Required Description
file_id path Uuid yes
variant path string yes Values: small, medium, large, poster.
ticket query string no Fetch ticket of createFileTicket (security scheme fileTicket, 12 9.2). Accepted only by downloadFile and downloadThumbnail; ignored when the request carries Authorization. A bearer secret: never logged.
Range header string no One byte range (RFC 9110 section 14), for example bytes=0-1023, bytes=1024- or bytes=-500. Exactly one range gives 206; several ranges and invalid values are ignored (200); a range that starts at or after the end gives 416 (12, 9.3).
If-Range header string no Applies Range only when equal to the current strong ETag; any other value, an HTTP date included, gives the whole variant (200).

Responses:

Status Description Content Headers
200 The whole thumbnail (12, 9.3; ADR 0048). image/jpeg: string (binary)
image/png: string (binary)
Correlation-Id, RateLimit, RateLimit-Policy, Content-Disposition, Content-Security-Policy, Cross-Origin-Resource-Policy, Cache-Control, ETag, Repr-Digest, Accept-Ranges
206 Exactly one byte range of the thumbnail (12, 9.3; ADR 0048). image/jpeg: string (binary)
image/png: string (binary)
Correlation-Id, RateLimit, RateLimit-Policy, Content-Disposition, Content-Security-Policy, Cross-Origin-Resource-Policy, Cache-Control, ETag, Repr-Digest, Accept-Ranges, Content-Range
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 FileConflict: Problem codes: file_not_ready, file_blocked. application/problem+json: Problem Correlation-Id, Retry-After
416 RangeNotSatisfiable: Problem codes: range_not_satisfiable. application/problem+json: Problem Correlation-Id, Content-Range
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

createFileTicket

POST /files/{file_id}/tickets

Create a short-lived fetch ticket

For media players and "open with" that cannot send a DPoP proof. Every fetch with the ticket checks signature, expiry, session and file.read again (12, 9.2). A ticket binds to the login session of the caller: a principal without a session (agent, app, API token) gets 403 forbidden with reason step_up_not_possible. No ticket is issued for a file that is not deliverable (409 file_not_ready or file_blocked), and a variant the file does not have gives 404. A repeated call mints a new ticket.

Parameters:

Name In Type Required Description
file_id path Uuid yes

Request body (required): application/json: FileTicketCreate

Request
{
  "variant": "original"
}

Responses:

Status Description Content Headers
201 Created. application/json: FileTicket Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 FileConflict: Problem codes: file_not_ready, file_blocked. application/problem+json: Problem Correlation-Id, Retry-After
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "url": "/api/v1/files/0192f4a0-7b1c-75c7-88f6-199cc394b56a/content?ticket=c2lnbmVk",
  "expires_at": "2026-10-10T09:30:00.000Z"
}

getTranscript

GET /files/{file_id}/transcript

Read the transcript of a voice message

409 file_not_ready or file_blocked as for downloadFile; without read access always 404 (12, 9.3). Normal authentication only, never a fetch ticket. text, language and source are present only with status done. The header ETag is the derived version of the transcript, the same value as in getFile and the If-Match of submitTranscript.

Parameters:

Name In Type Required Description
file_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Transcript Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 FileConflict: Problem codes: file_not_ready, file_blocked. application/problem+json: Problem Correlation-Id, Retry-After
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "file_id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
  "status": "done",
  "text": "Please call the customer back tomorrow morning.",
  "language": "en",
  "source": "agent"
}

requestTranscription

POST /files/{file_id}/transcribe

Request a transcript

403 feature_disabled when voice.enabled is off. Starts the server transcript in mode service of voice.transcription_mode (12, 8.2). An unknown or invisible file answers 404; another mode, or a file that is not a voice format, gives 409 conflict with reason transcription_unavailable; a file that is not ready gives 409 file_not_ready or file_blocked. A transcript in status none or failed goes to pending and a new job starts; in status pending or done nothing changes. The answer is the current Transcript; the result arrives through file.updated.

Parameters:

Name In Type Required Description
file_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
202 Accepted; processing continues asynchronously. application/json: Transcript Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "file_id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
  "status": "pending"
}

Full-text search filtered by permissions.

GET /search

Full-text search

Results are filtered by message.read, thread.read and file.read inside the query; counts are not returned. Page size search.page_size_default, at most search.page_size_max (14, 4.7).

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
q query string yes Query in web search syntax: words, "phrases", or, -word. Min length 1.
type query string no Result type; default messages (14, 11). Values: messages, threads, files. Default: messages.
sort query string no Order of the hits (14, 4.5). Values: relevance, newest. Default: relevance.
space_id query array of Uuid no Only channels of these spaces, intersected with the visible ones.
channel_id query array of Uuid no Only these channels, intersected with the visible ones.
thread_id query Uuid no Restrict to a thread.
author_id query Uuid no Author of the message or uploader of the file.
agent_id query Uuid no Threads operated by this agent.
after query Timestamp no Created at or after.
before query Timestamp no Created before.
has_file query boolean no Only messages with at least one attachment.
thread_state query ThreadState no Only open or closed threads.
tag_id query array of Uuid no Forum tags of the thread.

Responses:

Status Description Content Headers
200 OK. application/json: SearchHitPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "kind": "message",
      "score": 1.5,
      "thread_title": "Invoice export fails",
      "channel_name": "tickets",
      "space_name": "Support",
      "segments": [
        {
          "text": "the ",
          "match": false
        },
        {
          "text": "invoice",
          "match": true
        },
        {
          "text": " export fails",
          "match": false
        }
      ]
    }
  ],
  "candidates_capped": false
}

searchThreadTitles

GET /search/thread-titles

Prefix search over thread titles

For the quick switcher (14, 4.9): words shorter than search.prefix_min_chars are dropped; same access filter as /search, newest activity first. Page size search.page_size_default, at most search.page_size_max.

Parameters:

Name In Type Required Description
limit query PageLimit no
q query string yes Typed prefix text. Min length 1.

Responses:

Status Description Content Headers
200 OK. application/json: ThreadTitleHitList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "title": "Invoice export fails",
      "last_activity_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

Sync

Snapshot and catch-up over REST.

getSnapshot

GET /sync/snapshot

Load a snapshot

Responses:

Status Description Content Headers
200 OK. application/json: Snapshot Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "head_seq": 5300,
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "permission_version": 418,
  "principal": {
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "kind": "user",
    "handle": "alex",
    "display_name": "Alex"
  },
  "is_owner": false,
  "spaces": [
    {
      "space": {
        "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
        "name": "Support",
        "sort_key": "a0",
        "version": 3,
        "created_at": "2026-10-10T09:30:00.000Z"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ]
    }
  ],
  "channels": [
    {
      "channel": {
        "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
        "kind": "text",
        "name": "tickets",
        "topic": "Customer tickets",
        "sort_key": "a1",
        "read_only": false,
        "operator": {
          "mode": "inherit"
        },
        "version": 3,
        "settings_version": 1,
        "created_at": "2026-10-10T09:30:00.000Z"
      },
      "level": "read",
      "capabilities": [
        "approve_actions"
      ]
    }
  ],
  "sidebar": [
    {
      "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
      "collapsed": false,
      "sort_key": "a0V",
      "version": 3
    }
  ],
  "unread_threads": [
    {
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "unread_count": 1,
      "mention_count": 1,
      "last_message_seq": 5301,
      "last_read_seq": 5301
    }
  ],
  "active_runs": [
    {
      "id": "0192f4a0-7b1c-767f-8292-c1b14d7d40df",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
      "state": "queued",
      "state_reason": "user_cancelled",
      "version": 3,
      "billing_mode_expected": "personal",
      "status_line": "Reading the export logs",
      "summary": "Found the cause and proposed a fix",
      "cost": {
        "amount_micros": 1250000,
        "currency": "USD",
        "is_estimate": true
      },
      "step_count": 1,
      "queued_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "agents": [
    {
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "state": "unknown"
    }
  ],
  "settings": [
    {
      "key": "composer.enter_sends",
      "value": true,
      "version": 3
    }
  ],
  "drafts": [
    {
      "id": "0192f4a0-7b1c-7f2d-8106-461e390824dc",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "version": 3
    }
  ],
  "features": [
    {
      "key": "dm.enabled",
      "enabled": false
    }
  ]
}

listEvents

GET /events

Catch up on events after a sequence

Same filtering as the gateway. 410 resync_required with reason when catch-up is impossible.

Parameters:

Name In Type Required Description
after query integer (int64) yes Last processed seq. Minimum 0.
epoch query Uuid no Sync epoch stored with the cursor (04 section 7.5). A different epoch answers 410 resync_required with reason = epoch_changed. Absent only before the first catch-up; then cursor_ahead is the second net (R-SY-04).
limit query integer no At most sync.catchup_page_size. Minimum 1.

Responses:

Status Description Content Headers
200 OK. application/json: EventPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "events": [
    {
      "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
      "schema_version": 1,
      "occurred_at": "2026-10-10T09:30:00.000Z",
      "scope": {},
      "resource": {
        "kind": "message"
      },
      "type": "message.created",
      "payload": {
        "message": {
          "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
          "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
          "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
          "thread_seq": 42,
          "author": {
            "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
            "kind": "user",
            "handle": "alex",
            "display_name": "Alex"
          },
          "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
          "origin": "human",
          "kind": "text",
          "content_md": "@support-agent the invoice export fails since this morning.",
          "content_format": 1,
          "silent": false,
          "attachments": [
            {
              "position": 1,
              "file": {
                "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
                "size_bytes": 48213,
                "mime_type": "image/png",
                "original_name": "screenshot.png",
                "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
                "purpose": "attachment",
                "upload_state": "complete",
                "scan_status": "clean",
                "transcript_status": "none",
                "thumbnails": [],
                "created_at": "2026-10-10T09:30:00.000Z"
              }
            }
          ],
          "mention_ids": [
            "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
          ],
          "reactions": [
            {
              "emoji": "👍",
              "count": 3
            }
          ],
          "pinned": false,
          "components": [
            {
              "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
              "custom_id": "approve-refund",
              "type": "button",
              "definition": {},
              "position": 1,
              "single_use": true,
              "restricted_to": "any",
              "state": "active",
              "version": 3
            }
          ],
          "version": 3,
          "created_at": "2026-10-10T09:30:00.000Z"
        }
      }
    }
  ],
  "next_cursor": 1,
  "head_seq": 5301,
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60"
}

Preferences

Read state, drafts, settings, sidebar, notifications, quiet hours.

getMySidebar

GET /me/sidebar

Read own sidebar state

Responses:

Status Description Content Headers
200 OK. application/json: SidebarStateList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
      "collapsed": false,
      "sort_key": "a0V",
      "version": 3
    }
  ]
}

putMySidebarSpace

PUT /me/sidebar/spaces/{space_id}

Collapse or reorder a space for oneself

Parameters:

Name In Type Required Description
space_id path Uuid yes

Request body (required): application/json: SidebarStatePut

Request
{
  "collapsed": false
}

Responses:

Status Description Content Headers
200 OK. application/json: SidebarState Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
  "collapsed": false,
  "sort_key": "a0V",
  "version": 3
}

putReadState

PUT /threads/{thread_id}/read-state

Advance the read position

Parameters:

Name In Type Required Description
thread_id path Uuid yes

Request body (required): application/json: ReadStatePut

Request
{
  "last_read_seq": 42
}

Responses:

Status Description Content Headers
200 OK. application/json: ReadState Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "last_read_seq": 41,
  "mention_count": 1,
  "version": 3
}

markThreadUnread

POST /threads/{thread_id}/read-state/mark-unread

Move the read position back

Parameters:

Name In Type Required Description
thread_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ReadStatePut

Request
{
  "last_read_seq": 42
}

Responses:

Status Description Content Headers
200 OK. application/json: ReadState Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "last_read_seq": 41,
  "mention_count": 1,
  "version": 3
}

putThreadDraft

PUT /threads/{thread_id}/draft

Save the draft of a thread

Parameters:

Name In Type Required Description
thread_id path Uuid yes

Request body (required): application/json: DraftPut

Request
{
  "content_md": "Draft of a reply"
}

Responses:

Status Description Content Headers
200 OK. application/json: DraftPutResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "draft": {
    "id": "0192f4a0-7b1c-7ad4-8297-1c4f06dd683c",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "content_md": "Draft of a reply",
    "file_ids": [
      "0192f4a0-7b1c-746e-8bc6-de981880ca4c"
    ],
    "version": 3
  },
  "overwrote_newer": false
}

deleteThreadDraft

DELETE /threads/{thread_id}/draft

Delete the draft of a thread

Parameters:

Name In Type Required Description
thread_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

putChannelDraft

PUT /channels/{channel_id}/draft

Save the draft of a new forum post

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Request body (required): application/json: DraftPut

Request
{
  "content_md": "Draft of a reply"
}

Responses:

Status Description Content Headers
200 OK. application/json: DraftPutResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "draft": {
    "id": "0192f4a0-7b1c-7ad4-8297-1c4f06dd683c",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "content_md": "Draft of a reply",
    "file_ids": [
      "0192f4a0-7b1c-746e-8bc6-de981880ca4c"
    ],
    "version": 3
  },
  "overwrote_newer": false
}

deleteChannelDraft

DELETE /channels/{channel_id}/draft

Delete the draft of a new forum post

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

listMyReadStates

GET /me/read-states

List own read positions

Parameters:

Name In Type Required Description
channel_id query Uuid yes Only threads of this channel.

Responses:

Status Description Content Headers
200 OK. application/json: ReadStateList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "last_read_seq": 41,
      "mention_count": 1,
      "version": 3
    }
  ]
}

listMyDrafts

GET /me/drafts

List own drafts

Responses:

Status Description Content Headers
200 OK. application/json: DraftList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7ad4-8297-1c4f06dd683c",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "content_md": "Draft of a reply",
      "file_ids": [
        "0192f4a0-7b1c-746e-8bc6-de981880ca4c"
      ],
      "version": 3
    }
  ]
}

listMySettings

GET /me/settings

List own settings

Responses:

Status Description Content Headers
200 OK. application/json: UserSettingList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "key": "composer.enter_sends",
      "value": true,
      "version": 3
    }
  ]
}

putMySetting

PUT /me/settings/{key}

Set an own setting

Parameters:

Name In Type Required Description
key path string yes Pattern ^[a-z0-9_]+(\.[a-z0-9_]+)*$. Example: locale.default.

Request body (required): application/json: UserSettingPut

Request
{
  "value": true
}

Responses:

Status Description Content Headers
200 OK. application/json: UserSetting Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "key": "composer.enter_sends",
  "value": true,
  "version": 3
}

deleteMySetting

DELETE /me/settings/{key}

Reset an own setting to default

Parameters:

Name In Type Required Description
key path string yes Pattern ^[a-z0-9_]+(\.[a-z0-9_]+)*$. Example: locale.default.

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

listMyNotificationPreferences

GET /me/notification-preferences

List notification levels

The caller's own levels, ordered by target kind, then target id. Only targets the caller can still read are listed; rows on targets the caller lost stay stored and appear again when the right returns.

Responses:

Status Description Content Headers
200 OK. application/json: NotificationPreferenceList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "target_kind": "space",
      "target_id": "0192f4a0-7b1c-7fd5-831e-d4370e087874",
      "level": "all",
      "version": 3
    }
  ]
}

putNotificationPreference

PUT /me/notification-preferences/{target_kind}/{target_id}

Set the notification level of a target

Sets the caller's level on a space, channel or thread the caller can read, the main thread of a text channel included. An unknown target, an id of another kind and a target without read right give the same 404. An archived target (or a channel in an archived space) takes no new preference: 409 conflict with reason target_archived. muted_until is stored as given (whole microseconds), also when it has passed; a passed value has no effect. A write that changes nothing answers 200 without event and without a new version.

Parameters:

Name In Type Required Description
target_kind path string yes Values: space, channel, thread.
target_id path Uuid yes

Request body (required): application/json: NotificationPreferencePut

Request
{
  "level": "all"
}

Responses:

Status Description Content Headers
200 OK. application/json: NotificationPreference Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "target_kind": "space",
  "target_id": "0192f4a0-7b1c-7fd5-831e-d4370e087874",
  "level": "all",
  "version": 3
}

deleteNotificationPreference

DELETE /me/notification-preferences/{target_kind}/{target_id}

Inherit the notification level again

Removes the caller's level on the target, so it inherits again. Answers 204 also when no row is stored (then without event); deleting stays possible on an archived target. A later put starts again at version 1.

Parameters:

Name In Type Required Description
target_kind path string yes Values: space, channel, thread.
target_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

listMyQuietHours

GET /me/quiet-hours

List quiet hours

Responses:

Status Description Content Headers
200 OK. application/json: QuietHoursList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7c3e-88ef-5d4efd8f4f24",
      "weekdays": 31,
      "start_local": "22:00",
      "end_local": "07:00",
      "time_zone": "Europe/Berlin",
      "enabled": true,
      "version": 3
    }
  ]
}

createQuietHoursRule

POST /me/quiet-hours

Add a quiet hours rule

Adds a rule. time_zone must be an IANA zone name (400 validation_failed with errors[].code unknown_time_zone); absent means the person's time zone. Every write sends the complete list in quiet_hours.updated; a write that would make that list larger than sync.event_payload_max_bytes is refused with 400 validation_failed and errors[].code limit_reached.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: QuietHoursRuleInput

Request
{
  "weekdays": 31,
  "start_local": "22:00",
  "end_local": "07:00",
  "time_zone": "Europe/Berlin",
  "enabled": true
}

Responses:

Status Description Content Headers
201 Created. application/json: QuietHoursRule Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7c3e-88ef-5d4efd8f4f24",
  "weekdays": 31,
  "start_local": "22:00",
  "end_local": "07:00",
  "time_zone": "Europe/Berlin",
  "enabled": true,
  "version": 3
}

putQuietHoursRule

PUT /me/quiet-hours/{rule_id}

Change a quiet hours rule

Replaces the whole rule; an absent time_zone clears it (the rule then follows the person's time zone). Equal values answer 200 without event and without a new version. time_zone and the list size are checked as for createQuietHoursRule (unknown_time_zone, limit_reached).

Parameters:

Name In Type Required Description
rule_id path Uuid yes

Request body (required): application/json: QuietHoursRuleInput

Request
{
  "weekdays": 31,
  "start_local": "22:00",
  "end_local": "07:00",
  "time_zone": "Europe/Berlin",
  "enabled": true
}

Responses:

Status Description Content Headers
200 OK. application/json: QuietHoursRule Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7c3e-88ef-5d4efd8f4f24",
  "weekdays": 31,
  "start_local": "22:00",
  "end_local": "07:00",
  "time_zone": "Europe/Berlin",
  "enabled": true,
  "version": 3
}

deleteQuietHoursRule

DELETE /me/quiet-hours/{rule_id}

Delete a quiet hours rule

Parameters:

Name In Type Required Description
rule_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Agents

Agent administration and backend policy.

setAllAgentsBillingMode

PUT /instance/agent-billing-mode

Switch the backend policy of all agents

Request body (required): application/json: BillingModeSetAll

Request
{
  "billing_mode": "organization",
  "reason": "Switch all agents to the company key"
}

Responses:

Status Description Content Headers
200 OK. application/json: BillingModeSetAllResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "changed_agent_ids": [
    "0192f4a0-7b1c-7d65-8e06-d83d1842d15e"
  ]
}

listAgents

GET /agents

List visible agents

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: AgentPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "handle": "support-agent",
      "display_name": "Support Agent",
      "status": "active",
      "adapter_kind": "hermes",
      "tool_class": "chat",
      "description": "Answers support tickets",
      "billing_mode": "personal",
      "presence": {
        "state": "unknown"
      },
      "operator_config": {},
      "version": 3
    }
  ]
}

createAgent

POST /agents

Create an agent

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: AgentCreate

Request
{
  "handle": "support-agent",
  "display_name": "Support Agent",
  "adapter_kind": "hermes",
  "description": "Answers support tickets"
}

Responses:

Status Description Content Headers
201 Created. application/json: Agent Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "handle": "support-agent",
  "display_name": "Support Agent",
  "status": "active",
  "adapter_kind": "hermes",
  "tool_class": "chat",
  "description": "Answers support tickets",
  "billing_mode": "personal",
  "presence": {
    "state": "unknown",
    "runtime_version": "2.3.1"
  },
  "operator_config": {},
  "version": 3
}

getAgent

GET /agents/{agent_id}

Read an agent with reported state

Parameters:

Name In Type Required Description
agent_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Agent Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "handle": "support-agent",
  "display_name": "Support Agent",
  "status": "active",
  "adapter_kind": "hermes",
  "tool_class": "chat",
  "description": "Answers support tickets",
  "billing_mode": "personal",
  "presence": {
    "state": "unknown",
    "runtime_version": "2.3.1"
  },
  "operator_config": {},
  "version": 3
}

updateAgent

PATCH /agents/{agent_id}

Change an agent

Parameters:

Name In Type Required Description
agent_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: AgentUpdate

Request
{
  "display_name": "Support Agent"
}

Responses:

Status Description Content Headers
200 OK. application/json: Agent Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "handle": "support-agent",
  "display_name": "Support Agent",
  "status": "active",
  "adapter_kind": "hermes",
  "tool_class": "chat",
  "description": "Answers support tickets",
  "billing_mode": "personal",
  "presence": {
    "state": "unknown",
    "runtime_version": "2.3.1"
  },
  "operator_config": {},
  "version": 3
}

disableAgent

POST /agents/{agent_id}/disable

Disable an agent

Parameters:

Name In Type Required Description
agent_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
200 OK. application/json: Agent Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "handle": "support-agent",
  "display_name": "Support Agent",
  "status": "active",
  "adapter_kind": "hermes",
  "tool_class": "chat",
  "description": "Answers support tickets",
  "billing_mode": "personal",
  "presence": {
    "state": "unknown",
    "runtime_version": "2.3.1"
  },
  "operator_config": {},
  "version": 3
}

enableAgent

POST /agents/{agent_id}/enable

Enable an agent

Parameters:

Name In Type Required Description
agent_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
200 OK. application/json: Agent Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "handle": "support-agent",
  "display_name": "Support Agent",
  "status": "active",
  "adapter_kind": "hermes",
  "tool_class": "chat",
  "description": "Answers support tickets",
  "billing_mode": "personal",
  "presence": {
    "state": "unknown",
    "runtime_version": "2.3.1"
  },
  "operator_config": {},
  "version": 3
}

setAgentBillingMode

PUT /agents/{agent_id}/billing-mode

Switch the backend policy of an agent

Switching to personal requires credential_holder_id and fails with i1_violation if anyone else could trigger the agent.

Parameters:

Name In Type Required Description
agent_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: BillingModeSet

Request
{
  "billing_mode": "personal",
  "reason": "Team uses the agent now"
}

Responses:

Status Description Content Headers
200 OK. application/json: Agent Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "handle": "support-agent",
  "display_name": "Support Agent",
  "status": "active",
  "adapter_kind": "hermes",
  "tool_class": "chat",
  "description": "Answers support tickets",
  "billing_mode": "personal",
  "presence": {
    "state": "unknown",
    "runtime_version": "2.3.1"
  },
  "operator_config": {},
  "version": 3
}

setCredentialHolder

PUT /agents/{agent_id}/credential-holder

Change the credential holder

Parameters:

Name In Type Required Description
agent_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: CredentialHolderSet

Request
{
  "credential_holder_id": "0192f4a0-7b1c-7ae9-8d74-7494cd730bc3",
  "reason": "Handover to deputy"
}

Responses:

Status Description Content Headers
200 OK. application/json: Agent Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "handle": "support-agent",
  "display_name": "Support Agent",
  "status": "active",
  "adapter_kind": "hermes",
  "tool_class": "chat",
  "description": "Answers support tickets",
  "billing_mode": "personal",
  "presence": {
    "state": "unknown",
    "runtime_version": "2.3.1"
  },
  "operator_config": {},
  "version": 3
}

setAgentToolClass

PUT /agents/{agent_id}/tool-class

Set the tool class of an agent

Target tool class (chat < scoped < host, 07 2.11). authorize uses the higher of target and reported class; a guest run needs a matching tool class (SR2).

Parameters:

Name In Type Required Description
agent_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: ToolClassSet

Request
{
  "tool_class": "scoped",
  "reason": "Agent now works in a project checkout"
}

Responses:

Status Description Content Headers
200 OK. application/json: Agent Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "handle": "support-agent",
  "display_name": "Support Agent",
  "status": "active",
  "adapter_kind": "hermes",
  "tool_class": "scoped",
  "description": "Answers support tickets",
  "billing_mode": "organization",
  "presence": {
    "state": "unknown"
  },
  "operator_config": {},
  "version": 4
}

Agent runtime

Endpoints for agent adapters: heartbeat, consumer, config, run lifecycle.

reportAgentSession

POST /threads/{thread_id}/agent-sessions/report

Report the external session reference and model

The adapter reports the session of its own active run in the thread (09, 9.1 and 9.5). If-Match is the compare-and-swap over agent_sessions.version: absent means the run has no session row yet, and the report creates it; a row that exists needs its version, otherwise 412 version_conflict with current. 409 conflict with reason session_bound_elsewhere (the reference is current in another thread), session_changed (the thread got another current session) or session_not_bound (bind_failed without a started session row).

Parameters:

Name In Type Required Description
thread_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string no Optional ETag; when given, a mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: AgentSessionReport

Request
{
  "external_session_ref": "sess-7f3a",
  "model": "model-large"
}

Responses:

Status Description Content Headers
200 OK. application/json: AgentSession Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-741b-8617-885056753dc0",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "external_session_ref": "sess-7f3a",
  "is_current": true,
  "started": true,
  "model": "model-large",
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3
}

respondToInteraction

POST /interactions/{interaction_id}/respond

Acknowledge or answer an interaction

Parameters:

Name In Type Required Description
interaction_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: InteractionRespond

Request
{
  "state": "acknowledged"
}

Responses:

Status Description Content Headers
200 OK. application/json: Interaction Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-77f5-8fe4-151103a7b8b5",
  "component_id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
  "custom_id": "approve-refund",
  "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "principal_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "client_interaction_id": "0192f4a0-7b1c-704d-8f46-22a420803f92",
  "values": {},
  "state": "received",
  "created_at": "2026-10-10T09:30:00.000Z"
}

submitTranscript

PUT /files/{file_id}/transcript

Store a transcript created by the agent

Mode agent of voice.transcription_mode only (12, 8.2). Only the operator agent of the thread whose message the voice file is attached to, with read access, may store the transcript; a file the caller cannot read, an unattached file of another uploader and an unknown id answer the same 404, and a visible caller who is not that operator gets 403 forbidden. Another mode, or a file that is not a voice format, gives 409 conflict with reason transcription_unavailable; a file that is not ready gives 409 file_not_ready or file_blocked. If-Match carries the transcript ETag of getFile or getTranscript (derived from status, source, language and text, 03 R-DM-48); without it or with * 428 precondition_required, with another value 412 version_conflict with the current Transcript in current and its ETag. text may be empty, must not contain U+0000 (invalid) and is at most message.max_content_bytes UTF-8 bytes (too_long). The answer has status done and source agent and the new ETag; a later submit with that value replaces the transcript. No audit entry.

Parameters:

Name In Type Required Description
file_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: TranscriptSubmit

Request
{
  "text": "Please call the customer back tomorrow morning.",
  "language": "en"
}

Responses:

Status Description Content Headers
200 OK. application/json: Transcript Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "file_id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
  "status": "done",
  "text": "Please call the customer back tomorrow morning.",
  "language": "en",
  "source": "agent"
}

sendHeartbeat

POST /agents/me/heartbeat

Report state and actual billing mode

The adapter reports the whole state of its runtime (agent_heartbeat.v1, 09 section 4.8); the member agent of the gateway op heartbeat has the same effect. Only an agent may call it (agent-self); the body carries no agent id. The last heartbeat wins: an absent optional member means "not reported", except project_readiness, which is applied only when present and changed since the last list this server process applied (ApplyProjectReadiness of M2-03, in its own transaction).

The server validates every member and the closed keys of details itself, also the patterns of names, versions and codes; a violation answers 400 validation_failed with every field error; rate_limit carries only state and an optional resets_at (M6-14). A change of reported_billing_mode or reported_tool_class, also from or to "not reported", is stored at once and audited with action agent.heartbeat; the other fields are stored at most once per agent.heartbeat_persist_interval. The presence becomes offline once agent.presence_timeout passes without a heartbeat. The server compares the reported with the configured mode at each heartbeat and returns the warnings of AgentRuntimeStatus.warnings; the reported mode is evidence for display, warning, audit and alarm and never a permission (BR-05). interval_ms is sync.heartbeat_interval.

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: agent.heartbeat
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Request body (required): application/json: Heartbeat

Request
{
  "state": "online",
  "runtime_version": "2.3.1",
  "reported_billing_mode": "personal"
}

Responses:

Status Description Content Headers
200 OK. application/json: HeartbeatAck Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "presence": {
    "state": "online",
    "reported_billing_mode": "personal",
    "runtime_version": "2.3.1",
    "last_heartbeat_at": "2026-10-20T09:00:00.000Z",
    "billing_mode_matches": true
  },
  "interval_ms": 30000
}

getConsumerState

GET /agents/me/consumers/{consumer}

Read the cursor of a consumer

Parameters:

Name In Type Required Description
consumer path string yes Pattern ^[a-z0-9][a-z0-9_-]*$. Example: default.

Responses:

Status Description Content Headers
200 OK. application/json: ConsumerState Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "consumer": "default",
  "acked_seq": 5301,
  "head_seq": 5301
}

pollAgentEvents

GET /agents/me/consumers/{consumer}/events

Fetch events for a consumer without WebSocket

Delivers from acked_seq + 1. Invocation events carry a fresh invocation_token. Unacknowledged events are delivered again after agent.ack_timeout.

Parameters:

Name In Type Required Description
consumer path string yes Pattern ^[a-z0-9][a-z0-9_-]*$. Example: default.
limit query integer no At most agent.max_inflight_events. Minimum 1.

Responses:

Status Description Content Headers
200 OK. application/json: EventPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "events": [
    {
      "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
      "schema_version": 1,
      "occurred_at": "2026-10-10T09:30:00.000Z",
      "scope": {},
      "resource": {
        "kind": "message"
      },
      "type": "message.created",
      "payload": {
        "message": {
          "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
          "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
          "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
          "thread_seq": 42,
          "author": {
            "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
            "kind": "user",
            "handle": "alex",
            "display_name": "Alex"
          },
          "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
          "origin": "human",
          "kind": "text",
          "content_md": "@support-agent the invoice export fails since this morning.",
          "content_format": 1,
          "silent": false,
          "attachments": [
            {
              "position": 1,
              "file": {
                "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
                "size_bytes": 48213,
                "mime_type": "image/png",
                "original_name": "screenshot.png",
                "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
                "purpose": "attachment",
                "upload_state": "complete",
                "scan_status": "clean",
                "transcript_status": "none",
                "thumbnails": [],
                "created_at": "2026-10-10T09:30:00.000Z"
              }
            }
          ],
          "mention_ids": [
            "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
          ],
          "reactions": [
            {
              "emoji": "👍",
              "count": 3
            }
          ],
          "pinned": false,
          "components": [
            {
              "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
              "custom_id": "approve-refund",
              "type": "button",
              "definition": {},
              "position": 1,
              "single_use": true,
              "restricted_to": "any",
              "state": "active",
              "version": 3
            }
          ],
          "version": 3,
          "created_at": "2026-10-10T09:30:00.000Z"
        }
      }
    }
  ],
  "next_cursor": 1,
  "head_seq": 5301,
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60"
}

ackAgentEvents

POST /agents/me/consumers/{consumer}/ack

Acknowledge events up to a sequence

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: agent.events.consume
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Parameters:

Name In Type Required Description
consumer path string yes Pattern ^[a-z0-9][a-z0-9_-]*$. Example: default.

Request body (required): application/json: ConsumerAck

Request
{
  "seq": 5301
}

Responses:

Status Description Content Headers
200 OK. application/json: ConsumerState Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "consumer": "default",
  "acked_seq": 5301,
  "head_seq": 5301
}

listServedChannels

GET /agents/me/channels

List channels the agent serves

Responses:

Status Description Content Headers
200 OK. application/json: AgentChannelConfigList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "behavior": {
        "require_mention": false,
        "thread_require_mention": false,
        "free_response": false,
        "auto_thread": false,
        "allow_mentioned_agents": false,
        "history_backfill_limit": 20,
        "prompt": "Answer support tickets politely. Ask before closing a ticket.",
        "skills": [
          "support-triage"
        ],
        "settings_version": 1
      }
    }
  ]
}

getServedChannelConfig

GET /agents/me/channels/{channel_id}/config

Read prompt, skills and project binding of a served channel

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: AgentChannelConfig Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "behavior": {
    "require_mention": false,
    "thread_require_mention": false,
    "free_response": false,
    "auto_thread": false,
    "allow_mentioned_agents": false,
    "history_backfill_limit": 20,
    "prompt": "Answer support tickets politely. Ask before closing a ticket.",
    "skills": [
      "support-triage"
    ],
    "settings_version": 1
  }
}

getAgentTriggerers

GET /agents/me/triggerers

List who may trigger this agent

Principals with effective trigger on a channel the agent operates, with permission_version. The adapter keeps it as allow list and reloads on access.changed (09, 15).

Responses:

Status Description Content Headers
200 OK. application/json: AgentTriggerers Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "principal_ids": [
    "0192f4a0-7b1c-7f89-8d6b-6960453241bc"
  ],
  "permission_version": 418
}

patchRun

PATCH /runs/{run_id}

Apply a live-box patch

Same as gateway op run.update (one use case). Only the run's own agent patches, only while the run is queued, running or waiting_input. A path or op outside the allowed set of 09 section 5.3 (for example /state) gives 400 validation_failed with errors[].code patch_path_forbidden and the pointer of the op. An ended run gives 409 conflict with reason run_not_active, checked before the version. A wrong base_version gives 409 base_version_conflict with the current document in current, exactly as getRun answers it. Set semantics: add and replace set a member also when it is absent, remove of an absent member is a no-op, and one stored patch raises the version by one. A follow-up state moves forward only (queued to delivered or absorbed, delivered to absorbed); a backward change gives 409 invalid_state_transition.

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: run.update
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Parameters:

Name In Type Required Description
run_id path Uuid yes

Request body (required): application/json: RunPatch

Request
{
  "base_version": 7,
  "ops": [
    {
      "op": "replace",
      "path": "/steps/0192f4a0-7b1c-7000-8a00-0000000000a1/status",
      "value": "completed"
    }
  ]
}

Responses:

Status Description Content Headers
200 OK. application/json: RunPatchResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "version": 8
}

startRun

POST /runs/{run_id}/start

Start a queued run

Compare-and-swap queued -> running after checking the invocation token. Repeating the call with the same token after success returns 200 with Idempotent-Replay: true while the run is running; any other token gets 409 already_started. Once the run waits for input, the start token is consumed and gets 403 invocation_token_invalid with reason: superseded. A different billing_mode_used fails the run with billing_mode_mismatch; a tool_class_used above the tool_class of the token fails it with 409 tool_class_mismatch. A token error gives 403 invocation_token_invalid with reason expired (renew with renewInvocationToken, then start again), superseded (a newer delivery replaced it) or invalid (09 section 4.5).

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: run.start
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Parameters:

Name In Type Required Description
run_id path Uuid yes

Request body (required): application/json: RunStart

Request
{
  "invocation_token": "eyJhbGciOiJFZERTQSIsImtpZCI6Imludi0yMDI2LTEwIn0.e30.sig",
  "billing_mode_used": "personal",
  "tool_class_used": "scoped",
  "external_session_ref": "sess-7f3a",
  "model": "model-large"
}

Responses:

Status Description Content Headers
200 OK. A repeated start with the same token while the run is running answers the current run with Idempotent-Replay: true and changes nothing (06 section 7 point 5). application/json: Run Correlation-Id, Idempotent-Replay, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
  "state": "running",
  "version": 3,
  "billing_mode_expected": "personal",
  "model": "model-large",
  "status_line": "Reading the export logs",
  "metrics": {
    "context_pct": 37.5
  },
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "steps": {
    "0192f4a0-7b1c-7986-8350-06ee441b527a": {
      "id": "0192f4a0-7b1c-70f2-84b9-bdac58ce716b",
      "ordinal": 1,
      "kind": "tool_call",
      "name": "read_file",
      "title": "Reading export.log",
      "status": "pending",
      "started_at": "2026-10-10T09:30:00.000Z"
    }
  },
  "followups": {
    "0192f4a0-7b1c-77d2-8ef5-9f8e2e1db96b": {
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "state": "queued"
    }
  },
  "queued_at": "2026-10-10T09:30:00.000Z"
}

resumeRun

POST /runs/{run_id}/resume

Resume a run that waited for input

waiting_input -> running with the token of the interaction or follow-up delivery. The consumed start token (its jti equals runs.started_jti) gets 403 invocation_token_invalid with reason: superseded (09 section 4.5).

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: run.start
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Parameters:

Name In Type Required Description
run_id path Uuid yes

Request body (required): application/json: RunStart

Request
{
  "invocation_token": "eyJhbGciOiJFZERTQSIsImtpZCI6Imludi0yMDI2LTEwIn0.e30.sig",
  "billing_mode_used": "personal",
  "tool_class_used": "scoped",
  "external_session_ref": "sess-7f3a",
  "model": "model-large"
}

Responses:

Status Description Content Headers
200 OK. A repeated start with the same token while the run is running answers the current run with Idempotent-Replay: true and changes nothing (06 section 7 point 5). application/json: Run Correlation-Id, Idempotent-Replay, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
  "state": "running",
  "version": 3,
  "billing_mode_expected": "personal",
  "model": "model-large",
  "status_line": "Reading the export logs",
  "metrics": {
    "context_pct": 37.5
  },
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "steps": {
    "0192f4a0-7b1c-7986-8350-06ee441b527a": {
      "id": "0192f4a0-7b1c-70f2-84b9-bdac58ce716b",
      "ordinal": 1,
      "kind": "tool_call",
      "name": "read_file",
      "title": "Reading export.log",
      "status": "pending",
      "started_at": "2026-10-10T09:30:00.000Z"
    }
  },
  "followups": {
    "0192f4a0-7b1c-77d2-8ef5-9f8e2e1db96b": {
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "state": "queued"
    }
  },
  "queued_at": "2026-10-10T09:30:00.000Z"
}

renewInvocationToken

POST /runs/{run_id}/invocation-token

Get a fresh invocation token for an own waiting run

For a run in queued or waiting_input whose invocation token expired before the start (09 section 4.5.1). The body carries the current token; its expiry is not checked, but its signature, audience, run and jti are: the jti equals the current one (runs.invocation_jti) or the one the last renewal replaced (runs.renewed_from_jti, retry after a lost answer), and it is not consumed by a start (runs.started_jti is NULL or differs, SQL started_jti IS DISTINCT FROM jti). A retry with the replaced token issues a fresh token again; the run still starts at most once. The server repeats every check it runs before a delivery (agent.invoke for the triggering person with current permissions, I2, SR2, SR3); on failure the run becomes failed and the answer is 403 agent_invocation_denied. A replaced or consumed token gets 403 invocation_token_invalid with reason: superseded; a run that already started gets 409 already_started.

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: run.token.renew
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Parameters:

Name In Type Required Description
run_id path Uuid yes

Request body (required): application/json: InvocationTokenRenew

Request
{
  "invocation_token": "eyJhbGciOiJFZERTQSIsImtpZCI6Imludi0yMDI2LTEwIn0.e30.sig"
}

Responses:

Status Description Content Headers
200 OK. application/json: InvocationTokenGrant Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "invocation_token": "eyJhbGciOiJFZERTQSIsImtpZCI6Imludi0yMDI2LTEwIn0.e30.signature",
  "expires_at": "2026-10-10T09:31:00.000Z"
}

awaitRunInput

POST /runs/{run_id}/await-input

Wait for input from a person

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: run.finish
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Parameters:

Name In Type Required Description
run_id path Uuid yes

Request body (required): application/json: RunAwaitInput

Request
{
  "status_line": "Waiting for approval"
}

Responses:

Status Description Content Headers
200 OK. application/json: Run Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
  "state": "queued",
  "version": 3,
  "billing_mode_expected": "personal",
  "model": "model-large",
  "status_line": "Reading the export logs",
  "metrics": {
    "context_pct": 37.5
  },
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "steps": {
    "0192f4a0-7b1c-7986-8350-06ee441b527a": {
      "id": "0192f4a0-7b1c-70f2-84b9-bdac58ce716b",
      "ordinal": 1,
      "kind": "tool_call",
      "name": "read_file",
      "title": "Reading export.log",
      "status": "pending",
      "started_at": "2026-10-10T09:30:00.000Z"
    }
  },
  "followups": {
    "0192f4a0-7b1c-77d2-8ef5-9f8e2e1db96b": {
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "state": "queued"
    }
  },
  "queued_at": "2026-10-10T09:30:00.000Z"
}

finishRun

POST /runs/{run_id}/finish

End a run

Repeating the same final state is idempotent and returns 200.

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: run.finish
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Parameters:

Name In Type Required Description
run_id path Uuid yes

Request body (required): application/json: RunFinish

Request
{
  "state": "completed",
  "reason": "adapter_error",
  "summary": "Found the cause and proposed a fix"
}

Responses:

Status Description Content Headers
200 OK. application/json: Run Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
  "state": "queued",
  "version": 3,
  "billing_mode_expected": "personal",
  "model": "model-large",
  "status_line": "Reading the export logs",
  "metrics": {
    "context_pct": 37.5
  },
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "steps": {
    "0192f4a0-7b1c-7986-8350-06ee441b527a": {
      "id": "0192f4a0-7b1c-70f2-84b9-bdac58ce716b",
      "ordinal": 1,
      "kind": "tool_call",
      "name": "read_file",
      "title": "Reading export.log",
      "status": "pending",
      "started_at": "2026-10-10T09:30:00.000Z"
    }
  },
  "followups": {
    "0192f4a0-7b1c-77d2-8ef5-9f8e2e1db96b": {
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "state": "queued"
    }
  },
  "queued_at": "2026-10-10T09:30:00.000Z"
}

answerAutocomplete

POST /command-autocompletions/{request_id}/answer

Answer an autocomplete request

The owner of the command answers an open request of command.autocomplete_requested; the first valid answer goes back to the person. 404 for an unknown or forgotten request, 410 gone after the wait ended, 204 without effect for an answer after the first one. 400 validation_failed for more than command.autocomplete_max_choices choices (too_many_items), an empty name or value (too_short) or a name or value that is no display text (invalid_utf8, control_character, bidi_control); the request stays open.

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: command.autocomplete.respond
  • x-rate-limit-class: rl.agent_runtime
  • x-idempotency-exempt: agent_runtime

Parameters:

Name In Type Required Description
request_id path Uuid yes

Request body (required): application/json: AutocompleteAnswer

Request
{
  "choices": [
    {
      "name": "High priority",
      "value": "high"
    }
  ]
}

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Runs

Runs (live box) for people.

listThreadRuns

GET /threads/{thread_id}/runs

List runs of a thread

Parameters:

Name In Type Required Description
thread_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: RunSummaryPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-767f-8292-c1b14d7d40df",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
      "state": "queued",
      "state_reason": "user_cancelled",
      "version": 3,
      "billing_mode_expected": "personal",
      "status_line": "Reading the export logs",
      "summary": "Found the cause and proposed a fix",
      "cost": {
        "amount_micros": 1250000,
        "currency": "USD",
        "is_estimate": true
      },
      "step_count": 1,
      "queued_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

listActiveRuns

GET /runs

Running now

Runs in queued, running or waiting_input, filtered by run.read.

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
agent_id query Uuid no Only runs of this agent.

Responses:

Status Description Content Headers
200 OK. application/json: RunSummaryPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-767f-8292-c1b14d7d40df",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
      "state": "queued",
      "state_reason": "user_cancelled",
      "version": 3,
      "billing_mode_expected": "personal",
      "status_line": "Reading the export logs",
      "summary": "Found the cause and proposed a fix",
      "cost": {
        "amount_micros": 1250000,
        "currency": "USD",
        "is_estimate": true
      },
      "step_count": 1,
      "queued_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

getRun

GET /runs/{run_id}

Read the run document

Parameters:

Name In Type Required Description
run_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Run Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
  "state": "queued",
  "version": 3,
  "billing_mode_expected": "personal",
  "model": "model-large",
  "status_line": "Reading the export logs",
  "metrics": {
    "context_pct": 37.5
  },
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "steps": {
    "0192f4a0-7b1c-7986-8350-06ee441b527a": {
      "id": "0192f4a0-7b1c-70f2-84b9-bdac58ce716b",
      "ordinal": 1,
      "kind": "tool_call",
      "name": "read_file",
      "title": "Reading export.log",
      "status": "pending",
      "started_at": "2026-10-10T09:30:00.000Z"
    }
  },
  "followups": {
    "0192f4a0-7b1c-77d2-8ef5-9f8e2e1db96b": {
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "state": "queued"
    }
  },
  "queued_at": "2026-10-10T09:30:00.000Z"
}

listRunSteps

GET /runs/{run_id}/steps

List steps in order

Parameters:

Name In Type Required Description
run_id path Uuid yes
cursor query Cursor no Cursor from the previous page.
limit query PageLimit no Page size.

Responses:

Status Description Content Headers
200 OK. application/json: RunStepPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-70f2-84b9-bdac58ce716b",
      "ordinal": 1,
      "kind": "tool_call",
      "name": "read_file",
      "title": "Reading export.log",
      "status": "pending",
      "started_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

getRunContext

GET /runs/{run_id}/context

Load the context of an own active run

Agent-self, only for own active runs in queued, running or waiting_input (09, 4.6): the adapter reads it before startRun. An unknown run, a run the agent cannot see and an own run that is no longer active answer the same 404; another agent gets 403 forbidden with reason not_self, a person or an app reason subject_kind_not_allowed. The server computes role and trust of every element at the time of the request from the current rights; trigger_message is never cut and never counted, the other parts are cut per element at agent.context_message_max_bytes and in sum at agent.context_max_bytes from old to new.

Parameters:

Name In Type Required Description
run_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: RunContext Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "run_id": "0192f4a0-7b1c-7c4b-8f0e-4d2a6b1c9e30",
  "context_floor_seq": 0,
  "trigger_message": {
    "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
    "thread_seq": 42,
    "created_at": "2026-10-10T09:30:00.000Z",
    "author": {
      "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "kind": "user",
      "handle": "alex",
      "display_name": "Alex"
    },
    "role": "user",
    "origin": "human",
    "kind": "text",
    "channel_id": "0192f4a0-7b1c-7a1e-9c2d-3b4a5c6d7e8f",
    "content_md": "@support-agent the invoice export fails since this morning.",
    "attachments": [],
    "trust": "trigger"
  },
  "thread_context": []
}

cancelRun

POST /runs/{run_id}/cancel

Cancel a run

Writes run.cancel_requested for the agent. Without confirmation within agent.cancel_grace the server cancels the run itself.

Parameters:

Name In Type Required Description
run_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: RunCancel

Request
{
  "reason": "Wrong ticket"
}

Responses:

Status Description Content Headers
202 Accepted; processing continues asynchronously. application/json: RunSummary Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-767f-8292-c1b14d7d40df",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
  "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
  "state": "queued",
  "state_reason": "user_cancelled",
  "version": 3,
  "billing_mode_expected": "personal",
  "status_line": "Reading the export logs",
  "summary": "Found the cause and proposed a fix",
  "cost": {
    "amount_micros": 1250000,
    "currency": "USD",
    "is_estimate": true
  },
  "step_count": 1,
  "queued_at": "2026-10-10T09:30:00.000Z"
}

Commands

Slash commands, autocomplete, invocation.

listChannelCommands

GET /channels/{channel_id}/commands

List commands usable in a channel

Lists the registered commands offered in the channel: those of the channel's effective operator first, then those of guest agents (only with allow_mentioned_agents) and of apps with write on the channel, an active installation and the scope commands:write, each group ordered by lower-case name, owner and ID. Per owner and name only the most specific scope appears (channel before space before instance). The built-in commands are not part of the list; the client shows them from its own list. A dm channel lists nothing.

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: CommandList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa",
      "owner_principal_id": "0192f4a0-7b1c-7176-8de0-ddf186d11091",
      "name": "escalate",
      "description": "Escalate the ticket to second level",
      "scope_kind": "instance",
      "options": [
        {
          "name": "ticket",
          "description": "Ticket number",
          "type": "string",
          "required": true
        }
      ],
      "required_level": "write",
      "control": false,
      "version": 3
    }
  ]
}

registerCommand

POST /commands

Register a command

Registers a command of the calling agent or app. A built-in name answers 409 conflict with reason: command_name_reserved; a name the owner already uses on the same scope target answers 409 conflict without a reason.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: CommandRegister

Request
{
  "name": "escalate",
  "description": "Escalate the ticket to second level"
}

Responses:

Status Description Content Headers
201 Created. application/json: Command Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa",
  "owner_principal_id": "0192f4a0-7b1c-7176-8de0-ddf186d11091",
  "name": "escalate",
  "description": "Escalate the ticket to second level",
  "scope_kind": "instance",
  "options": [
    {
      "name": "ticket",
      "description": "Ticket number",
      "type": "string",
      "required": true
    }
  ],
  "required_level": "write",
  "control": false,
  "version": 3
}

getCommand

GET /commands/{command_id}

Read a command

Parameters:

Name In Type Required Description
command_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Command Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa",
  "owner_principal_id": "0192f4a0-7b1c-7176-8de0-ddf186d11091",
  "name": "escalate",
  "description": "Escalate the ticket to second level",
  "scope_kind": "instance",
  "options": [
    {
      "name": "ticket",
      "description": "Ticket number",
      "type": "string",
      "required": true
    }
  ],
  "required_level": "write",
  "control": false,
  "version": 3
}

updateCommand

PUT /commands/{command_id}

Replace a command definition

Replaces the definition of a command of the caller. A built-in name answers 409 conflict with reason: command_name_reserved; a name the owner already uses on the same scope target answers 409 conflict without a reason. An identical definition answers the command unchanged.

Parameters:

Name In Type Required Description
command_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: CommandRegister

Request
{
  "name": "escalate",
  "description": "Escalate the ticket to second level"
}

Responses:

Status Description Content Headers
200 OK. application/json: Command Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa",
  "owner_principal_id": "0192f4a0-7b1c-7176-8de0-ddf186d11091",
  "name": "escalate",
  "description": "Escalate the ticket to second level",
  "scope_kind": "instance",
  "options": [
    {
      "name": "ticket",
      "description": "Ticket number",
      "type": "string",
      "required": true
    }
  ],
  "required_level": "write",
  "control": false,
  "version": 3
}

removeCommand

DELETE /commands/{command_id}

Remove a command

Parameters:

Name In Type Required Description
command_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

autocompleteCommand

POST /channels/{channel_id}/commands/{command_id}/autocomplete

Get suggestions for an option

Forwards the query to the command owner and waits up to command.autocomplete_timeout; returns no choices when the owner does not answer in time. Returns an empty list at once when an agent owner, or an app owner without delivery.interactions_url, has no live gateway connection, when the installation of the owning app stops being active after the check, and for an agent command in a forum channel without thread_id after the check (R-AZ-26). An app whose manifest declares delivery.interactions_url gets the query as a signed POST to that address and has app.interaction_timeout to answer, never beyond command.autocomplete_timeout: 200 with valid choices returns them, 202 keeps the request open for answerAutocomplete, any other answer returns an empty list at once (11, 9). A command of an agent is checked like agent.invoke without a run: a refusal is 403 agent_invocation_denied with reason (for example level_insufficient, agent_not_reachable, billing_mode_personal_not_holder, tool_class_owner_only, project_not_ready), a read-only or archived channel 403 channel_read_only. A command of an app is checked by its required_level and the reachability of the app (active installation, commands:write, write on the channel), never by the agent.invoke guard; a missing level is 403 agent_invocation_denied with reason, a read-only or archived channel 403 channel_read_only. An unknown, removed or not covered command, an app command whose app is not reachable, an unknown channel or a thread of another channel is 404. The query names an option with autocomplete (400 validation_failed with unknown_option, autocomplete_not_enabled or duplicate; too_long when the request does not fit sync.event_payload_max_bytes).

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: command.autocomplete
  • x-rate-limit-class: rl.trigger
  • x-idempotency-exempt: read_only

Parameters:

Name In Type Required Description
channel_id path Uuid yes
command_id path Uuid yes

Request body (required): application/json: AutocompleteQuery

Request
{
  "option": "ticket",
  "value": "47"
}

Responses:

Status Description Content Headers
200 OK. application/json: AutocompleteResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "choices": [
    {
      "name": "High priority",
      "value": "high"
    }
  ]
}

invokeCommand

POST /channels/{channel_id}/commands/{command_id}/invoke

Run a command

Parameters:

Name In Type Required Description
channel_id path Uuid yes
command_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: CommandInvoke

Request
{}

Responses:

Status Description Content Headers
202 Accepted; processing continues asynchronously. application/json: CommandInvocation Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "invocation_id": "0192f4a0-7b1c-712e-8ccb-17c85f8d11c9",
  "command_id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "accepted": true
}

Apps

Installed apps, manifests and scopes.

listApps

GET /apps

List installed apps

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: AppPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
      "slug": "ticket-sync",
      "display_name": "Ticket Sync",
      "manifest": {
        "schema_version": 1,
        "slug": "ticket-sync",
        "name": "Ticket Sync",
        "description": "Mirrors tickets of a help desk into a forum.",
        "publisher": "Example Ltd",
        "version": "1.2.0",
        "homepage_url": "https://apps.example.com/ticket-sync",
        "min_api_version": "0.2",
        "scopes": {
          "required": [
            "messages:write"
          ],
          "optional": [
            "messages:read",
            "events:subscribe"
          ]
        },
        "events": [
          "message.created"
        ],
        "delivery": {
          "mode": "webhook",
          "events_url": "https://apps.example.com/ticket-sync/events"
        },
        "data_egress": "Messages of the granted channels go to apps.example.com."
      },
      "manifest_version": "1.2.0",
      "installation": {
        "id": "0192f4a0-7b1c-78dc-8da2-d6c386222e8a",
        "granted_scopes": [
          "events:subscribe",
          "messages:read",
          "messages:write"
        ],
        "event_subscriptions": [
          "message.created"
        ],
        "state": "active",
        "installed_at": "2026-10-10T09:30:00.000Z"
      }
    }
  ]
}

installApp

POST /apps

Install an app from its manifest

Owner only with a fresh step-up. The manifest is checked against the schema (unknown members give 400 validation_failed with unknown_member) and the check rules of 11, 3.2 (400 validation_failed with the pointers under /manifest; 400 webhook_host_not_allowed when every failure is a delivery host outside webhook.allowed_hosts). granted_scopes holds every required and any optional scope of the manifest; event_subscriptions absent means none, each needs events:subscribe and the scope of the event. One transaction creates the app principal (handle = slug, display name = name), the app and its installation and raises the rights version; nothing is stored on a refusal. No token and no grant is created: grants come per target from createGrant, tokens from createToken. The same slug again is 409 conflict (use upgradeAppManifest); a slug whose apps are all uninstalled reinstalls with the same principal.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: AppInstall

Request
{
  "manifest": {
    "schema_version": 1,
    "slug": "ticket-sync",
    "name": "Ticket Sync",
    "description": "Mirrors tickets of a help desk into a forum.",
    "publisher": "Example Ltd",
    "version": "1.2.0",
    "homepage_url": "https://apps.example.com/ticket-sync",
    "min_api_version": "0.2",
    "scopes": {
      "required": [
        "messages:write"
      ],
      "optional": [
        "messages:read",
        "events:subscribe"
      ]
    },
    "events": [
      "message.created"
    ],
    "delivery": {
      "mode": "webhook",
      "events_url": "https://apps.example.com/ticket-sync/events"
    },
    "data_egress": "Messages of the granted channels go to apps.example.com."
  },
  "granted_scopes": [
    "events:subscribe",
    "messages:read",
    "messages:write"
  ],
  "event_subscriptions": [
    "message.created"
  ],
  "reason": "Sync tickets with the help desk"
}

Responses:

Status Description Content Headers
201 Created. application/json: App Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
  "slug": "ticket-sync",
  "display_name": "Ticket Sync",
  "manifest": {
    "schema_version": 1,
    "slug": "ticket-sync",
    "name": "Ticket Sync",
    "description": "Mirrors tickets of a help desk into a forum.",
    "publisher": "Example Ltd",
    "version": "1.2.0",
    "homepage_url": "https://apps.example.com/ticket-sync",
    "min_api_version": "0.2",
    "scopes": {
      "required": [
        "messages:write"
      ],
      "optional": [
        "messages:read",
        "events:subscribe"
      ]
    },
    "events": [
      "message.created"
    ],
    "delivery": {
      "mode": "webhook",
      "events_url": "https://apps.example.com/ticket-sync/events"
    },
    "data_egress": "Messages of the granted channels go to apps.example.com."
  },
  "manifest_version": "1.2.0",
  "installation": {
    "id": "0192f4a0-7b1c-78dc-8da2-d6c386222e8a",
    "granted_scopes": [
      "events:subscribe",
      "messages:read",
      "messages:write"
    ],
    "event_subscriptions": [
      "message.created"
    ],
    "state": "active",
    "installed_at": "2026-10-10T09:30:00.000Z"
  }
}

validateManifest

POST /app-manifests/validate

Validate a manifest without installing

Owner only. Schema violations give 400 validation_failed; the check rules of 11, 3.2 give 200 with valid false and every rule error, pointers relative to the manifest root. Nothing is stored and no audit entry is written.

Request body (required): application/json: AppManifest

Request
{
  "schema_version": 1,
  "slug": "ticket-sync",
  "name": "Ticket Sync",
  "description": "Mirrors tickets of a help desk into a forum.",
  "publisher": "Example Ltd",
  "version": "1.2.0",
  "homepage_url": "https://apps.example.com/ticket-sync",
  "min_api_version": "0.2",
  "scopes": {
    "required": [
      "messages:write"
    ],
    "optional": [
      "messages:read",
      "events:subscribe"
    ]
  },
  "events": [
    "message.created"
  ],
  "delivery": {
    "mode": "webhook",
    "events_url": "https://apps.example.com/ticket-sync/events"
  },
  "data_egress": "Messages of the granted channels go to apps.example.com."
}

Responses:

Status Description Content Headers
200 OK. application/json: ManifestValidation Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "valid": false,
  "errors": [
    {
      "pointer": "/delivery/events_url",
      "code": "webhook_host_not_allowed",
      "detail": "The host is not in webhook.allowed_hosts (R-DM-17, 11 section 3.2 rule 3)."
    }
  ]
}

getApp

GET /apps/{app_id}

Read an app

Parameters:

Name In Type Required Description
app_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: App Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
  "slug": "ticket-sync",
  "display_name": "Ticket Sync",
  "manifest": {
    "schema_version": 1,
    "slug": "ticket-sync",
    "name": "Ticket Sync",
    "description": "Mirrors tickets of a help desk into a forum.",
    "publisher": "Example Ltd",
    "version": "1.2.0",
    "homepage_url": "https://apps.example.com/ticket-sync",
    "min_api_version": "0.2",
    "scopes": {
      "required": [
        "messages:write"
      ],
      "optional": [
        "messages:read",
        "events:subscribe"
      ]
    },
    "events": [
      "message.created"
    ],
    "delivery": {
      "mode": "webhook",
      "events_url": "https://apps.example.com/ticket-sync/events"
    },
    "data_egress": "Messages of the granted channels go to apps.example.com."
  },
  "manifest_version": "1.2.0",
  "installation": {
    "id": "0192f4a0-7b1c-78dc-8da2-d6c386222e8a",
    "granted_scopes": [
      "events:subscribe",
      "messages:read",
      "messages:write"
    ],
    "event_subscriptions": [
      "message.created"
    ],
    "state": "active",
    "installed_at": "2026-10-10T09:30:00.000Z"
  }
}

upgradeAppManifest

PUT /apps/{app_id}/manifest

Install a new manifest version

Owner only with a fresh step-up (app.install). The new manifest has the same slug and passes the rules of installApp; changed content needs another version (400 at /manifest/version). The upgrade never adds a scope, an event or a grant: granted_scopes and event_subscriptions are subsets of the current ones (a new scope gives 400 at /granted_scopes/<i>; consent with setAppScopes), and event_subscriptions absent keeps the current ones the new manifest and scopes still allow. What the new manifest drops acts at once. New delivery hosts are confirmed by the upgrade itself and must be in webhook.allowed_hosts. An identical manifest with identical lists answers 200 without effect; an uninstalled app is 409 conflict.

Parameters:

Name In Type Required Description
app_id path Uuid yes

Request body (required): application/json: AppInstall

Request
{
  "manifest": {
    "schema_version": 1,
    "slug": "ticket-sync",
    "name": "Ticket Sync",
    "description": "Mirrors tickets of a help desk into a forum.",
    "publisher": "Example Ltd",
    "version": "1.2.0",
    "homepage_url": "https://apps.example.com/ticket-sync",
    "min_api_version": "0.2",
    "scopes": {
      "required": [
        "messages:write"
      ],
      "optional": [
        "messages:read",
        "events:subscribe"
      ]
    },
    "events": [
      "message.created"
    ],
    "delivery": {
      "mode": "webhook",
      "events_url": "https://apps.example.com/ticket-sync/events"
    },
    "data_egress": "Messages of the granted channels go to apps.example.com."
  },
  "granted_scopes": [
    "events:subscribe",
    "messages:read",
    "messages:write"
  ],
  "event_subscriptions": [
    "message.created"
  ],
  "reason": "Sync tickets with the help desk"
}

Responses:

Status Description Content Headers
200 OK. application/json: App Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
  "slug": "ticket-sync",
  "display_name": "Ticket Sync",
  "manifest": {
    "schema_version": 1,
    "slug": "ticket-sync",
    "name": "Ticket Sync",
    "description": "Mirrors tickets of a help desk into a forum.",
    "publisher": "Example Ltd",
    "version": "1.2.0",
    "homepage_url": "https://apps.example.com/ticket-sync",
    "min_api_version": "0.2",
    "scopes": {
      "required": [
        "messages:write"
      ],
      "optional": [
        "messages:read",
        "events:subscribe"
      ]
    },
    "events": [
      "message.created"
    ],
    "delivery": {
      "mode": "webhook",
      "events_url": "https://apps.example.com/ticket-sync/events"
    },
    "data_egress": "Messages of the granted channels go to apps.example.com."
  },
  "manifest_version": "1.2.0",
  "installation": {
    "id": "0192f4a0-7b1c-78dc-8da2-d6c386222e8a",
    "granted_scopes": [
      "events:subscribe",
      "messages:read",
      "messages:write"
    ],
    "event_subscriptions": [
      "message.created"
    ],
    "state": "active",
    "installed_at": "2026-10-10T09:30:00.000Z"
  }
}

setAppScopes

PUT /apps/{app_id}/scopes

Change granted scopes and subscriptions

Owner only with a fresh step-up; the consent for new scopes and events. granted_scopes is a subset of the scopes of the manifest; event_subscriptions absent keeps the current ones the new scopes still allow, present it replaces them (each needs events:subscribe and the scope of the event). A removed scope acts on the next request of every token; a newly granted scope needs a new token, because a token keeps the scopes it was created with. Equal lists answer 200 without effect; an uninstalled app is 409 conflict.

Parameters:

Name In Type Required Description
app_id path Uuid yes

Request body (required): application/json: AppScopesPut

Request
{
  "granted_scopes": [
    "events:subscribe",
    "messages:read",
    "messages:write"
  ],
  "event_subscriptions": [
    "message.created"
  ],
  "reason": "Mirror replies into the help desk"
}

Responses:

Status Description Content Headers
200 OK. application/json: App Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
  "slug": "ticket-sync",
  "display_name": "Ticket Sync",
  "manifest": {
    "schema_version": 1,
    "slug": "ticket-sync",
    "name": "Ticket Sync",
    "description": "Mirrors tickets of a help desk into a forum.",
    "publisher": "Example Ltd",
    "version": "1.2.0",
    "homepage_url": "https://apps.example.com/ticket-sync",
    "min_api_version": "0.2",
    "scopes": {
      "required": [
        "messages:write"
      ],
      "optional": [
        "messages:read",
        "events:subscribe"
      ]
    },
    "events": [
      "message.created"
    ],
    "delivery": {
      "mode": "webhook",
      "events_url": "https://apps.example.com/ticket-sync/events"
    },
    "data_egress": "Messages of the granted channels go to apps.example.com."
  },
  "manifest_version": "1.2.0",
  "installation": {
    "id": "0192f4a0-7b1c-78dc-8da2-d6c386222e8a",
    "granted_scopes": [
      "events:subscribe",
      "messages:read",
      "messages:write"
    ],
    "event_subscriptions": [
      "message.created"
    ],
    "state": "active",
    "installed_at": "2026-10-10T09:30:00.000Z"
  }
}

suspendApp

POST /apps/{app_id}/suspend

Suspend an app

Emergency stop without losing grants: tokens blocked, deliveries paused, commands hidden, components disabled (11, 6).

Parameters:

Name In Type Required Description
app_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

resumeApp

POST /apps/{app_id}/resume

Resume a suspended app

Parameters:

Name In Type Required Description
app_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

uninstallApp

POST /apps/{app_id}/uninstall

Uninstall an app

Parameters:

Name In Type Required Description
app_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Left the team"
}

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Webhooks

Outgoing webhook subscriptions and deliveries, incoming webhooks.

listIncomingWebhooks

GET /channels/{channel_id}/incoming-webhooks

List incoming webhooks of a channel

Parameters:

Name In Type Required Description
channel_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: IncomingWebhookList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-784b-80fa-070d5a412eea",
      "app_id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "name": "Monitoring alerts",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createIncomingWebhook

POST /channels/{channel_id}/incoming-webhooks

Create an incoming webhook

Parameters:

Name In Type Required Description
channel_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: IncomingWebhookCreate

Request
{
  "app_id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
  "name": "Monitoring alerts"
}

Responses:

Status Description Content Headers
201 Created. application/json: IncomingWebhookCreated Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "webhook": {
    "id": "0192f4a0-7b1c-784b-80fa-070d5a412eea",
    "app_id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "name": "Monitoring alerts",
    "created_at": "2026-10-10T09:30:00.000Z"
  },
  "url": "https://chat.example.com/api/v1/hooks/0192f4a0-7b1c-784b-80fa-070d5a412eea/bothy_whi_EXAMPLE000000000000000000000000000000000000_2WwD3e"
}

revokeIncomingWebhook

DELETE /incoming-webhooks/{webhook_id}

Revoke an incoming webhook

Parameters:

Name In Type Required Description
webhook_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

postIncomingWebhookWithBearer

POST /hooks/{webhook_id}

Post a message through an incoming webhook with the token in Authorization

The token of the incoming webhook is sent as Authorization: Bearer <token>; the path ends with the webhook ID. Use this variant where the sender can set a header, so the token never appears in a URL. Of the root security only bearerAuth applies here, with the token of the incoming webhook; any other scheme or credential counts as a wrong token (404).

The format is recognised per request from the body: a body with at least one Alertmanager member (version, groupKey, truncatedAlerts, status, receiver, groupLabels, commonLabels, commonAnnotations, externalURL, alerts) is the unchanged webhook payload of Prometheus Alertmanager and gives one message per notification; it must carry no native member (400 validation_failed, format_mixed). Every other body is native: Markdown in content_md with optional title, thread_id and client_msg_id. A format outside webhook_in.formats_enabled gives 400 validation_failed with format_disabled.

Order of checks (11 8.4): rl.webhook_in of the webhook (429), the token (404), the body up to webhook_in.max_body_bytes (413), the format (400), authorize of the app (404), then the message (201). An unknown or revoked webhook, a wrong or malformed token, a suspended or uninstalled app and every refusal of the app's rights give the same 404. A failed token check counts against rl.public_auth of the client IP.

The message has origin = app with the app as author, resolves no mentions and never triggers an agent. native with client_msg_id is idempotent: a repeat answers 200 with the original and Idempotent-Replay: true, other content with the same client_msg_id 422 idempotency_key_reuse. Senders inside the stack reach the same path on the internal listener.

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: webhook_in.post
  • x-rate-limit-class: rl.webhook_in
  • x-idempotency-exempt: client_id

Parameters:

Name In Type Required Description
webhook_id path Uuid yes

Request body (required): application/json: IncomingWebhookPost

native
{
  "content_md": "Disk usage above threshold on build host.",
  "title": "Disk alert",
  "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b"
}
alertmanager
{
  "version": "4",
  "groupKey": "{}:{alertname=\"DiskFull\"}",
  "truncatedAlerts": 0,
  "status": "firing",
  "receiver": "bothy-ops",
  "groupLabels": {
    "alertname": "DiskFull"
  },
  "commonLabels": {
    "alertname": "DiskFull",
    "severity": "warning"
  },
  "commonAnnotations": {
    "summary": "Disk usage above threshold."
  },
  "externalURL": "https://alertmanager.example.com",
  "alerts": [
    {
      "status": "firing",
      "labels": {
        "alertname": "DiskFull",
        "instance": "build.example.com",
        "severity": "warning"
      },
      "annotations": {
        "summary": "Disk usage above threshold."
      },
      "startsAt": "2026-10-10T09:30:00.000Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "generatorURL": "https://prometheus.example.com/graph",
      "fingerprint": "4a1f0c2b9d3e5f60"
    }
  ]
}

Responses:

Status Description Content Headers
201 Created. application/json: IncomingWebhookResult Correlation-Id, RateLimit, RateLimit-Policy
200 Replay: the original created by an earlier native request with the same client_msg_id. application/json: IncomingWebhookResult Correlation-Id, RateLimit, RateLimit-Policy, Idempotent-Replay
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
default
{
  "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}
default
{
  "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

postIncomingWebhook

POST /hooks/{webhook_id}/{token}

Post a message through an incoming webhook

The token is the last path segment; Authorization is ignored. Servers write the path only as its pattern /api/v1/hooks/{webhook_id}/{token} in logs, traces and Problem.instance, and reverse proxies must redact it (16 4.3).

The format is recognised per request from the body: a body with at least one Alertmanager member (version, groupKey, truncatedAlerts, status, receiver, groupLabels, commonLabels, commonAnnotations, externalURL, alerts) is the unchanged webhook payload of Prometheus Alertmanager and gives one message per notification; it must carry no native member (400 validation_failed, format_mixed). Every other body is native: Markdown in content_md with optional title, thread_id and client_msg_id. A format outside webhook_in.formats_enabled gives 400 validation_failed with format_disabled.

Order of checks (11 8.4): rl.webhook_in of the webhook (429), the token (404), the body up to webhook_in.max_body_bytes (413), the format (400), authorize of the app (404), then the message (201). An unknown or revoked webhook, a wrong or malformed token, a suspended or uninstalled app and every refusal of the app's rights give the same 404. A failed token check counts against rl.public_auth of the client IP.

The message has origin = app with the app as author, resolves no mentions and never triggers an agent. native with client_msg_id is idempotent: a repeat answers 200 with the original and Idempotent-Replay: true, other content with the same client_msg_id 422 idempotency_key_reuse. Senders inside the stack reach the same path on the internal listener.

  • Security: none
  • x-authz-action: webhook_in.post
  • x-rate-limit-class: rl.webhook_in
  • x-idempotency-exempt: client_id

Parameters:

Name In Type Required Description
webhook_id path Uuid yes
token path string yes Example: bothy_whi_EXAMPLE000000000000000000000000000000000000_2WwD3e.

Request body (required): application/json: IncomingWebhookPost

native
{
  "content_md": "Disk usage above threshold on build host.",
  "title": "Disk alert",
  "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b"
}
alertmanager
{
  "version": "4",
  "groupKey": "{}:{alertname=\"DiskFull\"}",
  "truncatedAlerts": 0,
  "status": "firing",
  "receiver": "bothy-ops",
  "groupLabels": {
    "alertname": "DiskFull"
  },
  "commonLabels": {
    "alertname": "DiskFull",
    "severity": "warning"
  },
  "commonAnnotations": {
    "summary": "Disk usage above threshold."
  },
  "externalURL": "https://alertmanager.example.com",
  "alerts": [
    {
      "status": "firing",
      "labels": {
        "alertname": "DiskFull",
        "instance": "build.example.com",
        "severity": "warning"
      },
      "annotations": {
        "summary": "Disk usage above threshold."
      },
      "startsAt": "2026-10-10T09:30:00.000Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "generatorURL": "https://prometheus.example.com/graph",
      "fingerprint": "4a1f0c2b9d3e5f60"
    }
  ]
}

Responses:

Status Description Content Headers
201 Created. application/json: IncomingWebhookResult Correlation-Id, RateLimit, RateLimit-Policy
200 Replay: the original created by an earlier native request with the same client_msg_id. application/json: IncomingWebhookResult Correlation-Id, RateLimit, RateLimit-Policy, Idempotent-Replay
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}
default
{
  "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

listAgentWebhookSubscriptions

GET /agents/{agent_id}/webhooks

List webhook subscriptions of an agent

Webhook as transport for adapters without a running process (04, 15.6).

Parameters:

Name In Type Required Description
agent_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: WebhookSubscriptionList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7b8e-8d3f-2a9c4e6f0b15",
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "url": "https://hooks.example.com/agent",
      "event_types": [
        "agent.invocation"
      ],
      "state": "active",
      "consecutive_failures": 0,
      "signature_schemes": [
        "v1a"
      ],
      "signing_key_kid": "whk-2026-10",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createAgentWebhookSubscription

POST /agents/{agent_id}/webhooks

Subscribe an agent to webhooks

Delivery is strictly in seq order per subscription; 2xx acknowledges up to that seq. Every delivery carries a freshly issued invocation token.

Parameters:

Name In Type Required Description
agent_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: WebhookSubscriptionCreate

Request
{
  "url": "https://hooks.example.com/agent",
  "event_types": [
    "agent.invocation",
    "agent.followup",
    "run.cancel_requested"
  ]
}

Responses:

Status Description Content Headers
201 Created. application/json: WebhookSubscriptionCreated Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

listWebhookSubscriptions

GET /apps/{app_id}/webhooks

List outgoing webhook subscriptions

Parameters:

Name In Type Required Description
app_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: WebhookSubscriptionList Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7e12-8162-c8db90be34b1",
      "app_id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
      "url": "https://hooks.example.com/chat",
      "event_types": [
        "message.created"
      ],
      "state": "active",
      "consecutive_failures": 1,
      "signature_schemes": [
        "v1a"
      ],
      "signing_key_kid": "whk-2026-10",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createWebhookSubscription

POST /apps/{app_id}/webhooks

Subscribe a URL to events

The host and port must be in webhook.allowed_hosts; otherwise 400 webhook_host_not_allowed. With enable_hmac the response carries the v1 secret once; it is a one-time secret, so a replay with the same Idempotency-Key answers 409 conflict with reason one_time_secret.

Parameters:

Name In Type Required Description
app_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: WebhookSubscriptionCreate

Request
{
  "url": "https://hooks.example.com/chat",
  "event_types": [
    "message.created"
  ]
}

Responses:

Status Description Content Headers
201 Created. application/json: WebhookSubscriptionCreated Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "subscription": {
    "id": "0192f4a0-7b1c-7e12-8162-c8db90be34b1",
    "app_id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
    "url": "https://hooks.example.com/chat",
    "event_types": [
      "message.created"
    ],
    "state": "active",
    "consecutive_failures": 1,
    "signature_schemes": [
      "v1a"
    ],
    "signing_key_kid": "whk-2026-10",
    "created_at": "2026-10-10T09:30:00.000Z"
  },
  "hmac_secret": "whsec_EXAMPLE"
}

deleteWebhookSubscription

DELETE /webhooks/{subscription_id}

Delete a subscription

Parameters:

Name In Type Required Description
subscription_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

updateWebhookSubscription

PATCH /webhooks/{subscription_id}

Change, pause or rotate a subscription

A new host must be in webhook.allowed_hosts. rotate_hmac_secret returns the new v1 secret once; it is a one-time secret, so a replay with the same Idempotency-Key answers 409 conflict with reason one_time_secret.

Parameters:

Name In Type Required Description
subscription_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: WebhookSubscriptionUpdate

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: WebhookSubscriptionCreated Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "subscription": {
    "id": "0192f4a0-7b1c-7e12-8162-c8db90be34b1",
    "app_id": "0192f4a0-7b1c-7895-82f8-463a64ff0fbe",
    "url": "https://hooks.example.com/chat",
    "event_types": [
      "message.created"
    ],
    "state": "active",
    "consecutive_failures": 1,
    "signature_schemes": [
      "v1a"
    ],
    "signing_key_kid": "whk-2026-10",
    "created_at": "2026-10-10T09:30:00.000Z"
  },
  "hmac_secret": "whsec_EXAMPLE"
}

listWebhookDeliveries

GET /webhooks/{subscription_id}/deliveries

List delivery attempts

Parameters:

Name In Type Required Description
subscription_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
status query WebhookDeliveryStatus no Filter by status.

Responses:

Status Description Content Headers
200 OK. application/json: WebhookDeliveryPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-73de-870f-6ce6fa448f1e",
      "subscription_id": "0192f4a0-7b1c-756c-88a8-bf72a9fa67f3",
      "event_id": "0192f4a0-7b1c-757c-87c8-267db4b2c89f",
      "event_seq": 5301,
      "event_type": "message.created",
      "attempt": 1,
      "status": "pending",
      "last_error": "timeout",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

redeliverWebhook

POST /webhook-deliveries/{delivery_id}/redeliver

Deliver an event again

Parameters:

Name In Type Required Description
delivery_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
202 Accepted; processing continues asynchronously. application/json: WebhookDelivery Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-73de-870f-6ce6fa448f1e",
  "subscription_id": "0192f4a0-7b1c-756c-88a8-bf72a9fa67f3",
  "event_id": "0192f4a0-7b1c-757c-87c8-267db4b2c89f",
  "event_seq": 5301,
  "event_type": "message.created",
  "attempt": 1,
  "status": "pending",
  "last_error": "timeout",
  "created_at": "2026-10-10T09:30:00.000Z"
}

Audit

Audit log query, export and chain verification.

listAuditEvents

GET /audit/events

Query the audit log

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
actor_id query Uuid no Actor principal.
action query string no Action ID.
decision query AuditDecision no Decision.
resource_kind query string no Resource kind.
resource_id query Uuid no Resource ID.
from query Timestamp no Occurred at or after.
to query Timestamp no Occurred before.

Responses:

Status Description Content Headers
200 OK. application/json: AuditEventPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "seq": 5301,
      "id": "0192f4a0-7b1c-7cb3-8665-8fa2cdd01d12",
      "occurred_at": "2026-10-10T09:30:00.000Z",
      "action": "grant.create",
      "decision": "allow",
      "resource_kind": "grant",
      "details": {},
      "prev_hash": "text",
      "hash": "text"
    }
  ]
}

exportAuditEvents

GET /audit/export

Export the audit log

Streams one AuditEvent per line in ascending seq, with hashes for offline verification. The stream is the contiguous seq span from the smallest to the largest seq whose occurred_at lies in [from, to), so every line links the line before by prev_hash; a row inside the span whose occurred_at lies outside the range (an aggregated denial keeps the time of its first denial) is part of it. A gap inside the stream breaks the hash links (prev_hash); an error after the first line aborts the transfer instead of ending it, so a client sees a broken response, not a shorter complete one.

Parameters:

Name In Type Required Description
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).

Responses:

Status Description Content Headers
200 OK. One JSON object per line (application/x-ndjson). application/x-ndjson: AuditEvent Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

verifyAuditChain

POST /audit/verify

Verify the hash chain

Request body (required): application/json: AuditVerifyRequest

Request
{}

Responses:

Status Description Content Headers
200 OK. application/json: AuditVerifyResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "ok": true,
  "checked_from_seq": 1,
  "checked_to_seq": 5301,
  "checkpoints_compared": 12,
  "last_checkpoint_seq": 5290,
  "warnings": []
}

Stats

Usage, runs, tool calls, errors, costs and prices.

getThreadCosts

GET /threads/{thread_id}/costs

Costs of a thread per run

Valid cost entries of the thread (entries no correction supersedes), whatever channel they were booked in, per run (by run_id ascending, unpaginated) and summed per billing mode and currency without conversion. tokens are always present; amounts of runs in mode personal (their costs and their totals) appear only when the server key billing.show_personal_estimates is on (10, 12.2). Never a person: costs stand per run (20, 9). Without read on the thread the same 404 as for an unknown thread. A thread without entries answers empty lists.

Parameters:

Name In Type Required Description
thread_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: CostBreakdown Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "totals": [
    {
      "billing_mode": "organization",
      "amount_micros": 1250000,
      "currency": "USD",
      "is_estimate": true
    }
  ],
  "runs": [
    {
      "run_id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
      "billing_mode": "organization",
      "agent_session_id": "0192f4a0-7b1c-7000-8a00-000000000501",
      "tokens": {
        "tokens_in": 120000,
        "tokens_out": 8000,
        "tokens_cache_read": 40000,
        "tokens_cache_write": 10000,
        "tokens_cache_write_1h": 0
      },
      "costs": [
        {
          "amount_micros": 1250000,
          "currency": "USD",
          "is_estimate": true
        }
      ],
      "unpriced": false
    },
    {
      "run_id": "0192f4a0-7b1c-70cd-8013-27d7ac09a780",
      "billing_mode": "personal",
      "tokens": {
        "tokens_in": 3000,
        "tokens_out": 500,
        "tokens_cache_read": 0,
        "tokens_cache_write": 0,
        "tokens_cache_write_1h": 0
      },
      "unpriced": true
    }
  ]
}

submitClientMetrics

POST /client-metrics

Submit anonymous client measurements

Only when privacy.client_metrics is on; otherwise 403 feature_disabled. At most once per client.metrics.flush_interval (15, section 17).

  • Security: dpopAuth or bearerAuth or consoleSession (default)
  • x-authz-action: client_metrics.submit
  • x-rate-limit-class: rl.write
  • x-idempotency-exempt: telemetry

Request body (required): application/json: ClientMetricsBatch

Request
{
  "platform": "ios",
  "app_version": "1.4.0",
  "density": "touch",
  "metrics": [
    {
      "name": "client.thread_open.duration",
      "kind": "histogram",
      "buckets": [
        {
          "le": 0.1,
          "count": 12
        },
        {
          "le": 0.25,
          "count": 3
        }
      ]
    },
    {
      "name": "client.reconnects",
      "kind": "counter",
      "close_code": 4009,
      "value": 1
    }
  ]
}

Responses:

Status Description Content Headers
202 Accepted. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

getUsageStats

GET /stats/usage

Usage per space

Metrics per space and bucket: messages (messages not deleted) and by origin messages_human, messages_agent, messages_app, messages_import; threads_created, threads_done (threads closed in the bucket); runs (runs that ended in the bucket); active_people (distinct people with at least one message, only for granularity week or month; below privacy.stats_min_group_size the value is withheld and named in below_min_group); storage_bytes (current sum of the files of the space, in the last bucket only). Grouped by space (group_key is the space ID). Authorized with stats.read on the instance (owner) or, with space_id, on that space (manage); without space_id and without owner status 403, an unreadable space 404. Every number of a channel counts only the channels the caller may read (message.read), intersected with the space; channels without a space (DMs) are not counted. No metric is grouped by person and no person is named. from and to are aligned down and up to the granularity (default day): hour in UTC, day, week (ISO, Monday) and month from local midnight of stats.time_zone, returned as UTC instants; a range longer than stats.max_range, with more than api.stats_max_buckets buckets or with from >= to is 400 validation_failed. Buckets without a value are left out. The result is cached per caller scope for stats.cache_ttl.

Parameters:

Name In Type Required Description
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).
granularity query StatsGranularity no Bucket size; default day.
space_id query Uuid no Restrict to a space; required without owner role.

Responses:

Status Description Content Headers
200 OK. application/json: StatsSeries Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "granularity": "hour",
  "buckets": [
    {
      "start": "2026-10-10T09:30:00.000Z",
      "group_key": "0192f4a0-7b1c-7000-8a00-000000000101",
      "metrics": {}
    }
  ]
}

getRunStats

GET /stats/runs

Runs per agent

Metrics per agent and bucket of the end of a run: runs, completed, failed, cancelled, duration_ms_p50, duration_ms_p95 (from start to end of the runs that started), and failed_reason_<code> for every state_reason code of failed runs that occurs. Grouped by agent (group_key is the agent ID). Authorized with stats.read on the instance (owner) or, with space_id, on that space (manage); without space_id and without owner status 403, an unreadable space 404. Every number of a channel counts only the channels the caller may read (message.read), intersected with the space; channels without a space (DMs) are not counted. No metric is grouped by person and no person is named. from and to are aligned down and up to the granularity (default day): hour in UTC, day, week (ISO, Monday) and month from local midnight of stats.time_zone, returned as UTC instants; a range longer than stats.max_range, with more than api.stats_max_buckets buckets or with from >= to is 400 validation_failed. Buckets without a value are left out. The result is cached per caller scope for stats.cache_ttl.

Parameters:

Name In Type Required Description
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).
granularity query StatsGranularity no Bucket size; default day.
space_id query Uuid no Restrict to a space.
agent_id query Uuid no Restrict to an agent.

Responses:

Status Description Content Headers
200 OK. application/json: StatsSeries Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "granularity": "hour",
  "buckets": [
    {
      "start": "2026-10-10T09:30:00.000Z",
      "group_key": "0192f4a0-7b1c-7000-8a00-000000000101",
      "metrics": {}
    }
  ]
}

getToolCallStats

GET /stats/tool-calls

Tool calls by tool name

Metrics per tool name and bucket of the start of the call: calls, failed, duration_ms_p50 (finished calls). Grouped by the tool name from run_steps (group_key); no step detail, no input and no output. Authorized with stats.read on the instance (owner) or, with space_id, on that space (manage); without space_id and without owner status 403, an unreadable space 404. Every number of a channel counts only the channels the caller may read (message.read), intersected with the space; channels without a space (DMs) are not counted. No metric is grouped by person and no person is named. from and to are aligned down and up to the granularity (default day): hour in UTC, day, week (ISO, Monday) and month from local midnight of stats.time_zone, returned as UTC instants; a range longer than stats.max_range, with more than api.stats_max_buckets buckets or with from >= to is 400 validation_failed. Buckets without a value are left out. The result is cached per caller scope for stats.cache_ttl.

Parameters:

Name In Type Required Description
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).
granularity query StatsGranularity no Bucket size; default day.
space_id query Uuid no Restrict to a space.
agent_id query Uuid no Restrict to an agent.

Responses:

Status Description Content Headers
200 OK. application/json: StatsSeries Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "granularity": "hour",
  "buckets": [
    {
      "start": "2026-10-10T09:30:00.000Z",
      "group_key": "0192f4a0-7b1c-7000-8a00-000000000101",
      "metrics": {}
    }
  ]
}

getErrorStats

GET /stats/errors

Error rates of runs and deliveries

Metrics per bucket: run_failure_rate (failed per ended runs), invocation_denials (messages refused with billing_mode_personal_not_holder plus runs failed with billing_mode_mismatch); only for the instance (owner, without space_id): webhook_failure_rate (failed and dead per finished deliveries still within their retention), push_failure_rate_<provider> (registrations disabled for a provider reason per registrations active in the bucket), scan_errors and scan_infected; these have no channel and count the whole instance. A rate without a denominator is left out. Without space_id there is no group_key; with space_id it is the space ID. HTTP error rates come from telemetry, not from this API. Authorized with stats.read on the instance (owner) or, with space_id, on that space (manage); without space_id and without owner status 403, an unreadable space 404. Every number of a channel counts only the channels the caller may read (message.read), intersected with the space; channels without a space (DMs) are not counted. No metric is grouped by person and no person is named. from and to are aligned down and up to the granularity (default day): hour in UTC, day, week (ISO, Monday) and month from local midnight of stats.time_zone, returned as UTC instants; a range longer than stats.max_range, with more than api.stats_max_buckets buckets or with from >= to is 400 validation_failed. Buckets without a value are left out. The result is cached per caller scope for stats.cache_ttl.

Parameters:

Name In Type Required Description
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).
granularity query StatsGranularity no Bucket size; default day.
space_id query Uuid no Restrict to a space.

Responses:

Status Description Content Headers
200 OK. application/json: StatsSeries Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "granularity": "hour",
  "buckets": [
    {
      "start": "2026-10-10T09:30:00.000Z",
      "group_key": "0192f4a0-7b1c-7000-8a00-000000000101",
      "metrics": {}
    }
  ]
}

getCostStats

GET /stats/costs

Costs per space, agent or instance

Valid cost sums (entries without a successor) per bucket and billing_mode, grouped by group_by (space, agent, none; default none). Authorized with cost.read.aggregate on the instance (owner) or, with space_id, on that space (manage); without space_id and without owner status 403, an unreadable space 404; only channels the caller may read count. personal and organization are never summed together; amounts of mode personal are information only and appear only when billing.show_personal_estimates is on. is_estimate is true when any summed entry is an estimate. One currency per response: currency selects it; without it a range whose entries have one currency answers in that currency (USD when there is none), and a range with several currencies is 400 validation_failed with errors[].code currency_required and the currencies found in detail. Ranges, buckets, time zone and cache as for getUsageStats.

Parameters:

Name In Type Required Description
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).
granularity query StatsGranularity no Bucket size; default day.
group_by query string no Grouping of the buckets; default none. Values: space, agent, none.
space_id query Uuid no Restrict to a space.
agent_id query Uuid no Restrict to an agent.
currency query string no ISO 4217 code of the costs to sum; required when the range has costs in several currencies. Pattern ^[A-Z]{3}$. Example: USD.

Responses:

Status Description Content Headers
200 OK. application/json: CostSeries Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "granularity": "hour",
  "currency": "USD",
  "buckets": [
    {
      "start": "2026-10-10T09:30:00.000Z",
      "billing_mode": "personal",
      "amount_micros": 1,
      "is_estimate": true
    }
  ]
}

getStatsLive

GET /stats/live

Current live frame

The latest live frame (StatsLiveFrame) of the instance or of one space, the same frame the gateway sends as stats.live (docs/spec/25-visualization.md, section 5). The server returns the base frame built for the current stats.live_interval; polling does not rebuild it. Filtered to the channels visible to the caller; cost members only with cost.read.aggregate. 403 feature_disabled when stats.live_enabled is off.

Parameters:

Name In Type Required Description
space_id query Uuid no Restrict to a space; required without owner role.

Responses:

Status Description Content Headers
200 OK. application/json: StatsLiveFrame Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "at": "2026-10-10T09:30:00.000Z",
  "interval_ms": 1000,
  "scope": {
    "kind": "instance"
  },
  "runs": [
    {
      "run_id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
      "thread_id": "0192f4a0-7b1c-7000-8a00-000000000301",
      "channel_id": "0192f4a0-7b1c-7000-8a00-000000000201",
      "space_id": "0192f4a0-7b1c-7000-8a00-000000000101",
      "agent_id": "0192f4a0-7b1c-7000-8a00-000000000401",
      "state": "running",
      "queued_at": "2026-10-10T09:29:10.000Z",
      "started_at": "2026-10-10T09:29:11.000Z",
      "billing_mode": "organization",
      "step": {
        "kind": "tool_call",
        "name": "Bash"
      },
      "approval_pending": false,
      "cost_micros": 420000,
      "currency": "USD",
      "cost_is_estimate": true
    }
  ],
  "runs_truncated": false,
  "agents": [
    {
      "agent_id": "0192f4a0-7b1c-7000-8a00-000000000401",
      "presence": "online",
      "billing_mode": "organization",
      "reported_billing_mode": "organization",
      "rate_limit": {
        "state": "ok"
      }
    }
  ],
  "rates": [
    {
      "metric": "messages_created",
      "last_minute": 14,
      "current_minute": 3
    }
  ],
  "sli": [
    {
      "metric": "sli.delivery_latency",
      "total": 5210,
      "good": 5207,
      "ratio": 0.99942
    }
  ]
}

getStatsTimeline

GET /stats/timeline

Minute buckets and runs for playback

Minute aggregates from stats_minutes and run intervals for a range of at most stats.timeline_max_range inside retention.stats_minutes (docs/spec/25-visualization.md, section 6.5). Filtered to the channels visible to the caller. Rows without a channel (sli.*, gateway metrics) only with stats.read on the instance; cost only with cost.read.aggregate.

Parameters:

Name In Type Required Description
from query Timestamp yes Start of the range (inclusive), a full minute.
to query Timestamp yes End of the range (exclusive), a full minute.
space_id query Uuid no Restrict to a space; required without owner role.
metric query array of StatsMetric no Metrics to return; absent means all metrics the caller may see.

Responses:

Status Description Content Headers
200 OK. application/json: StatsTimeline Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "from": "2026-10-10T00:00:00.000Z",
  "to": "2026-10-11T00:00:00.000Z",
  "buckets": [
    {
      "start": "2026-10-10T09:30:00.000Z",
      "metric": "runs_finished",
      "channel_id": "0192f4a0-7b1c-7000-8a00-000000000201",
      "agent_id": "0192f4a0-7b1c-7000-8a00-000000000401",
      "dimension": "completed",
      "count": 2,
      "sum": 84000,
      "good": 0
    }
  ],
  "runs": [
    {
      "run_id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
      "channel_id": "0192f4a0-7b1c-7000-8a00-000000000201",
      "agent_id": "0192f4a0-7b1c-7000-8a00-000000000401",
      "queued_at": "2026-10-10T09:29:10.000Z",
      "started_at": "2026-10-10T09:29:11.000Z",
      "finished_at": "2026-10-10T09:30:35.000Z",
      "state": "completed"
    }
  ],
  "runs_truncated": false
}

getStatsSlo

GET /stats/slo

SLO traffic light from own measurement

One entry per SLO of the Sloth files, computed from stats_minutes over the SLO period (docs/spec/25-visualization.md, section 6.4). Label "own measurement": values may differ from Prometheus. Requires stats.read on the instance (owner); a space manager gets 403 forbidden.

Responses:

Status Description Content Headers
200 OK. application/json: StatsSloReport Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "at": "2026-10-10T09:30:00.000Z",
  "measured_by": "own",
  "items": [
    {
      "slo": "bothy-sync/delivery-latency",
      "metric": "sli.delivery_latency",
      "objective": 99.5,
      "threshold_ms": 500,
      "period_days": 30,
      "total": 1250000,
      "good": 1246100,
      "ratio": 0.99688,
      "budget_remaining": 0.376,
      "state": "green"
    }
  ]
}

getStatsBackends

GET /stats/backends

Backend policy view per agent

Per agent: configured and reported billing mode, supported modes, switches, denied invocations (I2, I3), cost per mode and the rate-limit state reported by the adapter (docs/spec/25-visualization.md, section 6.2). Agents of channels visible to the caller; cost members only with cost.read.aggregate. Never credentials, subscriptions or runtime names of an instance.

Parameters:

Name In Type Required Description
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).
space_id query Uuid no Restrict to a space; required without owner role.

Responses:

Status Description Content Headers
200 OK. application/json: StatsBackendReport Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "agent_id": "0192f4a0-7b1c-7000-8a00-000000000401",
      "billing_mode": "organization",
      "reported_billing_mode": "organization",
      "billing_modes_supported": [
        "organization"
      ],
      "switches": 1,
      "invocations_denied": {
        "i2_denied": 0,
        "billing_mode_mismatch": 0
      },
      "costs": [
        {
          "billing_mode": "organization",
          "currency": "USD",
          "amount_micros": 12400000,
          "is_estimate": true
        }
      ],
      "rate_limit": {
        "state": "near_limit",
        "resets_at": "2026-10-10T10:00:00.000Z"
      }
    }
  ]
}

listPrices

GET /prices

List prices

Every row of the price table, closed ones included, ordered by provider, model, unit, valid_from and id; valid_to is absent while a row is open. A small unpaginated list (06, 6 point 6). Owner only; an owner's personal token gets 403.

Responses:

Status Description Content Headers
200 OK. application/json: PriceList Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7096-8437-e1ee469c906c",
      "provider": "anthropic",
      "model": "model-large",
      "unit": "input_mtok",
      "price_micros": 1,
      "currency": "USD",
      "valid_from": "2026-10-10T09:30:00.000Z",
      "source_url": "https://provider.example.com/pricing",
      "retrieved_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createPrice

POST /prices

Add a price with source

Owner with step-up, audited with row, source and retrieval time (10, 14). source_url is an absolute https URL without user info and fragment, retrieved_at not in the future, currency an ISO 4217 code. 409 conflict with reason price_overlap when the validity overlaps a row of the same provider, model and unit, price_currency_mismatch when an overlapping row of the same provider and model has another currency (one currency per price set).

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: PriceCreate

Request
{
  "provider": "anthropic",
  "model": "model-large",
  "unit": "input_mtok",
  "price_micros": 1,
  "currency": "USD",
  "valid_from": "2026-10-10T09:30:00.000Z",
  "source_url": "https://provider.example.com/pricing",
  "retrieved_at": "2026-10-10T09:30:00.000Z"
}

Responses:

Status Description Content Headers
201 Created. application/json: Price Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7096-8437-e1ee469c906c",
  "provider": "anthropic",
  "model": "model-large",
  "unit": "input_mtok",
  "price_micros": 1,
  "currency": "USD",
  "valid_from": "2026-10-10T09:30:00.000Z",
  "source_url": "https://provider.example.com/pricing",
  "retrieved_at": "2026-10-10T09:30:00.000Z"
}

closePrice

POST /prices/{price_id}/close

End the validity of a price

Sets valid_to of an open row, the only change a row ever gets (R-DM-23). The same end again answers 200 without change. 409 conflict with reason price_closed when the row is already closed with another end (a closed row is never reopened or moved; a gap is filled by a new row), price_in_use when a computed cost entry at or after the new end used the row.

Parameters:

Name In Type Required Description
price_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: PriceClose

Request
{
  "valid_to": "2026-10-10T09:30:00.000Z"
}

Responses:

Status Description Content Headers
200 OK. application/json: Price Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7096-8437-e1ee469c906c",
  "provider": "anthropic",
  "model": "model-large",
  "unit": "input_mtok",
  "price_micros": 1,
  "currency": "USD",
  "valid_from": "2026-10-10T09:30:00.000Z",
  "source_url": "https://provider.example.com/pricing",
  "retrieved_at": "2026-10-10T09:30:00.000Z"
}

reconcileCosts

POST /costs/reconcile

Reconcile estimates with invoices

For an owner in a session with a fresh step-up; app, agent and personal tokens are refused (05, R-AZ-03). Stores new reconciled entries next to the estimates and never changes or deletes an entry (10, 12.4). An entry is matched when its run has at least one valid cost entry with occurred_at in the half-open period [period_start, period_end) and all of them have mode organization, the given provider and the entry's currency; otherwise its run ID is listed in unmatched_run_ids. The amount of a matched run is split over its valid entries in the period in proportion to their amounts, the remainder on the largest entry; a run whose valid entries in the period are already reconciled with the same sum is not written again. The job billing.reconcile then applies the entries to the run and agent session totals.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: CostReconcile

Request
{
  "provider": "anthropic",
  "period_start": "2026-10-10T09:30:00.000Z",
  "period_end": "2026-10-10T09:30:00.000Z",
  "entries": [
    {
      "run_id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
      "amount_micros": 1,
      "currency": "USD"
    }
  ]
}

Responses:

Status Description Content Headers
200 OK. application/json: CostReconcileResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "reconciled": 1,
  "unmatched_run_ids": [
    "0192f4a0-7b1c-7250-807f-c268a7b21797"
  ]
}

submitCostReconciliation

POST /costs/reconciliations

Submit reconciled cost entries (app)

For the reconciliation app with scope costs:reconcile, without step-up. Only adds reconciled entries to existing runs; deletes nothing (10, 12.4). Matching, period, split and repeat rules as reconcileCosts: an entry is matched when its run has at least one valid cost entry with occurred_at in [period_start, period_end) and all of them have mode organization, the given provider and the entry's currency; unmatched run IDs are listed in unmatched_run_ids; a run already reconciled with the same sum is not written again. The job billing.reconcile then applies the entries to the run and agent session totals.

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: CostReconcile

Responses:

Status Description Content Headers
200 OK. application/json: CostReconcileResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

listCostEstimates

GET /costs/estimates

Cost estimates per run for reconciliation

For the reconciliation app with scope costs:reconcile and for owners in a session, without step-up (05, R-AZ-28). One item per run of the given agents with cost entries of mode organization whose occurred_at lies in the range, sorted by run_id; runs whose entries in the range mix currencies are left out. Entries of mode personal never appear (03 cost_entries). Items name no channel, thread or content; the list is evaluated on the instance and not filtered by visible channels (06, 4 point 2).

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).
agent_id query array of Uuid yes Agents whose runs are listed; repeat the parameter for several agents. Min items 1.

Responses:

Status Description Content Headers
200 OK. application/json: CostEstimatePage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "run_id": "0192f4a0-7b1c-70cd-8013-27d7ac09a77f",
      "agent_id": "0192f4a0-7b1c-7250-807f-c268a7b21797",
      "provider": "anthropic",
      "currency": "USD",
      "estimate_micros": 1250000,
      "reconciled": false
    }
  ]
}

Status

Status page.

getStatus

GET /status

Status page

Responses:

Status Description Content Headers
200 OK. application/json: StatusPage Correlation-Id, RateLimit, RateLimit-Policy
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "overall_state": "operational",
  "components": [
    {
      "id": "0192f4a0-7b1c-7cbd-8bdb-de45278e4e7b",
      "name": "Messages",
      "description": "Support team",
      "sort_key": "a0",
      "state": "operational",
      "health_source": "db",
      "updated_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "incidents": [
    {
      "id": "0192f4a0-7b1c-7b46-88f5-a7d58fbd8809",
      "title": "Push notifications delayed",
      "kind": "incident",
      "impact": "none",
      "state": "scheduled",
      "started_at": "2026-10-10T09:30:00.000Z",
      "component_ids": [
        "0192f4a0-7b1c-790b-86bb-302f588b2602"
      ],
      "updates": [
        {
          "id": "0192f4a0-7b1c-7d72-8102-dd7af4afabb5",
          "state": "scheduled",
          "body_md": "The push provider reports delays. We are monitoring.",
          "created_at": "2026-10-10T09:30:00.000Z"
        }
      ]
    }
  ]
}

getPublicStatus

GET /status/public

Status page without login

404 unless status.public_enabled.

  • Security: none
  • x-authz-action: status.public.read
  • x-rate-limit-class: rl.public_auth

Responses:

Status Description Content Headers
200 OK. application/json: StatusPage Correlation-Id, RateLimit, RateLimit-Policy
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "overall_state": "operational",
  "components": [
    {
      "id": "0192f4a0-7b1c-7cbd-8bdb-de45278e4e7b",
      "name": "Messages",
      "description": "Support team",
      "sort_key": "a0",
      "state": "operational",
      "health_source": "db",
      "updated_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "incidents": [
    {
      "id": "0192f4a0-7b1c-7b46-88f5-a7d58fbd8809",
      "title": "Push notifications delayed",
      "kind": "incident",
      "impact": "none",
      "state": "scheduled",
      "started_at": "2026-10-10T09:30:00.000Z",
      "component_ids": [
        "0192f4a0-7b1c-790b-86bb-302f588b2602"
      ],
      "updates": [
        {
          "id": "0192f4a0-7b1c-7d72-8102-dd7af4afabb5",
          "state": "scheduled",
          "body_md": "The push provider reports delays. We are monitoring.",
          "created_at": "2026-10-10T09:30:00.000Z"
        }
      ]
    }
  ]
}

createStatusComponent

POST /status/components

Add a status component

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: StatusComponentInput

Request
{
  "name": "Messages"
}

Responses:

Status Description Content Headers
201 Created. application/json: StatusComponent Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7cbd-8bdb-de45278e4e7b",
  "name": "Messages",
  "description": "Support team",
  "sort_key": "a0",
  "state": "operational",
  "health_source": "db",
  "updated_at": "2026-10-10T09:30:00.000Z"
}

deleteStatusComponent

DELETE /status/components/{component_id}

Remove a status component

Parameters:

Name In Type Required Description
component_id path Uuid yes

Responses:

Status Description Content Headers
204 No content. Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

updateStatusComponent

PATCH /status/components/{component_id}

Change a status component

Parameters:

Name In Type Required Description
component_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: StatusComponentInput

Request
{
  "name": "Messages"
}

Responses:

Status Description Content Headers
200 OK. application/json: StatusComponent Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7cbd-8bdb-de45278e4e7b",
  "name": "Messages",
  "description": "Support team",
  "sort_key": "a0",
  "state": "operational",
  "health_source": "db",
  "updated_at": "2026-10-10T09:30:00.000Z"
}

createStatusIncident

POST /status/incidents

Open an incident or maintenance

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: StatusIncidentCreate

Request
{
  "title": "Push notifications delayed",
  "kind": "incident",
  "impact": "none",
  "started_at": "2026-10-10T09:30:00.000Z",
  "component_ids": [
    "0192f4a0-7b1c-790b-86bb-302f588b2602"
  ],
  "body_md": "The push provider reports delays."
}

Responses:

Status Description Content Headers
201 Created. application/json: StatusIncident Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7b46-88f5-a7d58fbd8809",
  "title": "Push notifications delayed",
  "kind": "incident",
  "impact": "none",
  "state": "scheduled",
  "started_at": "2026-10-10T09:30:00.000Z",
  "component_ids": [
    "0192f4a0-7b1c-790b-86bb-302f588b2602"
  ],
  "updates": [
    {
      "id": "0192f4a0-7b1c-7d72-8102-dd7af4afabb5",
      "state": "scheduled",
      "body_md": "The push provider reports delays. We are monitoring.",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

addStatusIncidentUpdate

POST /status/incidents/{incident_id}/updates

Add an update to an incident

Parameters:

Name In Type Required Description
incident_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: StatusIncidentUpdateCreate

Request
{
  "state": "scheduled",
  "body_md": "Delays are resolved."
}

Responses:

Status Description Content Headers
201 Created. application/json: StatusIncident Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7b46-88f5-a7d58fbd8809",
  "title": "Push notifications delayed",
  "kind": "incident",
  "impact": "none",
  "state": "scheduled",
  "started_at": "2026-10-10T09:30:00.000Z",
  "component_ids": [
    "0192f4a0-7b1c-790b-86bb-302f588b2602"
  ],
  "updates": [
    {
      "id": "0192f4a0-7b1c-7d72-8102-dd7af4afabb5",
      "state": "scheduled",
      "body_md": "The push provider reports delays. We are monitoring.",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

Import

Import jobs.

listImports

GET /imports

List import sources

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: ImportSourcePage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
      "kind": "discord",
      "name": "Old community server",
      "config": {},
      "state": "draft",
      "stats": {},
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createImport

POST /imports

Add an import source

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ImportSourceCreate

Request
{
  "kind": "discord",
  "name": "Old community server",
  "config": {}
}

Responses:

Status Description Content Headers
201 Created. application/json: ImportSource Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
  "kind": "discord",
  "name": "Old community server",
  "config": {},
  "state": "draft",
  "stats": {},
  "created_at": "2026-10-10T09:30:00.000Z"
}

getImport

GET /imports/{import_id}

Read progress of an import

Parameters:

Name In Type Required Description
import_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: ImportSource Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
  "kind": "discord",
  "name": "Old community server",
  "config": {},
  "state": "draft",
  "stats": {},
  "created_at": "2026-10-10T09:30:00.000Z"
}

listImportItems

GET /imports/{import_id}/items

List imported items

Parameters:

Name In Type Required Description
import_id path Uuid yes
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
state query ImportItemState no Filter by state.

Responses:

Status Description Content Headers
200 OK. application/json: ImportItemPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7e43-8919-6113546a4c70",
      "origin_key": "message:1029384756:0",
      "item_kind": "space",
      "state": "pending",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

startImport

POST /imports/{import_id}/start

Start or continue an import

Moves a draft or paused source to running (22, 7.4); started_at is set on the first start. Starting a running source answers it unchanged. Any other state is 409 conflict with reason import_state.

Parameters:

Name In Type Required Description
import_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
202 Accepted; processing continues asynchronously. application/json: ImportSource Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
  "kind": "discord",
  "name": "Old community server",
  "config": {},
  "state": "draft",
  "stats": {},
  "created_at": "2026-10-10T09:30:00.000Z"
}

pauseImport

POST /imports/{import_id}/pause

Pause an import

Moves a running source to paused; batches and cursor writes then answer 409 conflict with reason import_not_running. Pausing a paused source answers it unchanged. Any other state is 409 conflict with reason import_state.

Parameters:

Name In Type Required Description
import_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
200 OK. application/json: ImportSource Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
  "kind": "discord",
  "name": "Old community server",
  "config": {},
  "state": "draft",
  "stats": {},
  "created_at": "2026-10-10T09:30:00.000Z"
}

cancelImport

POST /imports/{import_id}/cancel

Cancel an import

Ends a draft, running or paused source as failed with the counter server.cancelled set to true in stats and sets finished_at. Any other state is 409 conflict with reason import_state.

Parameters:

Name In Type Required Description
import_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
200 OK. application/json: ImportSource Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
  "kind": "discord",
  "name": "Old community server",
  "config": {},
  "state": "draft",
  "stats": {},
  "created_at": "2026-10-10T09:30:00.000Z"
}

completeImport

POST /imports/{import_id}/complete

Complete an import

When every channel is led by this server: stop the mirror, source completed (22, 13.5). Only from running or paused, else 409 conflict with reason import_state. Every channel of the mapping whose target is not skip and whose channel item is posted must have lead = bothy, else 409 conflict with reason lead_not_bothy; mapped channels that were never imported do not block it.

Parameters:

Name In Type Required Description
import_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Responses:

Status Description Content Headers
200 OK. application/json: ImportSource Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
  "kind": "discord",
  "name": "Old community server",
  "config": {},
  "state": "completed",
  "stats": {},
  "created_at": "2026-10-10T09:30:00.000Z"
}

setImportLead

PUT /imports/{import_id}/leads

Set the leading side of a channel

Switches lead of one mapped channel and the read-only state of its target channel in one transaction (22, 12.1 and 13). The channel must be in the mapping with a target other than skip (else 404) and its channel item must be posted (else 409 conflict with reason channel_not_imported). lead = discord sets the target channel read-only and cancels its active runs; lead = bothy lifts read-only. A completed or failed source is 409 conflict with reason import_state. A lead equal to the current one changes nothing.

Parameters:

Name In Type Required Description
import_id path Uuid yes

Request body (required): application/json: ImportLeadSet

Request
{
  "source_channel": "1029384000",
  "lead": "bothy"
}

Responses:

Status Description Content Headers
200 OK. application/json: ImportSource Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
  "kind": "discord",
  "name": "Old community server",
  "config": {},
  "state": "completed",
  "stats": {},
  "created_at": "2026-10-10T09:30:00.000Z"
}

applyImportBatch

POST /imports/{import_id}/batches

Write a batch of imported objects

One transaction, at most import.batch_max_items objects. Every target must lie in a channel of this running source. Existing posted keys return their target without a duplicate or event (22, 7.2). Writes thread.updated and import.progress instead of one event per message. A source that is not running is 409 conflict with reason import_not_running; a target outside the channels of the source is 409 conflict with reason target_outside_source; a new channel whose name equals a live channel of its space is 409 conflict with reason name_collision. The data of a structure item follows ImportSpaceData, ImportChannelData, ImportForumTagData or ImportUserData. A batch with thread_origin_key concerns exactly one thread (thread:<id>, or channel:<id> for the main thread of a text channel; a forum has none, 400 validation_failed). Its optional first item is the thread item of that key (ImportThreadData), every other item a message (ImportMessageData) or a pin (ImportPinData); a structure item there, or a content item in a batch without thread_origin_key, is 400 validation_failed at its item_kind. A thread that is neither posted nor created by the batch is 409 conflict with reason thread_not_imported; a message whose author item is not posted 409 conflict with reason author_not_imported. Imported messages have origin = import, are silent, write no mentions and never trigger an agent; a posted thread only follows the mirror rules of 22 12.2 step 3. At its end a batch that changed something sets threads.unread_floor_seq to the end of the thread and appends one thread.updated and one import.progress, never message.created (04 15.8).

Parameters:

Name In Type Required Description
import_id path Uuid yes

Request body (required): application/json: ImportBatch

Request
{
  "thread_origin_key": "thread:1029384700",
  "items": [
    {
      "origin_key": "message:1029384756",
      "item_kind": "message",
      "data": {
        "author_origin_key": "user:1029384000",
        "content_md": "The invoice export fails.",
        "created_at": "2025-03-01T08:00:00.000Z"
      }
    }
  ]
}

Responses:

Status Description Content Headers
200 OK. application/json: ImportBatchResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7e43-8919-6113546a4c70",
      "origin_key": "message:1029384756",
      "item_kind": "message",
      "target_kind": "message",
      "target_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "state": "posted",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ],
  "unread_floor_seq": 42
}

createImportFile

POST /imports/{import_id}/files

Reserve an imported file

Writes the pending item and reserves the file ID with an upload session of mode direct, without the quota check of createUpload (12, 11); the parts and the completion follow through uploadImportFilePart and completeImportFile, which a read-only mirror channel accepts (05 rule 1.8). A repeated call with the same key returns the same ID: with the open session, with a new session after an aborted or expired one, and without upload once the item is posted (22, 7.2). channel_id must be the target of a posted channel item of the source (409 conflict, reason target_outside_source), author_id the target of a posted user item (409 conflict, reason author_not_imported); the scan of an import file runs with the lowest job priority.

Parameters:

Name In Type Required Description
import_id path Uuid yes

Request body (required): application/json: ImportFileCreate

Request
{
  "origin_key": "file:1029384799",
  "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
  "author_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "name": "report.pdf",
  "size_bytes": 48213,
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
}

Responses:

Status Description Content Headers
200 OK. application/json: ImportFileSlot Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

uploadImportFilePart

PUT /imports/{import_id}/files/{file_id}/parts/{part_number}

Upload one part of an imported file

One part of the file of a file item of this source in mode direct, with the rules of uploadPart (12, 3.2): the same part number with the same Content-Digest answers 200 without new work, with another digest 409 conflict with reason part_conflict; a wrong length or digest is 400 validation_failed with errors[].code part_digest_mismatch and stores nothing; an expired session answers 410 gone (a repeated createImportFile opens a new one). It authorizes import.apply on the running source instead of file.upload, so a read-only mirror channel accepts it (05 rule 1.8, 4.12). A file that is not the target of a file item of this source is 404.

Parameters:

Name In Type Required Description
import_id path Uuid yes
file_id path Uuid yes
part_number path integer yes Minimum 1.
Content-Digest header string yes RFC 9530 digest of the part with the member sha-256, e.g. sha-256=:<base64>:; other members are ignored.

Request body (required): application/octet-stream: string (binary)

Responses:

Status Description Content Headers
200 OK. application/json: UploadPartResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
413 PayloadTooLarge: Problem codes: payload_too_large. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "part_number": 1,
  "etag": "\"3858f62230ac3c915f300c664312c11f\""
}

completeImportFile

POST /imports/{import_id}/files/{file_id}/complete

Finish the upload of an imported file

Completes the upload of the file of a file item of this source with the rules of completeUpload (12, 3.4): parts is checked against the confirmed parts, missing parts are 409 conflict with reason upload_incomplete, another etag 409 conflict with reason part_conflict, an expired session 410 gone. The job files.scan checks size and SHA-256 against the declaration of createImportFile, detects the type and scans; it runs with the lowest job priority, so live uploads are scanned first (12, 11). The item becomes posted in the same transaction; a repeated call answers the posted item. It authorizes import.apply on the running source instead of file.upload (05 rule 1.8, 4.12). A file that is not the target of a file item of this source is 404.

Parameters:

Name In Type Required Description
import_id path Uuid yes
file_id path Uuid yes

Request body (required): application/json: UploadComplete

Request
{
  "parts": [
    {
      "part_number": 1,
      "etag": "\"3858f62230ac3c915f300c664312c11f\""
    }
  ]
}

Responses:

Status Description Content Headers
200 OK. application/json: ImportFileSlot Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "item": {
    "id": "0192f4a0-7b1c-7e43-8919-6113546a4c71",
    "origin_key": "file:1029384799",
    "item_kind": "file",
    "target_kind": "file",
    "target_id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
    "state": "posted",
    "created_at": "2026-10-10T09:30:00.000Z"
  }
}

setImportCursor

PUT /imports/{import_id}/cursor

Advance the import cursor

Only after a successful batch (22, 7.3). Replaces cursor with the given object and merges the top-level members of stats into the member tool of ImportSource.stats (the server's own counters stay under server). Only for a running source, else 409 conflict with reason import_not_running.

Parameters:

Name In Type Required Description
import_id path Uuid yes

Request body (required): application/json: ImportCursorSet

Request
{
  "cursor": {}
}

Responses:

Status Description Content Headers
200 OK. application/json: ImportSource Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-78d2-8a6a-ec465435b8a0",
  "kind": "discord",
  "name": "Old community server",
  "config": {},
  "state": "completed",
  "stats": {},
  "created_at": "2026-10-10T09:30:00.000Z"
}

Privacy

Privacy requests and exports.

exportChannel

GET /channels/{channel_id}/export

Export the history of a channel

Streams one Message per line in thread_seq order per thread. Requires step-up.

from must be strictly before to, else 400 validation_failed at #query/to with code invalid; the range has no upper bound, so clients split long ranges. Each line carries the full content_md without content_truncated and without my_reactions; deleted messages appear as tombstones at their thread_seq. Threads come ascending by id, the messages of a thread ascending by thread_seq. Read rights are checked again before every batch, so a revocation ends the stream. An export cut after the first byte ends without a complete response (no final chunk); a range without messages gives 200 with an empty body.

Parameters:

Name In Type Required Description
channel_id path Uuid yes
from query Timestamp yes Start of the range (inclusive).
to query Timestamp yes End of the range (exclusive).

Responses:

Status Description Content Headers
200 OK. One JSON object per line (application/x-ndjson). application/x-ndjson: Message Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

listGdprRequests

GET /gdpr-requests

List privacy requests

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
subject_user_id query Uuid no Only requests about this person.
state query GdprRequestState no Filter by state.

Responses:

Status Description Content Headers
200 OK. application/json: GdprRequestPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7ac0-85c3-2e83fd50d9e7",
      "subject_user_id": "0192f4a0-7b1c-7277-8379-95fe87046d8a",
      "kind": "export",
      "state": "requested",
      "requested_by": "0192f4a0-7b1c-7e23-8a0f-0b7e316bfc58",
      "reason": "Request by the person",
      "due_at": "2026-10-10T09:30:00.000Z",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  ]
}

createGdprRequest

POST /gdpr-requests

Request export, deletion or rectification

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: GdprRequestCreate

Request
{
  "kind": "export",
  "reason": "Request by the person"
}

Responses:

Status Description Content Headers
201 Created. application/json: GdprRequest Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7ac0-85c3-2e83fd50d9e7",
  "subject_user_id": "0192f4a0-7b1c-7277-8379-95fe87046d8a",
  "kind": "export",
  "state": "requested",
  "requested_by": "0192f4a0-7b1c-7e23-8a0f-0b7e316bfc58",
  "reason": "Request by the person",
  "due_at": "2026-10-10T09:30:00.000Z",
  "created_at": "2026-10-10T09:30:00.000Z"
}

getGdprRequest

GET /gdpr-requests/{request_id}

Read a privacy request

Parameters:

Name In Type Required Description
request_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: GdprRequest Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7ac0-85c3-2e83fd50d9e7",
  "subject_user_id": "0192f4a0-7b1c-7277-8379-95fe87046d8a",
  "kind": "export",
  "state": "requested",
  "requested_by": "0192f4a0-7b1c-7e23-8a0f-0b7e316bfc58",
  "reason": "Request by the person",
  "due_at": "2026-10-10T09:30:00.000Z",
  "created_at": "2026-10-10T09:30:00.000Z"
}

decideGdprRequest

POST /gdpr-requests/{request_id}/decide

Approve or reject a privacy request

Parameters:

Name In Type Required Description
request_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: GdprDecision

Request
{
  "decision": "approve",
  "reason": "Identity verified"
}

Responses:

Status Description Content Headers
200 OK. application/json: GdprRequest Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7ac0-85c3-2e83fd50d9e7",
  "subject_user_id": "0192f4a0-7b1c-7277-8379-95fe87046d8a",
  "kind": "export",
  "state": "requested",
  "requested_by": "0192f4a0-7b1c-7e23-8a0f-0b7e316bfc58",
  "reason": "Request by the person",
  "due_at": "2026-10-10T09:30:00.000Z",
  "created_at": "2026-10-10T09:30:00.000Z"
}

downloadGdprExport

GET /gdpr-requests/{request_id}/export

Download the export package

Parameters:

Name In Type Required Description
request_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/zip: string (binary) Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
410 Gone: Problem codes: resync_required, message_deleted, gone. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id

Hosts

Connected hosts for the terminal: registration, pairing, fingerprint, LLM login declaration (I6).

listHosts

GET /hosts

List hosts

Owners see every host; other people see hosts they are assigned to or hold a terminal grant on (07, 2.12). Ordered by name.

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no

Responses:

Status Description Content Headers
200 OK. application/json: HostPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
      "name": "Build server",
      "state": "active",
      "platform": "linux",
      "assigned_user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "llm_credentials": "organization",
      "declared_server_host": false,
      "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
      "key_generation": 1,
      "profiles": [
        {
          "name": "shell",
          "display_name": "Shell",
          "kind": "shell"
        },
        {
          "name": "claude",
          "display_name": "Claude Code",
          "kind": "claude"
        }
      ],
      "doctor": [
        {
          "check": "hd1_user",
          "ok": true
        }
      ],
      "session_users": [
        {
          "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
          "os_user": "bothy-s-robin",
          "created_at": "2026-10-10T09:42:00.000Z"
        }
      ],
      "reported_session_users": [
        {
          "os_user": "bothy-s-robin",
          "workdirs": [
            "Project A"
          ]
        }
      ],
      "connected": true,
      "host_version": "1.0.0",
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3
    }
  ]
}

createHost

POST /hosts

Register a host and issue its pairing code

Creates a host in state pairing and returns the pairing code bothy_hpc_... exactly once; it is valid for terminal.pairing_code_ttl (24, 3.2). Needs step-up. The code is a one-time secret: a replay with the same Idempotency-Key answers 409 conflict with reason one_time_secret instead of repeating it (06, 7).

Parameters:

Name In Type Required Description
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: HostCreate

Request
{
  "name": "Build server",
  "assigned_user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "reason": "Shared build machine for Alex"
}

Responses:

Status Description Content Headers
201 Created. application/json: HostPairingCode Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "host_id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "pairing_code": "bothy_hpc_EXAMPLE000000000000000000000000000000000000_EXAMPL",
  "expires_at": "2026-10-10T09:45:00.000Z"
}

pairHost

POST /hosts/pair

Redeem a pairing code from the host service

Called by bothy-host pair without login. Registers the static X25519 key (Noise) and the Ed25519 key (login) of the host, its profiles and the names of its session users (reported_session_users, 24 section 2.2). The host becomes confirming, key_generation rises; an owner confirms the fingerprint (24, 3.2). Every code that does not work answers 401 unauthenticated with the same body: a wrong form or checksum (checked without database access), an unknown, used, replaced or expired code; a retry after a lost answer gets 401 too, the operator asks for a new code. Key rules (400 validation_failed, the code stays valid): noise_public_key strict base64url of 32 bytes and no low-order point (errors[].code invalid_key); auth_public_jwk exactly kty OKP, crv Ed25519 and x of 32 bytes (invalid_key), any other member such as the private d is unknown_member. Report rules: at least one session user (empty), names distinct without regard to case (duplicate) and at most host.os_user_max_chars characters (too_long), labels and profile names at most terminal.report_label_max_chars characters (too_long), each list at most terminal.report_max_entries entries (limit_reached), distinct profile names (duplicate), host_version SemVer without v (invalid_format). 409 conflict with reason host_key_in_use when the login key belongs to another host, host_key_reused when the keys equal the keys a re-pairing dropped; the code stays valid.

  • Security: none
  • x-authz-action: host.pair
  • x-rate-limit-class: rl.public_auth
  • x-idempotency-exempt: auth_flow

Request body (required): application/json: HostPairRequest

Request
{
  "pairing_code": "bothy_hpc_EXAMPLE000000000000000000000000000000000000_EXAMPL",
  "noise_public_key": "Zm9vYmFyZm9vYmFyZm9vYmFyZm9vYmFyZm9vYmFyMTI",
  "auth_public_jwk": {
    "kty": "OKP",
    "crv": "Ed25519",
    "x": "EXAMPLE-ed25519-public-key-base64url-0000000"
  },
  "platform": "linux",
  "os_version": "Debian 13",
  "host_version": "1.0.0",
  "profiles": [
    {
      "name": "shell",
      "display_name": "Shell",
      "kind": "shell"
    },
    {
      "name": "claude",
      "display_name": "Claude Code",
      "kind": "claude"
    }
  ],
  "session_users": [
    {
      "os_user": "bothy-s-robin",
      "workdirs": [
        "Project A"
      ]
    }
  ]
}

Responses:

Status Description Content Headers
201 Created. application/json: HostPairResult Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "host_id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
  "instance_id": "0192f4a0-7b1c-7000-8a00-000000000001"
}

getHost

GET /hosts/{host_id}

Read a host

Parameters:

Name In Type Required Description
host_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: Host Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "name": "Build server",
  "state": "active",
  "platform": "linux",
  "assigned_user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "llm_credentials": "organization",
  "declared_server_host": false,
  "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
  "key_generation": 1,
  "profiles": [
    {
      "name": "shell",
      "display_name": "Shell",
      "kind": "shell"
    },
    {
      "name": "claude",
      "display_name": "Claude Code",
      "kind": "claude"
    }
  ],
  "doctor": [
    {
      "check": "hd1_user",
      "ok": true
    }
  ],
  "session_users": [
    {
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "os_user": "bothy-s-robin",
      "created_at": "2026-10-10T09:42:00.000Z"
    }
  ],
  "reported_session_users": [
    {
      "os_user": "bothy-s-robin",
      "workdirs": [
        "Project A"
      ]
    }
  ],
  "connected": true,
  "host_version": "1.0.0",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3
}

updateHost

PATCH /hosts/{host_id}

Change name or assignee of a host

A new assigned_user_id ends the sessions of people who no longer qualify under SR10 (access_revoked). add_session_users assigns own session users (ruling T12; a taken name gives 409 conflict with reason: session_user_taken, a name the host does not report in reported_session_users gives 400 validation_failed with errors[].code session_user_not_on_host); revoke_session_users ends the assignment of the listed people, ends their sessions on the host (access_revoked) and keeps the name taken (24 section 2.2). Needs step-up.

Parameters:

Name In Type Required Description
host_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: HostUpdate

Request
{
  "assigned_user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "reason": "Robin hands the machine to Alex"
}

Responses:

Status Description Content Headers
200 OK. application/json: Host Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "name": "Build server",
  "state": "active",
  "platform": "linux",
  "assigned_user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "llm_credentials": "organization",
  "declared_server_host": false,
  "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
  "key_generation": 1,
  "profiles": [
    {
      "name": "shell",
      "display_name": "Shell",
      "kind": "shell"
    },
    {
      "name": "claude",
      "display_name": "Claude Code",
      "kind": "claude"
    }
  ],
  "doctor": [
    {
      "check": "hd1_user",
      "ok": true
    }
  ],
  "session_users": [
    {
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "os_user": "bothy-s-robin",
      "created_at": "2026-10-10T09:42:00.000Z"
    }
  ],
  "reported_session_users": [
    {
      "os_user": "bothy-s-robin",
      "workdirs": [
        "Project A"
      ]
    }
  ],
  "connected": true,
  "host_version": "1.0.0",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3
}

issueHostPairingCode

POST /hosts/{host_id}/pairing-code

Issue a new pairing code (re-pairing)

Sets the host to pairing from pairing, confirming, active or disabled (also duplicate_connection, whose reason is cleared); retired gives 409 invalid_state_transition. From confirming, active and disabled it drops the stored keys at once; from active it ends the sessions (host_rekeyed) and closes the connections. Every owner gets host.updated, with key_changed exactly when stored keys were dropped (24, 3.3); key_generation rises at the next pairHost. A repeated call issues another code and invalidates the previous one. Needs step-up. The code is a one-time secret: a replay with the same Idempotency-Key answers 409 conflict with reason one_time_secret instead of repeating it (06, 7).

Parameters:

Name In Type Required Description
host_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Host reinstalled"
}

Responses:

Status Description Content Headers
201 Created. application/json: HostPairingCode Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
422 UnprocessableEntity: Problem codes: idempotency_key_reuse. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "host_id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "pairing_code": "bothy_hpc_EXAMPLE000000000000000000000000000000000000_EXAMPL",
  "expires_at": "2026-10-10T09:45:00.000Z"
}

confirmHost

POST /hosts/{host_id}/confirm

Confirm the fingerprint and declare the LLM login

The owner types the first terminal.fingerprint_confirm_chars characters shown by bothy-host pair, without separators, case-insensitive; a prefix of another length or with a character outside the Crockford alphabet (also I, L, O, U) gives 400 validation_failed with errors[].code invalid_format and does not count. A mismatch gives 409 fingerprint_mismatch with attempts_remaining; the failure counter is not part of Host, so version and the If-Match stay. After terminal.fingerprint_max_attempts failures the host falls back to pairing without keys (attempts_remaining 0), and a new pairing code is needed. A failed attempt counts also under an Idempotency-Key; its replay returns the stored 409. I6 is checked in the same transaction (409 i6_violation). session_users assigns each person their own session user on this host (ruling T12, 24 section 2.2); a name that belongs or belonged to another person on this host, or a second valid assignment of one person, gives 409 conflict with reason: session_user_taken; a name the host did not report (reported_session_users) gives 400 validation_failed with errors[].code session_user_not_on_host, and nothing is stored. Without an assignment a person gets no terminal there (SR12). Needs step-up.

Parameters:

Name In Type Required Description
host_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: HostConfirm

Request
{
  "fingerprint_prefix": "7K2QM9XD",
  "llm_credentials": "organization",
  "declared_server_host": false,
  "session_users": [
    {
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "os_user": "bothy-s-robin"
    }
  ],
  "reason": "Build machine of the engineering team"
}

Responses:

Status Description Content Headers
200 OK. application/json: Host Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "name": "Build server",
  "state": "active",
  "platform": "linux",
  "assigned_user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "llm_credentials": "organization",
  "declared_server_host": false,
  "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
  "key_generation": 1,
  "profiles": [
    {
      "name": "shell",
      "display_name": "Shell",
      "kind": "shell"
    },
    {
      "name": "claude",
      "display_name": "Claude Code",
      "kind": "claude"
    }
  ],
  "doctor": [
    {
      "check": "hd1_user",
      "ok": true
    }
  ],
  "session_users": [
    {
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "os_user": "bothy-s-robin",
      "created_at": "2026-10-10T09:42:00.000Z"
    }
  ],
  "reported_session_users": [
    {
      "os_user": "bothy-s-robin",
      "workdirs": [
        "Project A"
      ]
    }
  ],
  "connected": true,
  "host_version": "1.0.0",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3
}

setHostLlmCredentials

PUT /hosts/{host_id}/llm-credentials

Declare the LLM login of a host

personal needs credential_holder_id, a person that is not deleted; none and organization take none. Fails with 409 i6_violation (member conflicts, one entry per host) if any valid grant on the host names another subject than the holder or a group; switching to personal or changing the holder ends the sessions of other people in the same transaction (close_reason i6_violation, 24, 7.3). A retired host answers 409 conflict. The declaration the host already has answers 200 with the current host, without a new version, an event or a new rights version (audited with no_change). Needs step-up and the mandatory reason.

Parameters:

Name In Type Required Description
host_id path Uuid yes
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: HostLlmCredentialsSet

Request
{
  "llm_credentials": "personal",
  "credential_holder_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "reason": "Alex uses the own subscription on this laptop"
}

Responses:

Status Description Content Headers
200 OK. application/json: Host Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "name": "Build server",
  "state": "active",
  "platform": "linux",
  "assigned_user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "llm_credentials": "organization",
  "declared_server_host": false,
  "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
  "key_generation": 1,
  "profiles": [
    {
      "name": "shell",
      "display_name": "Shell",
      "kind": "shell"
    },
    {
      "name": "claude",
      "display_name": "Claude Code",
      "kind": "claude"
    }
  ],
  "doctor": [
    {
      "check": "hd1_user",
      "ok": true
    }
  ],
  "session_users": [
    {
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "os_user": "bothy-s-robin",
      "created_at": "2026-10-10T09:42:00.000Z"
    }
  ],
  "reported_session_users": [
    {
      "os_user": "bothy-s-robin",
      "workdirs": [
        "Project A"
      ]
    }
  ],
  "connected": true,
  "host_version": "1.0.0",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3
}

setHostState

POST /hosts/{host_id}/state

Disable, enable or retire a host

disabled and retired end all sessions (host_disabled, host_retired) and close the connections of the host service. retired is final. Needs step-up.

Parameters:

Name In Type Required Description
host_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.
If-Match header string yes ETag of the version the change is based on, e.g. "7". Mismatch gives 412 version_conflict. Example: "7".

Request body (required): application/json: HostStateSet

Request
{
  "state": "disabled",
  "reason": "Machine sent for repair"
}

Responses:

Status Description Content Headers
200 OK. application/json: Host Correlation-Id, RateLimit, RateLimit-Policy, ETag
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
412 PreconditionFailed: Problem codes: version_conflict. application/problem+json: Problem Correlation-Id
428 PreconditionRequired: Problem codes: precondition_required. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "name": "Build server",
  "state": "active",
  "platform": "linux",
  "assigned_user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "llm_credentials": "organization",
  "declared_server_host": false,
  "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
  "key_generation": 1,
  "profiles": [
    {
      "name": "shell",
      "display_name": "Shell",
      "kind": "shell"
    },
    {
      "name": "claude",
      "display_name": "Claude Code",
      "kind": "claude"
    }
  ],
  "doctor": [
    {
      "check": "hd1_user",
      "ok": true
    }
  ],
  "session_users": [
    {
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "os_user": "bothy-s-robin",
      "created_at": "2026-10-10T09:42:00.000Z"
    }
  ],
  "reported_session_users": [
    {
      "os_user": "bothy-s-robin",
      "workdirs": [
        "Project A"
      ]
    }
  ],
  "connected": true,
  "host_version": "1.0.0",
  "created_at": "2026-10-10T09:30:00.000Z",
  "version": 3
}

Terminal

Terminal sessions on connected hosts; the stream itself is end-to-end encrypted and runs over the channels in asyncapi.yaml.

openTerminalSession

POST /hosts/{host_id}/terminal/sessions

Open a terminal session

Needs a fresh, unused step-up (passkey or step-up device key; in the console only a passkey with userVerification = required), the terminal capability, SR10, SR11 (I6) and SR12 (an own session user on the host whose name the host reports, otherwise 403 terminal_denied with reason: no_session_user). With a claude profile workdir_index must point into the caller's own working directories (ruling T13). Consumes the step-up and returns a one-time session token for the Noise handshake (24, 5 and 6.1). The device then connects to stream_path.

Parameters:

Name In Type Required Description
host_id path Uuid yes

Request body (required): application/json: TerminalSessionOpen

Request
{
  "profile": "shell",
  "cols": 120,
  "rows": 40,
  "client_ephemeral_key_hash": "EXAMPLE-sha256-of-ephemeral-key-base64url00"
}

Responses:

Status Description Content Headers
201 Created. application/json: TerminalSessionGrant Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "session": {
    "id": "0192f4a0-7b1c-7b22-9d4f-5a6b7c8d9e0f",
    "host_id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "profile": "shell",
    "state": "active",
    "opened_at": "2026-10-10T09:31:00.000Z",
    "started_at": "2026-10-10T09:31:01.000Z",
    "bytes_in": 4096,
    "bytes_out": 65536,
    "version": 2
  },
  "session_token": "eyJhbGciOiJFZERTQSIsImtpZCI6InRlcm0tMjAyNi0xMCIsInR5cCI6InRlcm1pbmFsLXNlc3Npb24rand0In0.EXAMPLE.EXAMPLE",
  "session_token_expires_at": "2026-10-10T09:31:30.000Z",
  "stream_path": "/api/v1/terminal/sessions/0192f4a0-7b1c-7b22-9d4f-5a6b7c8d9e0f/stream",
  "noise_public_key": "Zm9vYmFyZm9vYmFyZm9vYmFyZm9vYmFyZm9vYmFyMTI",
  "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
  "key_generation": 1,
  "noise_protocol": "Noise_NK_25519_ChaChaPoly_SHA256",
  "prologue_version": "bothy-terminal/1"
}

listTerminalSessions

GET /terminal/sessions

List terminal sessions

Own sessions; owners see all sessions. Metadata only, never content.

Parameters:

Name In Type Required Description
cursor query Cursor no Cursor from next_cursor of the previous page.
limit query PageLimit no
host_id query Uuid no Only sessions on this host.
state query TerminalSessionState no Only sessions in this state; without it, all states.

Responses:

Status Description Content Headers
200 OK. application/json: TerminalSessionPage Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "items": [
    {
      "id": "0192f4a0-7b1c-7b22-9d4f-5a6b7c8d9e0f",
      "host_id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
      "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
      "profile": "shell",
      "state": "active",
      "opened_at": "2026-10-10T09:31:00.000Z",
      "started_at": "2026-10-10T09:31:01.000Z",
      "bytes_in": 4096,
      "bytes_out": 65536,
      "version": 2
    }
  ]
}

getTerminalSession

GET /terminal/sessions/{session_id}

Read a terminal session

Parameters:

Name In Type Required Description
session_id path Uuid yes

Responses:

Status Description Content Headers
200 OK. application/json: TerminalSession Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7b22-9d4f-5a6b7c8d9e0f",
  "host_id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
  "profile": "shell",
  "state": "active",
  "opened_at": "2026-10-10T09:31:00.000Z",
  "started_at": "2026-10-10T09:31:01.000Z",
  "bytes_in": 4096,
  "bytes_out": 65536,
  "version": 2
}

attachTerminalSession

POST /terminal/sessions/{session_id}/attach

Attach to an own session again

For a session in state opening, active or detached. Needs a fresh step-up, except from the same device in the same login session within terminal.quick_reattach_window after the disconnect. Returns a new session token; older tokens become worthless. A connection of another device is closed with 4103 (24, 6.2). An attach to an opening session restarts the opening (att = open, new deadline).

Parameters:

Name In Type Required Description
session_id path Uuid yes

Request body (required): application/json: TerminalSessionAttach

Request
{
  "cols": 120,
  "rows": 40,
  "client_ephemeral_key_hash": "EXAMPLE-sha256-of-ephemeral-key-base64url00"
}

Responses:

Status Description Content Headers
200 OK. application/json: TerminalSessionGrant Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "session": {
    "id": "0192f4a0-7b1c-7b22-9d4f-5a6b7c8d9e0f",
    "host_id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
    "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
    "profile": "shell",
    "state": "active",
    "opened_at": "2026-10-10T09:31:00.000Z",
    "started_at": "2026-10-10T09:31:01.000Z",
    "bytes_in": 4096,
    "bytes_out": 65536,
    "version": 2
  },
  "session_token": "eyJhbGciOiJFZERTQSIsImtpZCI6InRlcm0tMjAyNi0xMCIsInR5cCI6InRlcm1pbmFsLXNlc3Npb24rand0In0.EXAMPLE.EXAMPLE",
  "session_token_expires_at": "2026-10-10T09:31:30.000Z",
  "stream_path": "/api/v1/terminal/sessions/0192f4a0-7b1c-7b22-9d4f-5a6b7c8d9e0f/stream",
  "noise_public_key": "Zm9vYmFyZm9vYmFyZm9vYmFyZm9vYmFyZm9vYmFyMTI",
  "key_fingerprint": "7K2Q-M9XD-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000-0000",
  "key_generation": 1,
  "noise_protocol": "Noise_NK_25519_ChaChaPoly_SHA256",
  "prologue_version": "bothy-terminal/1"
}

closeTerminalSession

POST /terminal/sessions/{session_id}/close

End a terminal session

Own sessions; owners any session (closed_by_owner). The server closes both connections and tells the host service to end the PTY.

Parameters:

Name In Type Required Description
session_id path Uuid yes
Idempotency-Key header Uuid no UUIDv7 chosen by the client per logical operation. A repeat with the same request returns the stored response; a different request gives 422 idempotency_key_reuse; a repeat while the first is running gives 409 request_in_progress. Kept for sync.idempotency_key_ttl.

Request body (required): application/json: ReasonBody

Request
{
  "reason": "Done"
}

Responses:

Status Description Content Headers
200 OK. application/json: TerminalSession Correlation-Id, RateLimit, RateLimit-Policy
400 BadRequest: Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed. application/problem+json: Problem Correlation-Id
401 Unauthorized: Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof. application/problem+json: Problem Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce
403 Forbidden: Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied. application/problem+json: Problem Correlation-Id
404 NotFound: Problem codes: not_found. application/problem+json: Problem Correlation-Id
409 Conflict: Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch. application/problem+json: Problem Correlation-Id
429 TooManyRequests: Problem codes: rate_limited. application/problem+json: Problem Correlation-Id, Retry-After, RateLimit, RateLimit-Policy
default Error: Any other error, e.g. internal_error (500). application/problem+json: Problem Correlation-Id
Response
{
  "id": "0192f4a0-7b1c-7b22-9d4f-5a6b7c8d9e0f",
  "host_id": "0192f4a0-7b1c-7a11-8c3e-4f5a6b7c8d9e",
  "user_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
  "device_id": "0192f4a0-7b1c-7848-8501-1716705c7dbe",
  "profile": "shell",
  "state": "closed",
  "opened_at": "2026-10-10T09:31:00.000Z",
  "started_at": "2026-10-10T09:31:01.000Z",
  "bytes_in": 4096,
  "bytes_out": 65536,
  "version": 2,
  "closed_at": "2026-10-10T10:00:00.000Z",
  "close_reason": "client_closed"
}

Webhook events

Requests the server sends to subscribed endpoints. Delivery, the signature headers, retries and the receiver checks: webhooks; the envelope fields are those of the event schemas below.

onMessageCreatedEvent

POST webhook message.created

Event message.created

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: message.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: MessageCreatedEvent

message.created
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "message",
    "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "message.created",
  "payload": {
    "message": {
      "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "thread_seq": 42,
      "author": {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "kind": "user",
        "handle": "alex",
        "display_name": "Alex"
      },
      "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
      "origin": "human",
      "kind": "text",
      "content_md": "@support-agent the invoice export fails since this morning.",
      "content_format": 1,
      "silent": false,
      "attachments": [
        {
          "position": 1,
          "file": {
            "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
            "size_bytes": 48213,
            "mime_type": "image/png",
            "original_name": "screenshot.png",
            "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
            "purpose": "attachment",
            "upload_state": "complete",
            "scan_status": "clean",
            "transcript_status": "none",
            "thumbnails": [
              {
                "variant": "small",
                "mime_type": "image/jpeg",
                "width": 320,
                "height": 180
              }
            ],
            "created_at": "2026-10-10T09:30:00.000Z"
          }
        }
      ],
      "mention_ids": [
        "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
      ],
      "reactions": [
        {
          "emoji": "👍",
          "count": 3
        }
      ],
      "pinned": false,
      "components": [
        {
          "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
          "custom_id": "approve-refund",
          "type": "button",
          "definition": {},
          "position": 1,
          "single_use": true,
          "restricted_to": "any",
          "state": "active",
          "version": 3
        }
      ],
      "version": 3,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onMessageUpdatedEvent

POST webhook message.updated

Event message.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: message.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: MessageUpdatedEvent

message.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "message",
    "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "message.updated",
  "payload": {
    "message": {
      "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "thread_seq": 42,
      "author": {
        "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
        "kind": "user",
        "handle": "alex",
        "display_name": "Alex"
      },
      "client_msg_id": "0192f4a0-7b1c-7f4e-8959-c3574b6ad93b",
      "origin": "human",
      "kind": "text",
      "content_md": "@support-agent the invoice export fails since this morning.",
      "content_format": 1,
      "silent": false,
      "attachments": [
        {
          "position": 1,
          "file": {
            "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
            "size_bytes": 48213,
            "mime_type": "image/png",
            "original_name": "screenshot.png",
            "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
            "purpose": "attachment",
            "upload_state": "complete",
            "scan_status": "clean",
            "transcript_status": "none",
            "thumbnails": [
              {
                "variant": "small",
                "mime_type": "image/jpeg",
                "width": 320,
                "height": 180
              }
            ],
            "created_at": "2026-10-10T09:30:00.000Z"
          }
        }
      ],
      "mention_ids": [
        "0192f4a0-7b1c-718f-86e7-9cb8b914b848"
      ],
      "reactions": [
        {
          "emoji": "👍",
          "count": 3
        }
      ],
      "pinned": false,
      "components": [
        {
          "id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
          "custom_id": "approve-refund",
          "type": "button",
          "definition": {},
          "position": 1,
          "single_use": true,
          "restricted_to": "any",
          "state": "active",
          "version": 3
        }
      ],
      "version": 3,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onMessageDeletedEvent

POST webhook message.deleted

Event message.deleted

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: message.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: MessageDeletedEvent

message.deleted
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "message",
    "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
    "version": 4
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "message.deleted",
  "payload": {
    "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "thread_seq": 5301,
    "deleted_at": "2026-10-10T09:30:00.000Z"
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onReactionAddedEvent

POST webhook reaction.added

Event reaction.added

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: message.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ReactionAddedEvent

reaction.added
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "message",
    "id": "0192f4a0-7b1c-7353-8d8c-dea659467151"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "reaction.added",
  "payload": {
    "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "emoji": "👍",
    "principal_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "count": 1
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onReactionRemovedEvent

POST webhook reaction.removed

Event reaction.removed

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: message.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ReactionRemovedEvent

reaction.removed
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "message",
    "id": "0192f4a0-7b1c-7353-8d8c-dea659467151"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "reaction.removed",
  "payload": {
    "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "emoji": "👍",
    "principal_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
    "count": 1
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onPinAddedEvent

POST webhook pin.added

Event pin.added

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: thread.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: PinAddedEvent

pin.added
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "message",
    "id": "0192f4a0-7b1c-7353-8d8c-dea659467151"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "pin.added",
  "payload": {
    "pin": {
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "pinned_by": "0192f4a0-7b1c-72de-8fae-dfbd3e36ff9a",
      "pinned_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onPinRemovedEvent

POST webhook pin.removed

Event pin.removed

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: thread.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: PinRemovedEvent

pin.removed
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "message",
    "id": "0192f4a0-7b1c-7353-8d8c-dea659467151"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "pin.removed",
  "payload": {
    "pin": {
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "pinned_by": "0192f4a0-7b1c-72de-8fae-dfbd3e36ff9a",
      "pinned_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onThreadCreatedEvent

POST webhook thread.created

Event thread.created

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: thread.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ThreadCreatedEvent

thread.created
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "thread",
    "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "thread.created",
  "payload": {
    "thread": {
      "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "thread",
      "title": "Invoice export fails",
      "title_source": "auto",
      "state": "open",
      "last_message_seq": 5301,
      "last_activity_at": "2026-10-10T09:30:00.000Z",
      "message_count": 1,
      "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3,
      "tag_ids": [
        "0192f4a0-7b1c-712d-8017-1dad64203598"
      ]
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onThreadUpdatedEvent

POST webhook thread.updated

Event thread.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: thread.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ThreadUpdatedEvent

thread.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "thread",
    "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "thread.updated",
  "payload": {
    "thread": {
      "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "thread",
      "title": "Invoice export fails",
      "title_source": "auto",
      "state": "open",
      "last_message_seq": 5301,
      "last_activity_at": "2026-10-10T09:30:00.000Z",
      "message_count": 1,
      "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3,
      "tag_ids": [
        "0192f4a0-7b1c-712d-8017-1dad64203598"
      ]
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onThreadClosedEvent

POST webhook thread.closed

Event thread.closed

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: thread.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ThreadClosedEvent

thread.closed
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "thread",
    "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "thread.closed",
  "payload": {
    "thread": {
      "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "thread",
      "title": "Invoice export fails",
      "title_source": "auto",
      "state": "open",
      "last_message_seq": 5301,
      "last_activity_at": "2026-10-10T09:30:00.000Z",
      "message_count": 1,
      "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3,
      "tag_ids": [
        "0192f4a0-7b1c-712d-8017-1dad64203598"
      ]
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onThreadReopenedEvent

POST webhook thread.reopened

Event thread.reopened

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: thread.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ThreadReopenedEvent

thread.reopened
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "thread",
    "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "thread.reopened",
  "payload": {
    "thread": {
      "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "thread",
      "title": "Invoice export fails",
      "title_source": "auto",
      "state": "open",
      "last_message_seq": 5301,
      "last_activity_at": "2026-10-10T09:30:00.000Z",
      "message_count": 1,
      "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3,
      "tag_ids": [
        "0192f4a0-7b1c-712d-8017-1dad64203598"
      ]
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onThreadMovedEvent

POST webhook thread.moved

Event thread.moved

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: thread.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ThreadMovedEvent

thread.moved
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "thread",
    "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "thread.moved",
  "payload": {
    "thread": {
      "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "thread",
      "title": "Invoice export fails",
      "title_source": "auto",
      "state": "open",
      "last_message_seq": 5301,
      "last_activity_at": "2026-10-10T09:30:00.000Z",
      "message_count": 1,
      "created_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3,
      "moved_at": "2026-10-10T09:30:00.000Z",
      "tag_ids": []
    },
    "from_channel_id": "0192f4a0-7b1c-745e-8621-aacfb6cd0aad"
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onThreadMovedOutEvent

POST webhook thread.moved_out

Event thread.moved_out

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: channel.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ThreadMovedOutEvent

thread.moved_out
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  },
  "resource": {
    "kind": "channel",
    "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "thread.moved_out",
  "payload": {
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onAgentSessionChangedEvent

POST webhook agent_session.changed

Event agent_session.changed

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: thread.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: AgentSessionChangedEvent

agent_session.changed
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "thread",
    "id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "agent_session.changed",
  "payload": {
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
    "agent_session": {
      "id": "0192f4a0-7b1c-741b-8617-885056753dc0",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "is_current": true,
      "started": true,
      "cost": {
        "amount_micros": 1250000,
        "currency": "USD",
        "is_estimate": true
      },
      "created_at": "2026-10-10T09:30:00.000Z",
      "version": 3
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onRunStateChangedEvent

POST webhook run.state_changed

Event run.state_changed

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: run.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: RunStateChangedEvent

run.state_changed
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "run",
    "id": "0192f4a0-7b1c-767f-8292-c1b14d7d40df",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "run.state_changed",
  "payload": {
    "run": {
      "id": "0192f4a0-7b1c-767f-8292-c1b14d7d40df",
      "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
      "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "agent_id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "triggered_by": "0192f4a0-7b1c-7db7-8afc-99f48568ad99",
      "state": "queued",
      "version": 3,
      "billing_mode_expected": "personal",
      "cost": {
        "amount_micros": 1250000,
        "currency": "USD",
        "is_estimate": true
      },
      "step_count": 1,
      "queued_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onSpaceCreatedEvent

POST webhook space.created

Event space.created

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: space.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: SpaceCreatedEvent

space.created
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14"
  },
  "resource": {
    "kind": "space",
    "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "space.created",
  "payload": {
    "space": {
      "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
      "name": "Support",
      "sort_key": "a0",
      "version": 3,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onSpaceUpdatedEvent

POST webhook space.updated

Event space.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: space.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: SpaceUpdatedEvent

space.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14"
  },
  "resource": {
    "kind": "space",
    "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "space.updated",
  "payload": {
    "space": {
      "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
      "name": "Support",
      "sort_key": "a0",
      "version": 3,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onSpaceArchivedEvent

POST webhook space.archived

Event space.archived

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: space.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: SpaceArchivedEvent

space.archived
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14"
  },
  "resource": {
    "kind": "space",
    "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "space.archived",
  "payload": {
    "space": {
      "id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
      "name": "Support",
      "sort_key": "a0",
      "version": 3,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onChannelCreatedEvent

POST webhook channel.created

Event channel.created

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: channel.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ChannelCreatedEvent

channel.created
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  },
  "resource": {
    "kind": "channel",
    "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "channel.created",
  "payload": {
    "channel": {
      "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "text",
      "name": "tickets",
      "topic": "Customer tickets",
      "sort_key": "a1",
      "read_only": false,
      "operator": {
        "mode": "inherit"
      },
      "version": 3,
      "settings_version": 1,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onChannelUpdatedEvent

POST webhook channel.updated

Event channel.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: channel.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ChannelUpdatedEvent

channel.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  },
  "resource": {
    "kind": "channel",
    "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "channel.updated",
  "payload": {
    "channel": {
      "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "text",
      "name": "tickets",
      "topic": "Customer tickets",
      "sort_key": "a1",
      "read_only": false,
      "operator": {
        "mode": "inherit"
      },
      "version": 3,
      "settings_version": 1,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onChannelSettingsChangedEvent

POST webhook channel.settings_changed

Event channel.settings_changed

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: channel.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ChannelSettingsChangedEvent

channel.settings_changed
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  },
  "resource": {
    "kind": "channel",
    "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "channel.settings_changed",
  "payload": {
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "settings_version": 1
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onChannelArchivedEvent

POST webhook channel.archived

Event channel.archived

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: channel.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: ChannelArchivedEvent

channel.archived
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  },
  "resource": {
    "kind": "channel",
    "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "channel.archived",
  "payload": {
    "channel": {
      "id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
      "kind": "text",
      "name": "tickets",
      "topic": "Customer tickets",
      "sort_key": "a1",
      "read_only": false,
      "operator": {
        "mode": "inherit"
      },
      "version": 3,
      "settings_version": 1,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onCommandChangedEvent

POST webhook command.changed

Event command.changed

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: command.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: CommandChangedEvent

command.changed
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {},
  "resource": {
    "kind": "command",
    "id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "command.changed",
  "payload": {
    "command": {
      "id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa",
      "owner_principal_id": "0192f4a0-7b1c-7176-8de0-ddf186d11091",
      "name": "escalate",
      "description": "Escalate the ticket to second level",
      "scope_kind": "instance",
      "options": [
        {
          "name": "ticket",
          "description": "Ticket number",
          "type": "string",
          "required": true
        }
      ],
      "required_level": "write",
      "control": false,
      "version": 3
    },
    "change": "registered"
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onFileUpdatedEvent

POST webhook file.updated

Event file.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: file.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: FileUpdatedEvent

file.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {},
  "resource": {
    "kind": "file",
    "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "file.updated",
  "payload": {
    "file": {
      "id": "0192f4a0-7b1c-75c7-88f6-199cc394b56a",
      "size_bytes": 48213,
      "mime_type": "image/png",
      "original_name": "screenshot.png",
      "uploaded_by": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "purpose": "attachment",
      "upload_state": "complete",
      "scan_status": "clean",
      "transcript_status": "none",
      "thumbnails": [
        {
          "variant": "small",
          "mime_type": "image/jpeg",
          "width": 320,
          "height": 180
        }
      ],
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onUserUpdatedEvent

POST webhook user.updated

Event user.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: user.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: UserUpdatedEvent

user.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {},
  "resource": {
    "kind": "user",
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "user.updated",
  "payload": {
    "user": {
      "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "handle": "sam",
      "display_name": "Sam",
      "status": "active",
      "is_owner": false,
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onAgentUpdatedEvent

POST webhook agent.updated

Event agent.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: agent.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: AgentUpdatedEvent

agent.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {},
  "resource": {
    "kind": "agent",
    "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
    "version": 3
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "agent.updated",
  "payload": {
    "agent": {
      "id": "0192f4a0-7b1c-7d07-84b0-358556a08a99",
      "handle": "support-agent",
      "display_name": "Support Agent",
      "status": "active",
      "adapter_kind": "hermes",
      "tool_class": "chat",
      "description": "Answers support tickets",
      "billing_mode": "personal",
      "presence": {
        "state": "unknown"
      },
      "operator_config": {},
      "version": 3
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onInstanceUpdatedEvent

POST webhook instance.updated

Event instance.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: instance.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: InstanceUpdatedEvent

instance.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {},
  "resource": {
    "kind": "instance"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "instance.updated",
  "payload": {
    "changed_keys": [
      "branding.product_name"
    ]
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onStatusUpdatedEvent

POST webhook status.updated

Event status.updated

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: status.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: StatusUpdatedEvent

status.updated
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {},
  "resource": {
    "kind": "instance"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "status.updated",
  "payload": {
    "overall_state": "operational"
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onAccessChangedEvent

POST webhook access.changed

Event access.changed

Only for the subscribing app itself.

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: self

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: AccessChangedEvent

access.changed
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "audience": "self",
  "scope": {},
  "resource": {
    "kind": "principal",
    "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "access.changed",
  "payload": {
    "permission_version": 418,
    "added": [
      {
        "kind": "space",
        "id": "0192f4a0-7b1c-7835-8fba-fdbdfb6d3b85"
      }
    ],
    "removed": [
      {
        "kind": "space",
        "id": "0192f4a0-7b1c-7835-8fba-fdbdfb6d3b85"
      }
    ],
    "changed": [
      {
        "kind": "space",
        "id": "0192f4a0-7b1c-7835-8fba-fdbdfb6d3b85"
      }
    ]
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onAgentInvocationEvent

POST webhook agent.invocation

Event agent.invocation

Only for webhook subscriptions of the agent itself (webhook as agent transport, docs/spec/04-sync-protocol.md section 15.6). Carries a freshly issued invocation token in the delivery fields.

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: agent.events.consume

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: AgentInvocationEvent

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status acknowledges every event up to this seq.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries this event with backoff and sends nothing newer before it succeeds.

onAgentFollowupEvent

POST webhook agent.followup

Event agent.followup

Only for webhook subscriptions of the agent itself (webhook as agent transport, docs/spec/04-sync-protocol.md section 15.6). Carries a freshly issued invocation token in the delivery fields.

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: agent.events.consume

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: AgentFollowupEvent

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status acknowledges every event up to this seq.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries this event with backoff and sends nothing newer before it succeeds.

onRunCancelRequestedEvent

POST webhook run.cancel_requested

Event run.cancel_requested

Only for webhook subscriptions of the agent itself (webhook as agent transport, docs/spec/04-sync-protocol.md section 15.6). Carries a freshly issued invocation token in the delivery fields.

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: agent.events.consume

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: RunCancelRequestedEvent

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status acknowledges every event up to this seq.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries this event with backoff and sends nothing newer before it succeeds.

onAgentConfigChangedEvent

POST webhook agent.config_changed

Event agent.config_changed

Only for webhook subscriptions of the agent itself (webhook as agent transport, docs/spec/04-sync-protocol.md section 15.6). Carries a freshly issued invocation token in the delivery fields.

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: agent.config.read

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: AgentConfigChangedEvent

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status acknowledges every event up to this seq.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries this event with backoff and sends nothing newer before it succeeds.

onInteractionCreatedEvent

POST webhook interaction.created

Event interaction.created

Only for the subscribing app itself.

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: agent.events.consume

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: InteractionCreatedEvent

interaction.created
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "thread_id": "0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
  },
  "resource": {
    "kind": "interaction",
    "id": "0192f4a0-7b1c-77f5-8fe4-151103a7b8b5"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "interaction.created",
  "payload": {
    "interaction": {
      "id": "0192f4a0-7b1c-77f5-8fe4-151103a7b8b5",
      "component_id": "0192f4a0-7b1c-7080-8a1e-eb7183f5a9a2",
      "message_id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
      "principal_id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "client_interaction_id": "0192f4a0-7b1c-704d-8f46-22a420803f92",
      "values": {},
      "state": "received",
      "created_at": "2026-10-10T09:30:00.000Z"
    }
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

onCommandInvokedEvent

POST webhook command.invoked

Event command.invoked

Only for the subscribing app itself.

  • Security: none
  • x-authz-action: webhook_out.deliver
  • x-rate-limit-class: none
  • x-receive-action: agent.events.consume

Parameters:

Name In Type Required Description
webhook-id header Uuid yes Event ID; stable across retries, use it to deduplicate.
webhook-timestamp header integer (int64) yes Unix seconds of this attempt. Reject values outside webhook.receiver_tolerance.
webhook-signature header string yes Space-separated signatures v1a,<base64> (Ed25519) and, if enabled, v1,<base64> (HMAC-SHA256) over {webhook-id}.{webhook-timestamp}.{body}.

Request body (required): application/json: CommandInvokedEvent

command.invoked
{
  "id": "0192f4a0-7b1c-7ff0-88b6-7d3b051173dd",
  "seq": 5301,
  "schema_version": 1,
  "occurred_at": "2026-10-10T09:30:00.000Z",
  "permission_version": 418,
  "scope": {
    "space_id": "0192f4a0-7b1c-7881-8522-0a58634abc14",
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203"
  },
  "resource": {
    "kind": "command",
    "id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa"
  },
  "sync_epoch": "0192f4a0-7b1c-7a3e-8c41-5d2e9b7f1a60",
  "type": "command.invoked",
  "payload": {
    "invocation_id": "0192f4a0-7b1c-712e-8ccb-17c85f8d11c9",
    "command_id": "0192f4a0-7b1c-7beb-80fc-f336f4fe79aa",
    "command_name": "escalate",
    "control": false,
    "channel_id": "0192f4a0-7b1c-72d4-8bae-7661d2b2f203",
    "invoked_by": {
      "id": "0192f4a0-7b1c-7f89-8d6b-6960453241bc",
      "kind": "user",
      "handle": "alex",
      "display_name": "Alex"
    },
    "options": [
      {
        "name": "ticket",
        "value": "4711"
      }
    ]
  }
}

Responses:

Status Description Content Headers
204 Accepted. Any 2xx status counts as success.
410 The receiver gave up the endpoint; the server disables the subscription.
429 The server slows down and honors Retry-After; same for 502, 503 and 504.
default Failure; the server retries with backoff (docs/api/webhooks.md).

Security schemes

dpopAuth

  • type: http
  • scheme: DPoP

Access token of a person, bound to the device key (RFC 9449). Send Authorization: DPoP <token> and a DPoP proof header with htm, htu, iat, jti, ath and the latest server nonce. Also used by API tokens that were created with dpop_jkt. Inside a run an agent also sends the header Invocation-Token (#/components/parameters/InvocationToken, 07 guard rule SR9).

bearerAuth

  • type: http
  • scheme: bearer

API token of an agent, app or personal tool without key binding (Authorization: Bearer <token>). On postIncomingWebhookWithBearer only, the token of an incoming webhook (bothy_whi_...) instead. Inside a run an agent also sends the header Invocation-Token (#/components/parameters/InvocationToken, 07 guard rule SR9).

consoleSession

  • type: apiKey
  • in: cookie
  • name: __Host-console_session

Web console cookie; CSRF header ConsoleRequest and own Origin on writes (08, 7.5).

fileTicket

  • type: apiKey
  • in: query
  • name: ticket

Short-lived fetch ticket from createFileTicket for media players that cannot send a DPoP proof (12, 9.2; ADR 0048). Only downloadFile and downloadThumbnail accept it; every fetch checks signature, expiry, session and file.read, and any failure gives 404.

pushPreviewToken

  • type: http
  • scheme: DPoP

Preview token of a push registration (bothy_pvw_..., issued once by registerPush) with a DPoP proof of the device key of the registration's session, ath over the preview token (13, 6.4; R-PN-07). Only getPushPreview accepts it; it has no refresh and ends with its registration, its session, its device or its person.

Shared responses

BadRequest

Problem codes: validation_failed, malformed_request, cursor_invalid, webhook_host_not_allowed.

  • x-status: 400

Content: application/problem+json: Problem

Headers: Correlation-Id

Validation failed
{
  "type": "/api/v1/problems/validation_failed",
  "title": "Validation failed",
  "status": 400,
  "code": "validation_failed",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "errors": [
    {
      "pointer": "/content_md",
      "code": "too_long",
      "detail": "Longer than `message.max_content_bytes`."
    }
  ]
}

ConsoleLogin

Console session (08, 7.5).

  • x-status: 200

Content: application/json: ConsoleSession

Headers: Correlation-Id, Set-Cookie

StepUpDone

OK; a console session gets a new cookie (08, 7.5).

  • x-status: 200

Content: application/json: StepUpResult

Headers: Correlation-Id, Set-Cookie

Unauthorized

Problem codes: unauthenticated, token_expired, session_revoked, step_up_required, use_dpop_nonce, invalid_dpop_proof.

  • x-status: 401

Content: application/problem+json: Problem

Headers: Correlation-Id, Set-Cookie, WWW-Authenticate, DPoP-Nonce

Unauthenticated
{
  "type": "/api/v1/problems/unauthenticated",
  "title": "Unauthenticated",
  "status": 401,
  "code": "unauthenticated",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

Forbidden

Problem codes: forbidden, scope_missing, device_pending, channel_read_only, feature_disabled, agent_invocation_denied, invocation_token_invalid, terminal_denied.

  • x-status: 403

Content: application/problem+json: Problem

Headers: Correlation-Id

Forbidden
{
  "type": "/api/v1/problems/forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "forbidden",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

NotFound

Problem codes: not_found.

  • x-status: 404

Content: application/problem+json: Problem

Headers: Correlation-Id

Not found
{
  "type": "/api/v1/problems/not_found",
  "title": "Not found",
  "status": 404,
  "code": "not_found",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

Conflict

Problem codes: conflict, request_in_progress, i1_violation, i6_violation, last_owner, already_started, billing_mode_mismatch, tool_class_mismatch, invalid_state_transition, base_version_conflict, component_used, operator_mismatch, file_not_ready, file_blocked, title_manual, host_unavailable, fingerprint_mismatch.

  • x-status: 409

Content: application/problem+json: Problem

Headers: Correlation-Id

Conflict
{
  "type": "/api/v1/problems/conflict",
  "title": "Conflict",
  "status": 409,
  "code": "conflict",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

FileConflict

Problem codes: file_not_ready, file_blocked.

  • x-status: 409

Content: application/problem+json: Problem

Headers: Correlation-Id, Retry-After

File not ready
{
  "type": "/api/v1/problems/file_not_ready",
  "title": "File not ready",
  "status": 409,
  "code": "file_not_ready",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/files/0192f4a0-7b1c-75c7-88f6-199cc394b56a/content"
}

Gone

Problem codes: resync_required, message_deleted, gone.

  • x-status: 410

Content: application/problem+json: Problem

Headers: Correlation-Id

Gone
{
  "type": "/api/v1/problems/gone",
  "title": "Gone",
  "status": 410,
  "code": "gone",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

PreconditionFailed

Problem codes: version_conflict.

  • x-status: 412

Content: application/problem+json: Problem

Headers: Correlation-Id

Version conflict
{
  "type": "/api/v1/problems/version_conflict",
  "title": "Version conflict",
  "status": 412,
  "code": "version_conflict",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d",
  "current": {
    "id": "0192f4a0-7b1c-7353-8d8c-dea659467151",
    "version": 8
  }
}

PayloadTooLarge

Problem codes: payload_too_large.

  • x-status: 413

Content: application/problem+json: Problem

Headers: Correlation-Id

Payload too large
{
  "type": "/api/v1/problems/payload_too_large",
  "title": "Payload too large",
  "status": 413,
  "code": "payload_too_large",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

UnsupportedMediaType

Problem codes: unsupported_media_type.

  • x-status: 415

Content: application/problem+json: Problem

Headers: Correlation-Id

Unsupported media type
{
  "type": "/api/v1/problems/unsupported_media_type",
  "title": "Unsupported media type",
  "status": 415,
  "code": "unsupported_media_type",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

RangeNotSatisfiable

Problem codes: range_not_satisfiable.

  • x-status: 416

Content: application/problem+json: Problem

Headers: Correlation-Id, Content-Range

Range not satisfiable
{
  "type": "/api/v1/problems/range_not_satisfiable",
  "title": "Range not satisfiable",
  "status": 416,
  "code": "range_not_satisfiable",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

UnprocessableEntity

Problem codes: idempotency_key_reuse.

  • x-status: 422

Content: application/problem+json: Problem

Headers: Correlation-Id

Idempotency key reused
{
  "type": "/api/v1/problems/idempotency_key_reuse",
  "title": "Idempotency key reused",
  "status": 422,
  "code": "idempotency_key_reuse",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

PreconditionRequired

Problem codes: precondition_required.

  • x-status: 428

Content: application/problem+json: Problem

Headers: Correlation-Id

Precondition required
{
  "type": "/api/v1/problems/precondition_required",
  "title": "Precondition required",
  "status": 428,
  "code": "precondition_required",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

TooManyRequests

Problem codes: rate_limited.

  • x-status: 429

Content: application/problem+json: Problem

Headers: Correlation-Id, Retry-After, RateLimit, RateLimit-Policy

Too many requests
{
  "type": "/api/v1/problems/rate_limited",
  "title": "Too many requests",
  "status": 429,
  "code": "rate_limited",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

ServiceUnavailable

Problem codes: unavailable, maintenance, setup_required.

  • x-status: 503

Content: application/problem+json: Problem

Headers: Correlation-Id, Retry-After

Service unavailable
{
  "type": "/api/v1/problems/unavailable",
  "title": "Service unavailable",
  "status": 503,
  "code": "unavailable",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

Error

Any other error, e.g. internal_error (500).

  • x-status: 500

Content: application/problem+json: Problem

Headers: Correlation-Id

Internal error
{
  "type": "/api/v1/problems/internal_error",
  "title": "Internal error",
  "status": 500,
  "code": "internal_error",
  "correlation_id": "0192f4a0-7b1c-7577-8bf0-c4f4ee4f887e",
  "instance": "/api/v1/threads/0192f4a0-7b1c-78f9-8074-fa94e84bab7d"
}

Shared headers

Correlation-Id

Type: CorrelationId

Correlation ID of this request (its W3C trace ID written as UUID); also in problem bodies, events and audit entries. Clients never send it.

RateLimit

Type: string

Remaining quota of the rate-limit class, format of draft-ietf-httpapi-ratelimit-headers (work in progress), e.g. "rl.message";r=17;t=4.

RateLimit-Policy

Type: string

Quota policy of the rate-limit class, e.g. "rl.message";q=60;w=60.

Retry-After

Type: integer

Seconds to wait before retrying (RFC 9110).

ETag

Type: string

Strong entity tag of the resource version, e.g. "7".

File-ETag

Type: string

"<sha256 hex>", the lowercase hex SHA-256 of the whole delivered variant (12, 9.3); not a version.

Repr-Digest

Type: string

sha-256=:<base64>: of the whole delivered variant (RFC 9530); the client checks it after the download.

Accept-Ranges

Type: string

Always bytes; exactly one range is supported.

Content-Range

Type: string

bytes <first>-<last>/<size> with 206, bytes */<size> with 416 (RFC 9110).

Content-Disposition

Type: string

inline only for the inline list of 12 9.3, otherwise attachment; always filename="<ASCII fallback>" before filename*=UTF-8''<percent-encoded> (RFC 6266, RFC 8187).

File-Content-Security-Policy

Type: string

Always default-src 'none'; sandbox, so an upload never runs as a page of the instance (12, 9.3).

Cross-Origin-Resource-Policy

Type: string

Always same-origin.

File-Cache-Control

Type: string

private, max-age=<client.cache_max_age>, immutable with normal authentication, private, no-store with a ticket (12, 9.3; ADR 0048).

Idempotent-Replay

Type: boolean

true when the response is the stored original of an earlier identical request.

Location

Type: string (uri)

Target of the redirect.

Type: string

Console cookie or its clearing value (08, 7.5).

WWW-Authenticate

Type: string

Authentication challenge, e.g. DPoP error="use_dpop_nonce" (RFC 9449).

DPoP-Nonce

Type: string

Fresh server nonce for the next DPoP proof (RFC 9449).

Deprecation

Type: string

Deprecation date of this operation as structured field date (RFC 9745), e.g. @1798761599. Sent by deprecated operations only.

Sunset

Type: string

Date after which the operation stops working (RFC 8594). Not earlier than Deprecation plus api.deprecation_min_notice.

Type: string

rel="deprecation" link to the migration notes of a deprecated operation (RFC 9745).