# Introduction Fin is a REST API for adding an agent to your application. Your backend sends a user's instruction; Fin runs it asynchronously, records progress, and asks for approval when an action needs the user's consent. Build your own interface around conversations, runs and events. Start with a simple question, then add tools, agent wallets and automations as your integration needs them. ## How it works 1. **Authenticate your integration and user.** Your backend sends a partner API key and the user's access token on every API request. 2. **Provision the Fin account.** One idempotent call resolves the internal `userId`. 3. **Open a conversation.** It holds the user's messages, files and event history. 4. **Start a run.** Send an instruction and receive `202` with a run id. Work happens after that response. 5. **Follow progress and decisions.** Read the stream or poll the API. Present any required approval, record the user's decision, and follow the eventual result. The [quickstart](/quickstart) walks through these calls with tools disabled and no funded wallet. ## Your application and Fin | Your application owns | Fin owns | | --- | --- | | Sign-in and the user's browser session | Token verification and user isolation | | Secure storage of your integration key | Authorization of each API request | | Conversation UI and progress display | Durable runs, tool execution and event history | | Presenting exact terms and collecting a user's decision | Enforcing the approval or authorization contract | | Your customer's connected human wallet interface | Configured agent wallets and their backend credentials | Your backend calls Fin over HTTP. Before sending a model request, Fin reserves its maximum cost against the user's budget. Tool calls have a separate path through policy, consent, execution, verification and audit. A saved prompt or schedule does not authorize money movement. ## A predictable integration surface The partner API lives under `/v1`. Account resources are scoped to the verified user, requests and responses use JSON, and live updates use server-sent events. The reference is generated from the route contracts and includes request fields, response schemas and errors. Each endpoint page describes its request and response. The guides explain how calls fit together: [authentication](/authentication), [resource ownership](/concepts), [streaming](/streaming), and [error handling](/errors). ## What to verify for your deployment The API contract does not establish that a particular deployment is ready for your traffic or funds. Your integration needs a partner key, a compatible identity provider, model access, execution capacity and the providers for any enabled financial tools. Test the complete path your application uses: authentication, an accepted run, durable events, approval rendering and decisions, reconnects, and failures. Wallet provisioning or a successful balance read does not prove funded settlement. Validate provider behavior and funded execution separately before enabling financial actions for your users. ## Start here - [Your first run](/quickstart) — make the initial calls and read the result. - [Core concepts](/concepts) — understand users, conversations, runs and approvals. - [Financial operations](/financial-operations) — follow consent, execution and settlement evidence. - [Authentication](/authentication) — connect your backend and user identity. - [Docs for agents](/agents) — connect your coding assistant to the same documentation. --- # Quickstart Create an account, open a conversation, and get your first agent response. This run disables tools, so it needs no agent wallet or funded balance. ## Before you begin Obtain your deployment's API base URL, a partner API key, and a valid end-user access token from the configured identity provider. Fin does not issue human login tokens. Your deployment also needs model access and available execution budget. These examples use Bash, `curl`, `jq` and `uuidgen`. Set the values in a trusted terminal or backend; keep the partner key out of browser code. Replace the placeholder URL with your API origin, without a trailing `/v1`. ```bash FIN_BASE_URL=https://api.example.test FIN_API_KEY=your_partner_key FIN_USER_TOKEN=your_user_access_token FIN_AUTH=(-H "X-Api-Key: $FIN_API_KEY" -H "Authorization: Bearer $FIN_USER_TOKEN") ``` See [Authentication](/authentication) for how the two credentials work together. ## 1. Provision the user [`users.ensure`](/api-reference/users/ensure) creates the verified identity's Fin account if needed, or returns the existing account. Save its `userId` for subsequent paths; it is not the identity provider's subject. ```bash FIN_USER_ID=$(curl --fail-with-body -sS -X POST "$FIN_BASE_URL/v1/users" \ "${FIN_AUTH[@]}" -H 'Content-Type: application/json' -d '{}' | jq -er '.userId') ``` ## 2. Open a conversation [`conversations.create`](/api-reference/conversations/create) opens a conversation and returns `201` with its id. Save and reuse that id to continue the same thread; create another conversation when your application needs a separate one. Fin does not designate a special main conversation. ```bash FIN_CONVERSATION_ID=$(curl --fail-with-body -sS \ -X POST "$FIN_BASE_URL/v1/users/$FIN_USER_ID/conversations" \ "${FIN_AUTH[@]}" -H 'Content-Type: application/json' -d '{}' | jq -er '.id') ``` ## 3. Start a run Generate one `runId` for this instruction and retain it. Reuse the same id if you need to retry this start after a timeout. Generate a new id for a new instruction. ```bash FIN_RUN_ID=$(uuidgen | tr '[:upper:]' '[:lower:]') curl --fail-with-body -sS \ -X POST "$FIN_BASE_URL/v1/users/$FIN_USER_ID/agent-runs" \ "${FIN_AUTH[@]}" -H 'Content-Type: application/json' \ -d "$(jq -n --arg runId "$FIN_RUN_ID" --arg conversationId "$FIN_CONVERSATION_ID" \ '{conversationId: $conversationId, text: "Say hello in one sentence.", runId: $runId, profile: {tools: []}}')" ``` A successful response is `202` with the accepted `runId`. It confirms admission, not completion. The explicit empty `profile.tools` list prevents tool calls. Omitting that list allows the deployment's registered tools, subject to policy and consent. ## 4. Follow the response Open the conversation stream. It replays the journal, so opening it after the start response does not lose recorded events. ```bash curl --fail-with-body -sSN \ "$FIN_BASE_URL/v1/users/$FIN_USER_ID/conversations/$FIN_CONVERSATION_ID/stream?cursor=0" \ "${FIN_AUTH[@]}" -H 'Accept: text/event-stream' ``` Show `agent.text_delta` as temporary text. Use durable `agent.entry` for the saved reply and `run.ended` for the recorded outcome. The stream stays open for future work; press Ctrl-C to close this terminal connection. See [Streaming and events](/streaming) for reconnect handling. You can also read a run's state without holding a connection open: ```bash curl --fail-with-body -sS \ "$FIN_BASE_URL/v1/users/$FIN_USER_ID/agent-runs/$FIN_RUN_ID" \ "${FIN_AUTH[@]}" ``` `status` reports `running`, `completed`, `failed`, `aborted` or `paused`. Read `response.text` for the retained public assistant answer and `response.completeness` for a complete or partial ending. `response` is null until an answer is recorded. `output` separately carries a structured result when the run requested a `profile.outputContract`; `output: null` does not mean a text response failed. ## When you enable tools An action needing consent can open an approval and pause the run. `approval.opened` announces it, and the run's `pendingApprovals` lists undecided approvals. Fetch [`approvals.get`](/api-reference/approvals/get) for the persisted tool input, fingerprint, summary and authorization contract. Show the exact assets, amounts, destinations, limits and validity before asking the user to decide. A friendly summary alone is not the consent payload. For an approval opened by a run, call [`approvals.approve`](/api-reference/approvals/approve) or [`approvals.deny`](/api-reference/approvals/deny) only after that user decision. Successful decisions resume work automatically in the same conversation; do not send a second start. Keep following the conversation after `approval.decided`, or poll the same run id until its status is `completed`, `failed` or `aborted`. Approval resume does not emit another `run.started`; the public run keeps the same id and admitted input. A `run.ended` frame with `status: "paused"` is not terminal. If its pending approval expires, Fin records Stop and ends the run as aborted. If resuming cannot be admitted, the decision is not recorded and the approval remains pending. If it expired or was already decided, handle `409 approval_not_pending` by refreshing state. An approved or consumed approval does not establish settlement. Read financial operations for the exact request, consent, execution plan and receipts: ```bash curl --fail-with-body -sS \ "$FIN_BASE_URL/v1/users/$FIN_USER_ID/financial-operations?runId=$FIN_RUN_ID" \ "${FIN_AUTH[@]}" ``` ### Direct withdrawals Withdrawals use a separate review and confirmation flow. Review the terms returned by [`wallets.prepareWithdrawal`](/api-reference/wallets/prepare-withdrawal), then pass its `approvalId` and unchanged `fingerprint` to [`wallets.confirmWithdrawal`](/api-reference/wallets/confirm-withdrawal). Do not send a withdrawal approval to the generic approval endpoint. Retain its `operationId` to read the result; a direct withdrawal has no conversation or agent run. ## Continue building - [Core concepts](/concepts): resource ownership, lifecycle and consent. - [Streaming and events](/streaming): durable history and reconnection. - [Financial operations](/financial-operations): consent, settlement and uncertain results. - [Errors](/errors): machine-readable refusals and retry handling. - [Docs for agents](/agents): Markdown exports and the documentation MCP server. --- # How Fin works Fin separates the person asking for work, the conversation that holds its history, the agent run that carries out an instruction, and any financial operation it requests. Each has its own identity and lifecycle, so your application can read the facts it needs directly. ## Users and credentials A **user** is a Fin account mapped to a verified identity. Call [`users.ensure`](/api-reference/users/ensure) with your partner key and the user's valid access token before making account-dependent requests. It creates the account once and returns the same account on later calls. Use the returned `userId` in API paths. This is Fin's internal UUID, distinct from the identity provider's `subject`; do not substitute a wallet address or decoded JWT subject. | Credential | Identifies | Held by | | --- | --- | --- | | `X-Api-Key` | Your integration | Your backend | | `Authorization: Bearer ` | The end user | Forwarded by your backend | Every `/v1` request needs both. A partner key alone cannot act for a user. A path naming a different Fin user returns `403 subject_mismatch`. A verified identity without a provisioned account can call `users.ensure`; other account-dependent requests return `412 account_not_provisioned`. Provisioning never makes an invalid credential valid or re-enables a disabled account. See [Authentication](/authentication). ## Conversations and agent runs A **conversation** holds messages, events, approvals and files. Use [`conversations.create`](/api-reference/conversations/create) to open one. Your application chooses which conversation to show and stores its id; Fin does not designate a special main conversation. Reuse that id for the same thread, or create another for separate work. An **agent run** carries out an instruction inside that conversation. [`runs.start`](/api-reference/agent-runs/runs-start) accepts `conversationId`, instruction text, an optional execution profile and an optional client-chosen `runId`. It returns `202` when work is accepted; it does not wait for completion. | Run status | Client behavior | | --- | --- | | `running` | Continue showing progress. | | `completed` | Read the public assistant response or requested structured output. | | `failed` | Show the failure and inspect recorded details. | | `aborted` | Show that this work was stopped, including when a pending approval expired. | | `paused` | Read the approval state; the run awaits a decision and is not terminal. | The public run keeps the same id, input and admitted profile across approvals and continuations. A paused execution keeps the conversation reserved but releases its user execution capacity. An approval decision must pass admission again before work continues. Internal continuation segments do not create new public runs. Read [`runs.get`](/api-reference/agent-runs/runs-get) for the original request, current status, pending approvals and retained public result. Its `response` contains the full assistant text and whether it is complete or partial. Its `output` separately carries a structured result when the admitted profile requested one. You do not need to reconstruct the journal to read the result. List runs with `runs.list`, or stop the stable run id with `runs.abort`, including while it is paused. A decision emits `approval.decided`, with no new `run.started` event. Keep following the conversation for tool results, assistant replies and the eventual `run.ended`, or keep polling the same run id. A `run.ended` event with `status: "paused"` ends an execution segment; it does not end the public run. Starting unrelated work while a conversation is held returns `409 run_active`. Supply a client-chosen `runId` and reuse it for retries of the same start request. Replaying that id cannot replace its admitted instruction or profile. ## Financial operations A **financial operation** records one exact request, its consent, frozen execution plan and settlement evidence. An agent-proposed operation links to its actual conversation, stable run and tool call. A direct withdrawal belongs to the user and has no conversation or agent run; its approval belongs to that financial operation. Read [`financialOperations.get`](/api-reference/financial-operations/financial-operations-get) for the operation's request, execution legs and complete public receipts. An accepted command or a completed agent run does not establish that funds settled. See [Financial operations](/financial-operations) for the lifecycle and uncertain outcomes. ## Journal and stream The **journal** is the conversation's durable history. The **stream** replays that history and then delivers new events, including temporary text deltas for a responsive UI. Use durable events as the source of truth. Read [Streaming and events](/streaming) for replay and reconnects. ## Approvals and consent An approval describes one action the user may accept or decline. Its status starts as `pending`, then becomes `approved`, `denied` or `expired`. [`approvals.get`](/api-reference/approvals/get) returns the persisted input, fingerprint, summary, authorization contract and decision state. Show those exact terms before sending a decision; a friendly summary alone is not the consent payload. | Path | Review | Decision | | --- | --- | --- | | A tool call during a run | Exact terms from `approvals.get`; `approval.opened` announces the review | `approvals.approve` or `approvals.deny` | | A direct withdrawal | Terms from `wallets.prepareWithdrawal` | `wallets.confirmWithdrawal` with its `approvalId` and unchanged `fingerprint` | The generic approval endpoint does not execute a prepared withdrawal. `consumedAt` and `approval.consumed` record permission being spent to authorize execution; the action can still fail afterward. Read the financial operation's outcome and receipts before reporting settlement. Direct withdrawals have no conversation journal. An automation can use a previously approved, persisted authorization contract within its exact bounds, without a fresh approval for every authorized occurrence. A saved instruction or schedule on its own grants no permission to move funds. ## Agent wallet and budget The **agent wallet** is separate from the human's connected wallet. Fin manages its backend credentials. [`wallets.ensure`](/api-reference/wallets/ensure) creates or reconnects it; [`wallets.get`](/api-reference/wallets/get) only reads it. Provisioning a user does not provision or fund the wallet. Availability depends on the deployment's configured provider. The **budget** tracks execution spend and reservations. [`budgets.headroom`](/api-reference/budgets/headroom) reports day and month limits, reserved spend, recorded spend and any freeze. It is separate from token balances in the agent wallet. ## Automations An **automation** starts work on a schedule or a supported event. Its runs use the same conversation, journal, policy and consent boundaries as interactive work. Your integration can inspect and control existing automations through the API. Authoring and financial consent are part of the agent's reviewed tool flow; a run request is not a standing authorization. Continue with [Your first run](/quickstart). --- # Base URL Use the API origin supplied for your deployment: ```text https://{your-deployment} ``` Endpoint paths include `/v1`; append the documented path once to this origin. For example, provisioning uses `POST /v1/users`. The documentation site has a separate origin and does not serve these API requests. Account-dependent resources use the returned `userId` in their paths. Operation ids such as `conversations.create` and `runs.start` identify the same calls in logs and traces. --- # Authentication Every `/v1` request carries two credentials: | Header | Holder | Purpose | | --- | --- | --- | | `X-Api-Key: fin_…` | Your backend | Identifies your registered integration. | | `Authorization: Bearer ` | The end user, forwarded by your backend | Identifies the user the request acts for. | Get your partner key from the deployment operator. Keys are shown once when minted. To rotate, mint a replacement, update your backend, and revoke the old key; both remain valid until revocation. Revocation may take up to 30 seconds to reach every replica's credential cache. Keep partner keys out of browser code and public repositories. Your identity integration obtains and refreshes access tokens from the configured trusted issuer. Fin verifies those tokens; it does not issue human login or refresh tokens. A partner key alone cannot act for a user. A valid key with no user token receives `401`. First call [`users.ensure`](/api-reference/users/ensure) with the verified user's token. It creates their Fin account if needed and returns its internal `userId`. Use that UUID in paths, not the token's `subject` or a wallet address. A path naming another user receives `403 subject_mismatch` before resource lookup. Account-dependent calls before provisioning receive `412 account_not_provisioned`; provisioning cannot re-enable a disabled account. For browser applications, your backend owns the session, token renewal and request proxy. Attach both credentials when forwarding to Fin. User logout or token expiry does not delete history or cancel work already admitted by Fin. --- # Pagination Lists take `cursor` and `limit` and return `data` and `nextCursor`, with `total` where documented. Pass `nextCursor` back unchanged; `null` means the end as of that read. Use the endpoint's schema for its limit and default. The event journal is oldest-first; activity history is newest-first. Journal pagination uses an opaque list cursor. Streaming resumes with a journal sequence through `Last-Event-ID` or `?cursor=`; do not interchange these cursor formats. See [Streaming](/streaming). --- # Idempotency `runs.start` accepts an optional client-chosen `runId`. Retry the same start with the same id and conversation to receive the same run id without duplicate work. Use a new id for a new instruction. A retry does not amend the already admitted input or profile. `automations.invoke` and `automations.signal` accept an `idempotencyKey`. Follow their endpoint contracts, including the required current automation revision. There is no general `Idempotency-Key` header in v1. Approval decisions are single-shot: a repeated decision can return `409 approval_not_pending`. Read recorded state after an ambiguous response instead of assuming the action failed or creating a replacement action. --- # Rate limits Requests are limited per partner key and per user. Defaults are 6,000 requests per minute per partner key and 300 per minute per user; deployment configuration can change those values. Inspect the response's rate-limit headers and honor `Retry-After` on `429`. Streams also have per-user and per-replica socket limits; reaching them returns `429 stream_capacity`. Reconnect with backoff. Request limits, execution capacity and user spend budget are separate constraints. Read the error's `reason` to distinguish them. --- # Compatibility Document revision **2.0.0** is an intentional breaking reset of the earlier staging `/v1` contract: run and approval paths, resource identities and response types changed together. Existing integrations must update their requests and generated types. This reset is an explicit exception to the previous six-month notice promise; no prior notice or external client migration is claimed. The complete change record is `docs/api-reset-2.md` in the repository. The policy below applies to subsequent changes. Response objects are open: new fields can ship within `/v1`, and clients should ignore fields they do not recognize. Send only documented request keys; request bodies are strict. Enums are closed. Adding an enum value is a breaking change because generated clients validate against the published union. New values must use a new field or operation rather than extending a published enum in place. Treat an unknown enum value as a client/schema mismatch. Event discriminators are also defined by the published schema; do not assume they can expand silently. Breaking changes require `/v2`, with `Deprecation` and `Sunset` headers on `/v1` at least six months before removal. Follow the generated reference for the deployed schema. Send `X-Request-Id` with 8–64 characters from `[A-Za-z0-9._-]` for correlation. The response echoes the id it used; include it when reporting a problem. See [Errors](/errors) for the format and reason catalog. --- # Errors Every failure is an RFC 9457 problem (`application/problem+json`). `type` names the kind, `reason` is the machine-readable why, `retryable` says whether repeating the same request can succeed, and `requestId` is what to quote. A resource that belongs to someone else answers exactly like a missing one. ```json { "type": "urn:fin:error:conflict", "title": "Conflict", "status": 409, "reason": "run_active", "requestId": "0192…", "retryable": false } ``` - `run_active` (409) — a run already holds this conversation - `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it - `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation - `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again - `execution_unavailable` (409) — the execution engine could not take the work - `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed - `automation_changed` (409) — the `revision` sent is stale; reload the automation - `automation_held` (409) — an operator holds the automation; it fires again when released - `automation_invalid` (409) — the automation's definition cannot run as written - `automation_completed` (409) — the automation has finished for good and cannot fire again - `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have - `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired - `run_not_active` (409) — the run named in the path is not the conversation's live run - `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress - `credential_expired` (401) — the user token has expired; obtain a fresh one - `account_disabled` (403) — an operator disabled the account - `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first - `provider_unavailable` (503) — an external provider the call depends on did not answer - `invalid_input` (400) — the body or query failed validation; `issues` names each field - `internal` (500) — a fault on our side; quote `requestId` when reporting it - `partner_key_required` (401) — no `X-Api-Key` header was sent - `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked - `subject_mismatch` (403) — the `{userId}` in the path is not the token's user - `origin_rejected` (403) — a browser `Origin` other than the configured web origin - `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After` - `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After` - `invalid_cursor` (400) — the `cursor` is not one this list minted --- # Events The journal and the stream carry one shape. On the stream, `id` is the journal `seq`, `event` is the type below, and `data` is a `{ delivery, seq, payload }` frame; resume with `Last-Event-ID` or `?cursor=`. - `run.started` — Opens a new run: the engine admitted it and is about to process the input, whether an ordinary turn or an automation firing. Emitted once, at admission — a run resumed after an approval does not get a second one. `run.ended` closes what this event opened. - `run.ended` — The run stopped occupying its execution slot: `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending. Carries token usage and cost once known, and the failure message when it failed. A paused run resumes without a fresh `run.started`. - `agent.entry` — One durable message in the conversation: the user's message, the assistant's completed reply, or a tool's display text once it resolves. Streaming assistant text arrives first as `agent.text_delta` and lands here only when the turn completes. - `agent.text_delta` — A chunk of the assistant's reply while it is still generating. Delivered live only — never written to the durable journal or replayed on reconnect — and superseded by the complete text in the `agent.entry` that follows. - `tool.call` — The assistant asked to call a tool. Emitted once the call is committed to the conversation, before it runs; `approval.opened` follows if a human must decide first, otherwise the call proceeds straight to `tool.result`. - `tool.result` — One tool call resolved: `outcome` says what happened (completed, denied, parked for approval, or failed). Immediately followed by an `agent.entry` (role `tool`) carrying that outcome's own display text. - `approval.opened` — A tool call is parked, waiting on a human decision. Carries the terms the approval card renders: the call's input, a summary, and the authorization contract in effect, if any. `approval.decided` or `approval.expired` closes it. - `approval.decided` — The user, or a partner integration, approved or denied a parked approval. `approve` says which way; a denial may carry `reason`. Consuming the decision to execute the tool follows as `approval.consumed`, but only when the decision was an approval — a denial never reaches consumption. - `approval.consumed` — The approval was spent to authorize its tool call, immediately before that call runs. This is when the call is authorized, not when it finishes: the call can still fail after this event lands, and nothing here rolls it back. Marks the approval used; it cannot authorize a second execution. - `approval.expired` — A parked approval lapsed before anyone decided: its deadline passed, or the run it belongs to stopped while it was still pending. - `automation.fired` — An automation triggered this conversation's run. Emitted once, immediately before the `run.started` it precedes, naming the automation and its name at fire time. - `intents.settlement` — A later, independently verified financial fact about one leg of an authorized swap — settled, refunded, or never executed — never inferred from the model's own tool result. Appended whenever the provider confirms the outcome, independent of the run that requested it; `legId` and `operationId` join it back to its financial request, progress and authorizing approval. Archived receipts retain their original `occurrenceId`. - `intents.progress` — Best-effort, display-only progress for an authorized swap, between approval and its settlement receipt: freezing the plan (`planning`), the frozen legs (`planned`), then each leg's own stage (`stage`). Never gates execution and may arrive out of order or not at all; an `intents.settlement` receipt always takes precedence, and a terminal outcome is never reported here. --- # Streaming & events Use the conversation's event stream to show progress and its durable journal to restore state. Both expose the same recorded history; the stream also carries temporary text updates for your UI. ## Choose how to read | Interface | Use it for | Ordering | | --- | --- | --- | | [`events.list`](/api-reference/events/list) | History, backfilling, or polling | Oldest durable event first | | [`conversations.stream`](/api-reference/events/conversations-stream) | Replaying history, then following live work | Durable sequence plus live frames | `events.list` returns `data` and `nextCursor`. Pass the cursor back unchanged until it is `null`, meaning the end as of that read. More history may arrive later. ## Connect to the stream Open `GET /v1/users/{userId}/conversations/{conversationId}/stream` with both authentication headers and `Accept: text/event-stream`. A `cursor` of `0` replays from the beginning. A positive cursor replays durable events strictly after that journal sequence. ```bash curl --fail-with-body -sSN \ "$FIN_BASE_URL/v1/users/$FIN_USER_ID/conversations/$FIN_CONVERSATION_ID/stream?cursor=0" \ -H "X-Api-Key: $FIN_API_KEY" \ -H "Authorization: Bearer $FIN_USER_TOKEN" \ -H 'Accept: text/event-stream' ``` For a browser application, connect through your backend so your partner key stays server-side. Native `EventSource` does not accept arbitrary authorization headers; use your authenticated same-origin proxy or a streaming HTTP client suited to your session design. ## Durable and live frames This illustrates the framing, not a complete run transcript: ```text : connected id: 42 event: run.started data: {"delivery":"durable","seq":42,"payload":{"input":"Hello","runId":"…"}} event: agent.text_delta data: {"delivery":"live","payload":{"text":"Hello"}} ``` | Delivery | Persistence | Client behavior | | --- | --- | --- | | `durable` | Has a journal `seq`, appears in history, replays on reconnect | Apply to saved conversation state. | | `live` | Has no journal sequence and does not replay | Use for temporary presentation only. | `agent.text_delta` provides text while the assistant is generating. Replace that temporary text with the canonical reply when durable `agent.entry` arrives. Lines beginning with `:` are comments or heartbeats, not events. Parse SSE framing before interpreting `data` as JSON. ## Reconnect without losing your place Record the last durable sequence you successfully applied. Reconnect with that value in `Last-Event-ID` or `?cursor=`; `Last-Event-ID` takes precedence when both are supplied. Deduplicate durable events by conversation and sequence when reloading or replaying them. Live text deltas never advance this cursor. Reconnect with backoff and honor `Retry-After` on `429`. A stream uses the user's credential; if it expires, renew it through your authentication integration before reconnecting. Streams have their own capacity limits in addition to normal request limits. ## Read resources after a reconnect The journal shows progress; resource reads provide the current facts without reconstructing every event. [`runs.get`](/api-reference/agent-runs/runs-get) returns the original request, current status, full public assistant response, structured output and pending approvals. The same public run id survives every continuation. `approval.opened` announces a decision. Fetch [`approvals.get`](/api-reference/approvals/get) for its persisted tool input, summary, fingerprint and authorization contract, even after a decision. You do not need to find the original event to render those exact terms. ## Handle approvals and continuations `approval.decided` records a decision. `approval.consumed` records permission being spent before execution; it is not a successful tool result. Follow the journal for tool results and replies, or read the same run resource for its current result. A `run.ended` event with `status: "paused"` ends an execution segment while its public run waits for a decision. Approval resume keeps the same public run id and emits no new `run.started`. After `approval.decided`, continue processing tool results, assistant entries and the eventual `run.ended`; do not wait for a fresh start event. The public run ends when its status becomes `completed`, `failed` or `aborted`. ## Read financial evidence separately [`financialOperations.get`](/api-reference/financial-operations/financial-operations-get) returns a financial request, its frozen plan, actual execution legs and complete public receipts. `intents.progress` and `intents.settlement` name the `operationId`; use settlement updates to refresh that resource. A model reply or completed run does not prove settlement. Direct withdrawals have no conversation journal. Read their financial operation for consent and execution evidence. See [Financial operations](/financial-operations). The [event catalog](/events) describes each event. The [quickstart](/quickstart) shows a complete connection. --- # Financial operations A financial operation records one exact request to move funds. It has its own id, consent and execution lifecycle, whether an agent proposed the request or a user prepared a withdrawal directly. Read it through [`financialOperations.get`](/api-reference/financial-operations/financial-operations-get) or list it through [`financialOperations.list`](/api-reference/financial-operations/financial-operations-list). ```bash export FIN_OPERATION_ID='' curl --fail-with-body -sS \ "$FIN_BASE_URL/v1/users/$FIN_USER_ID/financial-operations/$FIN_OPERATION_ID" "${FIN_AUTH[@]}" curl --fail-with-body -sS \ "$FIN_BASE_URL/v1/users/$FIN_USER_ID/financial-operations?runId=$FIN_RUN_ID" "${FIN_AUTH[@]}" ``` Use the credentials and variables from the [quickstart](/quickstart). Lists can filter by `runId`, `conversationId` or `origin`, and return ordinary cursor pages. ## Request identity and consent For `origin: "agent"`, the operation links to the actual conversation, stable agent run and recorded model tool call. An automation occurrence id is present only when an actual occurrence exists. For `origin: "direct"`, there is no conversation or model call; those links are null. `request` contains the ordered actions and bounds that were reviewed. `requestApproval` exposes the exact request's decision and contract, while `grantApprovalId` identifies the approval that created the execution grant. An authorized automation may use a standing grant without opening another request approval. These links distinguish the proposed action from the consent that allows it to execute. For a direct withdrawal, `wallets.prepareWithdrawal` returns `operationId`, `approvalId`, `fingerprint`, expiry and contract. Show those terms and have `wallets.confirmWithdrawal` echo the approval id and fingerprint. Keep the operation id: `wallets.getWithdrawal` provides its withdrawal view, and `financialOperations.get` provides the full financial evidence. ## Execution and settlement are different facts | Field | How to interpret it | | --- | --- | | `state` | The command's lifecycle: prepared, denied, expired, executing, reported or uncertain. | | `plan` | Frozen execution terms and every planned leg. Null before a plan exists. | | `legs` | Only actual execution claims, with their current state and complete receipt when resolved. | | `result` | The safe executor outcome, updated from verified receipts when reconciliation resolves it. | | `terminal` | Whether this request is finished with no unresolved actual execution leg. It does not mean success. | An execution claim means the operation reserved authority to act. A returned executor result does not prove settlement. `reported` can still have `terminal: false` while the provider's outcome remains unresolved. Likewise, an agent run's `completed` status says the agent finished its work, not that a financial operation settled. Inspect the outcome and each receipt. `settled`, `refunded` and `status: "not_executed"` describe different resolutions. `partial` may mean mixed final results or unfinished work; `terminal` distinguishes those cases. A denied or expired preparation is terminal with a null result because execution never started. An approved preparation can also expire before its consent is consumed. The planned legs and actual legs need not have the same length. Execution can stop after an earlier leg is refused or refunded. Later unattempted actions have no invented claims or receipts; a finished request can therefore have fewer actual legs than planned legs. ## After a timeout or uncertain result Retain the operation id and read it again. A lost response, `pending` result or `uncertain` state is not permission to start a replacement transfer. Fin reconciles the existing execution against provider evidence. The operation remains readable while that evidence is incomplete; it does not manufacture a settlement result from a successful HTTP response or model reply. These reads expose frozen public terms and receipts. Signing keys, signatures, provider session credentials, raw provider payloads and internal execution fences are never part of the resource. --- # Docs for AI agents Give your coding assistant access to the same guides and generated API reference you read here. The documentation server only reads public documentation; it cannot call the Fin API, access accounts, approve actions or move funds. ## Connect over MCP The docs server exposes a Streamable HTTP MCP endpoint at `/mcp`: ```text https://docs.fin.benkurrek.com/mcp ``` Add that URL as a remote HTTP MCP server in your assistant's connection settings. Public documentation does not require your Fin partner key or an end-user token. The endpoint is available when the docs version containing this feature is deployed. For a local preview, replace the origin with the preview site's address and keep `/mcp`; a separate assistant can connect only if it can reach that address. ## Search, then read | Tool | Input | Use | | --- | --- | --- | | `search_docs` | `{ "query": "approval continuation" }` | Find matching pages. | | `get_doc` | `{ "id": "" }` | Read a matching page's full Markdown. | Search for a task or resource, then pass a returned page id to `get_doc`. Use endpoint schemas for request and response fields, and guides for workflows across calls. The server reads the documentation packaged with that deployment. A local preview can contain changes that have not yet reached the public site. For example, ask your assistant: > Use the Fin documentation MCP to explain how to start a run and reconnect to its event > stream. Read the authentication and streaming guides, then check the endpoint schemas > before writing the integration. ## Copy or fetch Markdown Use **Copy page** to copy a page's Markdown. Its `.md` URL exposes the same content without navigation or styling, for example: ```text https://docs.fin.benkurrek.com/quickstart.md https://docs.fin.benkurrek.com/api-reference/agent-runs/runs-start.md ``` [llms.txt](/llms.txt) provides a compact page index. [llms-full.txt](/llms-full.txt) provides the documentation as one text file. Use [OpenAPI](/openapi.json) for the machine-readable API schema. ## Keep credentials in your application Documentation access requires no API credentials. When moving to real requests, keep your partner key and user token in your trusted application environment. Follow [Authentication](/authentication) and [Your first run](/quickstart) for the separate steps needed to call Fin. --- # Create account Provisions the verified identity's account. Idempotent: calling it again for an already-provisioned identity returns the same account unchanged. It is the only call an unprovisioned identity may make; every other endpoint requires this to have run first. `POST /v1/users` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": {}, "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data '{}' ``` ## Responses ### 200 The provisioned account. ```json { "description": "The provisioned account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "users.ensure", "summary": "Create account", "tags": [ "users" ], "description": "Provisions the verified identity's account. Idempotent: calling it again for an already-provisioned identity returns the same account unchanged. It is the only call an unprovisioned identity may make; every other endpoint requires this to have run first.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": {}, "additionalProperties": false } } } }, "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The provisioned account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } }, "400": { "$ref": "#/components/responses/InvalidInputForRegistration" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/ForbiddenForRegistration" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } }, "parameters": [] }, "components": { "schemas": { "User": { "type": "object", "properties": { "subject": { "type": "string", "minLength": 1, "maxLength": 512, "description": "The verified identity's subject, from the login provider." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the credential expires; the caller must re-authenticate after this." }, "userId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The user's account id." } }, "required": [ "subject", "expiresAt", "userId" ], "description": "The verified caller: their account id, verified subject and when the credential expires." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInputForRegistration": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "ForbiddenForRegistration": { "description": "The credentials are valid but may not do this.\n\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get current account Returns the caller's own account: its id, verified subject and when the credential expires. Lets a client learn its user id before it names one explicitly in another call. `GET /v1/users/me` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/me' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The caller's own account. ```json { "description": "The caller's own account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "users.me", "summary": "Get current account", "tags": [ "users" ], "description": "Returns the caller's own account: its id, verified subject and when the credential expires. Lets a client learn its user id before it names one explicitly in another call.", "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The caller's own account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } }, "parameters": [] }, "components": { "schemas": { "User": { "type": "object", "properties": { "subject": { "type": "string", "minLength": 1, "maxLength": 512, "description": "The verified identity's subject, from the login provider." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the credential expires; the caller must re-authenticate after this." }, "userId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The user's account id." } }, "required": [ "subject", "expiresAt", "userId" ], "description": "The verified caller: their account id, verified subject and when the credential expires." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get account Returns the caller's own account, addressed by the explicit `userId` in the path — the same shape every other user-scoped resource uses. Equivalent to `users.me`; the path's `userId` must equal the token's own account. `GET /v1/users/{userId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The caller's own account. ```json { "description": "The caller's own account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "users.get", "summary": "Get account", "tags": [ "users" ], "description": "Returns the caller's own account, addressed by the explicit `userId` in the path — the same shape every other user-scoped resource uses. Equivalent to `users.me`; the path's `userId` must equal the token's own account.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The caller's own account.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "User": { "type": "object", "properties": { "subject": { "type": "string", "minLength": 1, "maxLength": 512, "description": "The verified identity's subject, from the login provider." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the credential expires; the caller must re-authenticate after this." }, "userId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The user's account id." } }, "required": [ "subject", "expiresAt", "userId" ], "description": "The verified caller: their account id, verified subject and when the credential expires." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Start a conversation Starts a new conversation for the caller, optionally titled. `conversations.list` and `conversations.activity` pick it up as soon as it exists; nothing needs to happen in it first. `POST /v1/users/{userId}/conversations` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "default": {}, "type": "object", "properties": { "title": { "description": "A title for the conversation; omit to leave it untitled.", "type": "string", "maxLength": 120 } }, "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/conversations' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data '{}' ``` ## Responses ### 201 The new conversation. ```json { "description": "The new conversation.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Conversation" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "conversations.create", "summary": "Start a conversation", "tags": [ "conversations" ], "description": "Starts a new conversation for the caller, optionally titled. `conversations.list` and `conversations.activity` pick it up as soon as it exists; nothing needs to happen in it first.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "default": {}, "type": "object", "properties": { "title": { "description": "A title for the conversation; omit to leave it untitled.", "type": "string", "maxLength": 120 } }, "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "201": { "description": "The new conversation.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Conversation" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Conversation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "title": { "description": "The conversation's title, or null if none was set.", "type": [ "string", "null" ] }, "origin": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "conversation", "description": "An ordinary user-started conversation." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "automation", "description": "A conversation an automation created." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation that created this conversation." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The automation's name at the time this conversation started." } }, "required": [ "type", "automationId", "name" ] } ], "description": "Where this conversation came from: an ordinary conversation, or one an automation started." }, "runner": { "type": "string", "description": "Which execution engine ran this conversation's turns." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the conversation was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the conversation was last modified." }, "summary": { "type": "object", "properties": { "runStatus": { "anyOf": [ { "type": "string", "const": "idle" }, { "$ref": "#/components/schemas/RunStatus" } ], "description": "What the last run is doing: `idle` before any run, `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals in this conversation are waiting on the user." }, "userMessages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many messages the user has sent in this conversation." }, "assistantMessages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many messages the assistant has sent in this conversation." }, "toolCalls": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many tool calls the conversation's runs have made." }, "lastEventAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the last journal event landed; null before the first." }, "lastUserText": { "description": "The user's most recent message, for a list preview; null before the first.", "type": [ "string", "null" ] }, "lastAssistantText": { "description": "The assistant's most recent message, for a list preview; null before the first.", "type": [ "string", "null" ] }, "lastRunError": { "description": "The last run's failure message, when its most recent run failed.", "type": [ "string", "null" ] } }, "required": [ "runStatus", "pendingApprovals", "userMessages", "assistantMessages", "toolCalls", "lastEventAt", "lastUserText", "lastAssistantText", "lastRunError" ], "description": "The conversation's current status and a preview, kept current on every journal append." } }, "required": [ "id", "title", "origin", "runner", "createdAt", "updatedAt", "summary" ], "description": "One conversation: its title, origin, and a live summary of its last run." }, "RunStatus": { "type": "string", "enum": [ "running", "completed", "aborted", "failed", "paused" ], "description": "What the run is doing: `running`, or how it stopped — `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List conversations Lists the caller's ordinary conversations, newest created first. Automation execution conversations are addressable directly (`conversations.get`) but do not appear in this list; for conversations ordered by recent activity instead, see `conversations.activity`. `GET /v1/users/{userId}/conversations` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/conversations' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 A page of the caller's conversations. ```json { "description": "A page of the caller's conversations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Conversation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "conversations.list", "summary": "List conversations", "tags": [ "conversations" ], "description": "Lists the caller's ordinary conversations, newest created first. Automation execution conversations are addressable directly (`conversations.get`) but do not appear in this list; for conversations ordered by recent activity instead, see `conversations.activity`.", "parameters": [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "A page of the caller's conversations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Conversation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Conversation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "title": { "description": "The conversation's title, or null if none was set.", "type": [ "string", "null" ] }, "origin": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "conversation", "description": "An ordinary user-started conversation." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "automation", "description": "A conversation an automation created." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation that created this conversation." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The automation's name at the time this conversation started." } }, "required": [ "type", "automationId", "name" ] } ], "description": "Where this conversation came from: an ordinary conversation, or one an automation started." }, "runner": { "type": "string", "description": "Which execution engine ran this conversation's turns." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the conversation was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the conversation was last modified." }, "summary": { "type": "object", "properties": { "runStatus": { "anyOf": [ { "type": "string", "const": "idle" }, { "$ref": "#/components/schemas/RunStatus" } ], "description": "What the last run is doing: `idle` before any run, `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals in this conversation are waiting on the user." }, "userMessages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many messages the user has sent in this conversation." }, "assistantMessages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many messages the assistant has sent in this conversation." }, "toolCalls": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many tool calls the conversation's runs have made." }, "lastEventAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the last journal event landed; null before the first." }, "lastUserText": { "description": "The user's most recent message, for a list preview; null before the first.", "type": [ "string", "null" ] }, "lastAssistantText": { "description": "The assistant's most recent message, for a list preview; null before the first.", "type": [ "string", "null" ] }, "lastRunError": { "description": "The last run's failure message, when its most recent run failed.", "type": [ "string", "null" ] } }, "required": [ "runStatus", "pendingApprovals", "userMessages", "assistantMessages", "toolCalls", "lastEventAt", "lastUserText", "lastAssistantText", "lastRunError" ], "description": "The conversation's current status and a preview, kept current on every journal append." } }, "required": [ "id", "title", "origin", "runner", "createdAt", "updatedAt", "summary" ], "description": "One conversation: its title, origin, and a live summary of its last run." }, "RunStatus": { "type": "string", "enum": [ "running", "completed", "aborted", "failed", "paused" ], "description": "What the run is doing: `running`, or how it stopped — `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get conversation Returns one conversation by id: an ordinary conversation or an automation execution conversation, as long as the caller owns it. A conversation belonging to another user answers exactly like an unknown id. `GET /v1/users/{userId}/conversations/{conversationId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/conversations/YOUR_CONVERSATION_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The conversation. ```json { "description": "The conversation.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Conversation" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "conversations.get", "summary": "Get conversation", "tags": [ "conversations" ], "description": "Returns one conversation by id: an ordinary conversation or an automation execution conversation, as long as the caller owns it. A conversation belonging to another user answers exactly like an unknown id.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The conversation.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Conversation" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Conversation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "title": { "description": "The conversation's title, or null if none was set.", "type": [ "string", "null" ] }, "origin": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "conversation", "description": "An ordinary user-started conversation." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "automation", "description": "A conversation an automation created." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation that created this conversation." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The automation's name at the time this conversation started." } }, "required": [ "type", "automationId", "name" ] } ], "description": "Where this conversation came from: an ordinary conversation, or one an automation started." }, "runner": { "type": "string", "description": "Which execution engine ran this conversation's turns." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the conversation was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the conversation was last modified." }, "summary": { "type": "object", "properties": { "runStatus": { "anyOf": [ { "type": "string", "const": "idle" }, { "$ref": "#/components/schemas/RunStatus" } ], "description": "What the last run is doing: `idle` before any run, `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals in this conversation are waiting on the user." }, "userMessages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many messages the user has sent in this conversation." }, "assistantMessages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many messages the assistant has sent in this conversation." }, "toolCalls": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many tool calls the conversation's runs have made." }, "lastEventAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the last journal event landed; null before the first." }, "lastUserText": { "description": "The user's most recent message, for a list preview; null before the first.", "type": [ "string", "null" ] }, "lastAssistantText": { "description": "The assistant's most recent message, for a list preview; null before the first.", "type": [ "string", "null" ] }, "lastRunError": { "description": "The last run's failure message, when its most recent run failed.", "type": [ "string", "null" ] } }, "required": [ "runStatus", "pendingApprovals", "userMessages", "assistantMessages", "toolCalls", "lastEventAt", "lastUserText", "lastAssistantText", "lastRunError" ], "description": "The conversation's current status and a preview, kept current on every journal append." } }, "required": [ "id", "title", "origin", "runner", "createdAt", "updatedAt", "summary" ], "description": "One conversation: its title, origin, and a live summary of its last run." }, "RunStatus": { "type": "string", "enum": [ "running", "completed", "aborted", "failed", "paused" ], "description": "What the run is doing: `running`, or how it stopped — `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Start an agent run Starts the model working on the conversation's next turn and answers 202 with the run's id at once; the work happens after the response. A client-chosen `runId` makes the call safe to retry: calling it again with the same id — whether the first call already created the run or is still being admitted — answers the same id rather than starting a second run. The run's progress and output follow on the journal and `runs.get`; a tool call that needs consent opens an approval and pauses the run until `approvals.approve` or `approvals.deny` decides it. `POST /v1/users/{userId}/agent-runs` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "text": { "type": "string", "minLength": 1, "maxLength": 32768, "description": "The run's seed instruction, up to 32768 characters." }, "profile": { "type": "object", "properties": { "tools": { "description": "The only tools this run may reach. Absent means every registered tool.", "maxItems": 64, "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", "description": "A tool's name: lowercase, starting with a letter, letters, digits and underscores only." } }, "outputContract": { "description": "The strict terminal output contract validated and frozen during admission.", "type": "object", "properties": { "name": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", "description": "A tool's name: lowercase, starting with a letter, letters, digits and underscores only." }, "description": { "description": "What the terminal result means, shown beside the run's output.", "type": "string", "maxLength": 4096 }, "schema": { "description": "A bounded, strict JSON Schema object (`type: \"object\"`, `additionalProperties: false`) the run's terminal output must satisfy." } }, "required": [ "name", "schema" ], "additionalProperties": false } }, "additionalProperties": false, "description": "Bounds on this run beyond its seed text: which tools it may reach, and its terminal output contract." }, "runId": { "description": "A client-chosen id that makes the start safe to retry: calling this again with the same id — whether the first call already created the run or is still being admitted — answers the same run rather than starting a second one.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } }, "required": [ "conversationId", "text" ], "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/agent-runs' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data-binary '@request.json' ``` ## Responses ### 202 The run's id; the same id again when this exact `runId` was already accepted. ```json { "description": "The run's id; the same id again when this exact `runId` was already accepted.", "content": { "application/json": { "schema": { "type": "object", "properties": { "runId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The started run's id; the same value sent, when one was sent." } }, "required": [ "runId" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `run_active` — a run already holds this conversation - `budget_exhausted` — the user's spend headroom is gone, or an operator froze it - `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again - `execution_unavailable` — the execution engine could not take the work - `profile_unknown_tool` — the run profile names a tool this deployment does not have - `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired - `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed ```json { "description": "The operation lost to the current state.\n\n- `run_active` — a run already holds this conversation\n- `budget_exhausted` — the user's spend headroom is gone, or an operator froze it\n- `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` — the execution engine could not take the work\n- `profile_unknown_tool` — the run profile names a tool this deployment does not have\n- `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired\n- `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "runs.start", "summary": "Start an agent run", "tags": [ "agent-runs" ], "description": "Starts the model working on the conversation's next turn and answers 202 with the run's id at once; the work happens after the response. A client-chosen `runId` makes the call safe to retry: calling it again with the same id — whether the first call already created the run or is still being admitted — answers the same id rather than starting a second run. The run's progress and output follow on the journal and `runs.get`; a tool call that needs consent opens an approval and pauses the run until `approvals.approve` or `approvals.deny` decides it.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "text": { "type": "string", "minLength": 1, "maxLength": 32768, "description": "The run's seed instruction, up to 32768 characters." }, "profile": { "type": "object", "properties": { "tools": { "description": "The only tools this run may reach. Absent means every registered tool.", "maxItems": 64, "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", "description": "A tool's name: lowercase, starting with a letter, letters, digits and underscores only." } }, "outputContract": { "description": "The strict terminal output contract validated and frozen during admission.", "type": "object", "properties": { "name": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", "description": "A tool's name: lowercase, starting with a letter, letters, digits and underscores only." }, "description": { "description": "What the terminal result means, shown beside the run's output.", "type": "string", "maxLength": 4096 }, "schema": { "description": "A bounded, strict JSON Schema object (`type: \"object\"`, `additionalProperties: false`) the run's terminal output must satisfy." } }, "required": [ "name", "schema" ], "additionalProperties": false } }, "additionalProperties": false, "description": "Bounds on this run beyond its seed text: which tools it may reach, and its terminal output contract." }, "runId": { "description": "A client-chosen id that makes the start safe to retry: calling this again with the same id — whether the first call already created the run or is still being admitted — answers the same run rather than starting a second one.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } }, "required": [ "conversationId", "text" ], "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "202": { "description": "The run's id; the same id again when this exact `runId` was already accepted.", "content": { "application/json": { "schema": { "type": "object", "properties": { "runId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The started run's id; the same value sent, when one was sent." } }, "required": [ "runId" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `run_active` — a run already holds this conversation\n- `budget_exhausted` — the user's spend headroom is gone, or an operator froze it\n- `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` — the execution engine could not take the work\n- `profile_unknown_tool` — the run profile names a tool this deployment does not have\n- `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired\n- `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List agent runs Lists the caller-owned durable agent runs, newest first, optionally restricted to one conversation. Each result has the same complete representation as runs.get; continuation segments retain the same public run id. `GET /v1/users/{userId}/agent-runs` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "query", "name": "conversationId", "required": false, "description": "The conversation's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/agent-runs' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 A page of complete agent runs. ```json { "description": "A page of complete agent runs.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Run" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "description": "How many rows the list holds in all, when it is known.", "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": [ "data", "nextCursor" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "runs.list", "summary": "List agent runs", "tags": [ "agent-runs" ], "description": "Lists the caller-owned durable agent runs, newest first, optionally restricted to one conversation. Each result has the same complete representation as runs.get; continuation segments retain the same public run id.", "parameters": [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "query", "name": "conversationId", "required": false, "description": "The conversation's id." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "A page of complete agent runs.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Run" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "description": "How many rows the list holds in all, when it is known.", "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": [ "data", "nextCursor" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Run": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The stable public agent run id, retained across approval continuations." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "input": { "description": "Original admitted instruction; null only for historical requests whose input was not retained.", "type": [ "string", "null" ] }, "profile": { "type": "object", "properties": { "tools": { "description": "The only tools this run may reach. Absent means every registered tool.", "maxItems": 64, "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", "description": "A tool's name: lowercase, starting with a letter, letters, digits and underscores only." } }, "outputContract": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", "description": "A tool's name: lowercase, starting with a letter, letters, digits and underscores only." }, "description": { "description": "Meaning of this terminal output contract.", "type": "string", "maxLength": 4096 }, "schema": { "description": "The immutable strict object schema that the terminal output must satisfy.", "$ref": "#/components/schemas/RunOutputObjectSchema" } }, "required": [ "name", "schema" ], "description": "The immutable admitted output contract, readable without invoking its admission transform." }, "modelId": { "description": "The reviewed provider model pinned by trusted admission; absent for historical default selection.", "type": "string", "minLength": 1, "maxLength": 200 } }, "description": "Immutable execution bounds and model selection admitted with this public run." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this public request was admitted." }, "endedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the public request ended; null while running or paused for approval." }, "status": { "$ref": "#/components/schemas/RunStatus" }, "output": { "anyOf": [ { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/JsonValue" } }, { "type": "null" } ], "description": "The run's terminal structured result, once it has one under its `outputContract`; null otherwise." }, "response": { "anyOf": [ { "type": "object", "properties": { "text": { "type": "string", "description": "The complete retained public assistant answer, without model-summary truncation." }, "eventSeq": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "Journal sequence of the answer entry." }, "completeness": { "type": "string", "enum": [ "complete", "partial" ], "description": "Complete after successful completion; partial when execution stopped or failed." } }, "required": [ "text", "eventSeq", "completeness" ] }, { "type": "null" } ], "description": "The retained public answer for the latest segment, if one exists." }, "error": { "description": "Public failure or abort explanation; null when no error was recorded.", "type": [ "string", "null" ] }, "failure": { "anyOf": [ { "type": "object", "properties": { "code": { "type": "string", "enum": [ "model_timeout", "execution_deadline", "provider_rate_limit", "provider_unavailable", "internal_error", "unknown" ], "description": "Why the execution failed: `model_timeout` (the model was too slow to respond), `execution_deadline` (the run's active time limit elapsed before it finished), `provider_rate_limit` or `provider_unavailable` (classified from the provider's own HTTP status), `internal_error` (a host-side fault), or `unknown` when nothing more specific was classified." }, "stage": { "type": "string", "enum": [ "model_request", "tool_execution", "finalization" ], "description": "Which phase of the run was executing when it failed: `model_request` while calling or awaiting the model provider, `tool_execution` while running or resuming a tool call, or `finalization` while settling the run's output and accounting after the model finished." }, "providerMessage": { "description": "The model provider's own error text, when one was available: credential values are redacted and it is cut to 256 characters, but it is not a content classifier, so other sensitive detail may remain. Treat it as diagnostic context only — never branch on it, and review before showing it to an end user.", "type": "string", "minLength": 1, "maxLength": 256 }, "diagnosticReference": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "This failed run's own id, repeated here as one field to cite when asking support to check the host's internal logs for this execution; it carries no meaning beyond that." }, "effectWarning": { "type": "string", "const": "Earlier actions may have completed. Partial output does not prove success or a delivery failure. Check receipts before retrying; retrying may repeat actions.", "description": "This build's fixed caution: earlier actions may already have run, so partial output alone never proves success, a delivery failure, or that retrying is free of duplicate effects." } }, "required": [ "code", "stage", "diagnosticReference", "effectWarning" ] }, { "type": "null" } ], "description": "Structured safe failure details, when recorded." }, "pendingApprovals": { "type": "array", "items": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "description": "Undecided, unexpired approvals this run opened, oldest first." } }, "required": [ "id", "conversationId", "input", "profile", "startedAt", "endedAt", "status", "output", "response", "error", "failure", "pendingApprovals" ], "description": "One stable public agent request, its immutable profile, lifecycle and complete retained result." }, "RunOutputObjectSchema": { "type": "object", "properties": { "type": { "type": "string", "const": "object", "description": "JSON Schema type keyword: object." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "properties": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/RunOutputSchemaNode" }, "description": "Named fields and their strict schemas." }, "required": { "type": "array", "items": { "type": "string" }, "description": "Every declared property is required exactly once." }, "additionalProperties": { "type": "boolean", "const": false, "description": "Always false; undeclared properties are rejected." } }, "required": [ "type", "properties", "required", "additionalProperties" ], "description": "A strict object with all declared properties required and no extra properties." }, "RunOutputSchemaNode": { "description": "A bounded node in the strict JSON Schema supported for run output.", "$ref": "#/components/schemas/schema0" }, "schema0": { "anyOf": [ { "$ref": "#/components/schemas/RunOutputObjectSchema" }, { "type": "object", "properties": { "type": { "type": "string", "const": "array", "description": "JSON Schema type keyword: array." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "items": { "description": "Schema every array entry must satisfy.", "$ref": "#/components/schemas/RunOutputSchemaNode" }, "minItems": { "description": "Inclusive minimum number of array entries.", "type": "number" }, "maxItems": { "description": "Inclusive maximum number of array entries.", "type": "number" } }, "required": [ "type", "items" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "string", "description": "JSON Schema type keyword: string." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "enum": { "description": "The allowed literal values, when restricted.", "type": "array", "items": { "type": "string" } }, "minLength": { "description": "Inclusive minimum string length.", "type": "number" }, "maxLength": { "description": "Inclusive maximum string length.", "type": "number" } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "number", "description": "JSON Schema type keyword: number." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "enum": { "description": "The allowed literal values, when restricted.", "type": "array", "items": { "type": "number" } }, "minimum": { "description": "Inclusive numeric lower bound.", "type": "number" }, "maximum": { "description": "Inclusive numeric upper bound.", "type": "number" } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "integer", "description": "JSON Schema type keyword: integer." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "enum": { "description": "The allowed literal values, when restricted.", "type": "array", "items": { "type": "number" } }, "minimum": { "description": "Inclusive numeric lower bound.", "type": "number" }, "maximum": { "description": "Inclusive numeric upper bound.", "type": "number" } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "boolean", "description": "JSON Schema type keyword: boolean." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "enum": { "description": "The allowed literal values, when restricted.", "type": "array", "items": { "type": "boolean" } } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "null", "description": "JSON Schema type keyword: null." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" } }, "required": [ "type" ] } ], "description": "One supported strict JSON Schema node: object, array, string, number, integer, boolean or null." }, "RunStatus": { "type": "string", "enum": [ "running", "completed", "aborted", "failed", "paused" ], "description": "What the run is doing: `running`, or how it stopped — `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending." }, "JsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/JsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/JsonValue" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get an agent run Returns one run by id: its status, its output once it ends, and any approvals still waiting on a decision. `GET /v1/users/{userId}/agent-runs/{runId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "runId", "required": true, "description": "The run's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/agent-runs/YOUR_RUN_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The run. ```json { "description": "The run.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Run" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "runs.get", "summary": "Get an agent run", "tags": [ "agent-runs" ], "description": "Returns one run by id: its status, its output once it ends, and any approvals still waiting on a decision.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "runId", "required": true, "description": "The run's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The run.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Run" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Run": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The stable public agent run id, retained across approval continuations." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "input": { "description": "Original admitted instruction; null only for historical requests whose input was not retained.", "type": [ "string", "null" ] }, "profile": { "type": "object", "properties": { "tools": { "description": "The only tools this run may reach. Absent means every registered tool.", "maxItems": 64, "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", "description": "A tool's name: lowercase, starting with a letter, letters, digits and underscores only." } }, "outputContract": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", "description": "A tool's name: lowercase, starting with a letter, letters, digits and underscores only." }, "description": { "description": "Meaning of this terminal output contract.", "type": "string", "maxLength": 4096 }, "schema": { "description": "The immutable strict object schema that the terminal output must satisfy.", "$ref": "#/components/schemas/RunOutputObjectSchema" } }, "required": [ "name", "schema" ], "description": "The immutable admitted output contract, readable without invoking its admission transform." }, "modelId": { "description": "The reviewed provider model pinned by trusted admission; absent for historical default selection.", "type": "string", "minLength": 1, "maxLength": 200 } }, "description": "Immutable execution bounds and model selection admitted with this public run." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this public request was admitted." }, "endedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the public request ended; null while running or paused for approval." }, "status": { "$ref": "#/components/schemas/RunStatus" }, "output": { "anyOf": [ { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/JsonValue" } }, { "type": "null" } ], "description": "The run's terminal structured result, once it has one under its `outputContract`; null otherwise." }, "response": { "anyOf": [ { "type": "object", "properties": { "text": { "type": "string", "description": "The complete retained public assistant answer, without model-summary truncation." }, "eventSeq": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "Journal sequence of the answer entry." }, "completeness": { "type": "string", "enum": [ "complete", "partial" ], "description": "Complete after successful completion; partial when execution stopped or failed." } }, "required": [ "text", "eventSeq", "completeness" ] }, { "type": "null" } ], "description": "The retained public answer for the latest segment, if one exists." }, "error": { "description": "Public failure or abort explanation; null when no error was recorded.", "type": [ "string", "null" ] }, "failure": { "anyOf": [ { "type": "object", "properties": { "code": { "type": "string", "enum": [ "model_timeout", "execution_deadline", "provider_rate_limit", "provider_unavailable", "internal_error", "unknown" ], "description": "Why the execution failed: `model_timeout` (the model was too slow to respond), `execution_deadline` (the run's active time limit elapsed before it finished), `provider_rate_limit` or `provider_unavailable` (classified from the provider's own HTTP status), `internal_error` (a host-side fault), or `unknown` when nothing more specific was classified." }, "stage": { "type": "string", "enum": [ "model_request", "tool_execution", "finalization" ], "description": "Which phase of the run was executing when it failed: `model_request` while calling or awaiting the model provider, `tool_execution` while running or resuming a tool call, or `finalization` while settling the run's output and accounting after the model finished." }, "providerMessage": { "description": "The model provider's own error text, when one was available: credential values are redacted and it is cut to 256 characters, but it is not a content classifier, so other sensitive detail may remain. Treat it as diagnostic context only — never branch on it, and review before showing it to an end user.", "type": "string", "minLength": 1, "maxLength": 256 }, "diagnosticReference": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "This failed run's own id, repeated here as one field to cite when asking support to check the host's internal logs for this execution; it carries no meaning beyond that." }, "effectWarning": { "type": "string", "const": "Earlier actions may have completed. Partial output does not prove success or a delivery failure. Check receipts before retrying; retrying may repeat actions.", "description": "This build's fixed caution: earlier actions may already have run, so partial output alone never proves success, a delivery failure, or that retrying is free of duplicate effects." } }, "required": [ "code", "stage", "diagnosticReference", "effectWarning" ] }, { "type": "null" } ], "description": "Structured safe failure details, when recorded." }, "pendingApprovals": { "type": "array", "items": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "description": "Undecided, unexpired approvals this run opened, oldest first." } }, "required": [ "id", "conversationId", "input", "profile", "startedAt", "endedAt", "status", "output", "response", "error", "failure", "pendingApprovals" ], "description": "One stable public agent request, its immutable profile, lifecycle and complete retained result." }, "RunOutputObjectSchema": { "type": "object", "properties": { "type": { "type": "string", "const": "object", "description": "JSON Schema type keyword: object." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "properties": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/RunOutputSchemaNode" }, "description": "Named fields and their strict schemas." }, "required": { "type": "array", "items": { "type": "string" }, "description": "Every declared property is required exactly once." }, "additionalProperties": { "type": "boolean", "const": false, "description": "Always false; undeclared properties are rejected." } }, "required": [ "type", "properties", "required", "additionalProperties" ], "description": "A strict object with all declared properties required and no extra properties." }, "RunOutputSchemaNode": { "description": "A bounded node in the strict JSON Schema supported for run output.", "$ref": "#/components/schemas/schema0" }, "schema0": { "anyOf": [ { "$ref": "#/components/schemas/RunOutputObjectSchema" }, { "type": "object", "properties": { "type": { "type": "string", "const": "array", "description": "JSON Schema type keyword: array." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "items": { "description": "Schema every array entry must satisfy.", "$ref": "#/components/schemas/RunOutputSchemaNode" }, "minItems": { "description": "Inclusive minimum number of array entries.", "type": "number" }, "maxItems": { "description": "Inclusive maximum number of array entries.", "type": "number" } }, "required": [ "type", "items" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "string", "description": "JSON Schema type keyword: string." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "enum": { "description": "The allowed literal values, when restricted.", "type": "array", "items": { "type": "string" } }, "minLength": { "description": "Inclusive minimum string length.", "type": "number" }, "maxLength": { "description": "Inclusive maximum string length.", "type": "number" } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "number", "description": "JSON Schema type keyword: number." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "enum": { "description": "The allowed literal values, when restricted.", "type": "array", "items": { "type": "number" } }, "minimum": { "description": "Inclusive numeric lower bound.", "type": "number" }, "maximum": { "description": "Inclusive numeric upper bound.", "type": "number" } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "integer", "description": "JSON Schema type keyword: integer." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "enum": { "description": "The allowed literal values, when restricted.", "type": "array", "items": { "type": "number" } }, "minimum": { "description": "Inclusive numeric lower bound.", "type": "number" }, "maximum": { "description": "Inclusive numeric upper bound.", "type": "number" } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "boolean", "description": "JSON Schema type keyword: boolean." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" }, "enum": { "description": "The allowed literal values, when restricted.", "type": "array", "items": { "type": "boolean" } } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "null", "description": "JSON Schema type keyword: null." }, "description": { "description": "Human-readable meaning of this schema node.", "type": "string" } }, "required": [ "type" ] } ], "description": "One supported strict JSON Schema node: object, array, string, number, integer, boolean or null." }, "RunStatus": { "type": "string", "enum": [ "running", "completed", "aborted", "failed", "paused" ], "description": "What the run is doing: `running`, or how it stopped — `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending." }, "JsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/JsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/JsonValue" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Stop an agent run Asks the engine to stop the run named in the path; it must be the conversation's current live run. The call waits for the engine to confirm cleanup before answering. When this stop is what ends the run (`aborted: true`), the run's terminal `run.ended` event (status `aborted`) follows on the journal and the stream, and `runs.get` reports it once it lands. `POST /v1/users/{userId}/agent-runs/{runId}/abort` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "runId", "required": true, "description": "The run's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/agent-runs/YOUR_RUN_ID/abort' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 Whether the run actually ended aborted; false when it had already finished or was already being recovered. ```json { "description": "Whether the run actually ended aborted; false when it had already finished or was already being recovered.", "content": { "application/json": { "schema": { "type": "object", "properties": { "aborted": { "type": "boolean", "description": "Whether the run actually ended aborted; false when it had already finished, or was already being recovered, before this stop took effect." } }, "required": [ "aborted" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `run_not_active` — the run named in the path is not the conversation's live run - `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed - `execution_unavailable` — the execution engine could not take the work ```json { "description": "The operation lost to the current state.\n\n- `run_not_active` — the run named in the path is not the conversation's live run\n- `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed\n- `execution_unavailable` — the execution engine could not take the work", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "runs.abort", "summary": "Stop an agent run", "tags": [ "agent-runs" ], "description": "Asks the engine to stop the run named in the path; it must be the conversation's current live run. The call waits for the engine to confirm cleanup before answering. When this stop is what ends the run (`aborted: true`), the run's terminal `run.ended` event (status `aborted`) follows on the journal and the stream, and `runs.get` reports it once it lands.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "runId", "required": true, "description": "The run's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "Whether the run actually ended aborted; false when it had already finished or was already being recovered.", "content": { "application/json": { "schema": { "type": "object", "properties": { "aborted": { "type": "boolean", "description": "Whether the run actually ended aborted; false when it had already finished, or was already being recovered, before this stop took effect." } }, "required": [ "aborted" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `run_not_active` — the run named in the path is not the conversation's live run\n- `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed\n- `execution_unavailable` — the execution engine could not take the work", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List financial operations Lists actual financial requests owned by the caller, including direct withdrawals and requests from agent runs or automation occurrences. Each resource includes immutable requested terms, exact approval and grant links, current lifecycle, safe frozen plan terms and all persisted leg receipts. Pagination does not truncate a resource or depend on journal replay. `GET /v1/users/{userId}/financial-operations` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "query", "name": "runId", "required": false, "description": "Include only operations proposed by this stable agent run." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "query", "name": "conversationId", "required": false, "description": "Include only operations linked to this conversation; direct operations have no conversation." }, { "schema": { "type": "string", "enum": [ "direct", "agent" ] }, "in": "query", "name": "origin", "required": false, "description": "Include direct user requests or agent tool calls; omit to include both." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/financial-operations' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 A page of complete financial operations. ```json { "description": "A page of complete financial operations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/FinancialOperation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "description": "How many rows the list holds in all, when it is known.", "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": [ "data", "nextCursor" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "financialOperations.list", "summary": "List financial operations", "tags": [ "financial-operations" ], "description": "Lists actual financial requests owned by the caller, including direct withdrawals and requests from agent runs or automation occurrences. Each resource includes immutable requested terms, exact approval and grant links, current lifecycle, safe frozen plan terms and all persisted leg receipts. Pagination does not truncate a resource or depend on journal replay.", "parameters": [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "query", "name": "runId", "required": false, "description": "Include only operations proposed by this stable agent run." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "query", "name": "conversationId", "required": false, "description": "Include only operations linked to this conversation; direct operations have no conversation." }, { "schema": { "type": "string", "enum": [ "direct", "agent" ] }, "in": "query", "name": "origin", "required": false, "description": "Include direct user requests or agent tool calls; omit to include both." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "A page of complete financial operations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/FinancialOperation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "description": "How many rows the list holds in all, when it is known.", "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": [ "data", "nextCursor" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "FinancialOperation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The durable financial operation's id, independent of any conversation or run." }, "kind": { "type": "string", "enum": [ "withdraw_to_owner", "intents_execute" ], "description": "The requested capability: a direct withdrawal to the owner or an agent's exact intents request." }, "origin": { "type": "string", "enum": [ "direct", "agent" ], "description": "Whether the request came directly from the user or from a recorded agent tool call." }, "conversationId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, { "type": "null" } ], "description": "The proposing agent's conversation; null for a direct request." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The stable public agent run id, retained across approval continuations." }, { "type": "null" } ], "description": "The stable agent run that proposed the request; null for a direct request." }, "callId": { "description": "The actual recorded model tool call that proposed the request; null for a direct request.", "type": [ "string", "null" ] }, "automationOccurrenceId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The actual automation occurrence linked to the proposing run; null when none exists. An occurrence itself grants no financial consent." }, "request": { "anyOf": [ { "type": "object", "properties": { "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact input asset's token id and decimals." } }, "required": [ "pinned" ], "description": "The concrete asset this request spends; it must match the approved action at this position." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact output asset's token id and decimals." } }, "required": [ "pinned" ], "description": "The concrete asset this request produces; it must match the approved action at this position." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact input asset's token id and decimals." } }, "required": [ "pinned" ], "description": "The concrete asset this request spends; it must match the approved action at this position." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact output asset's token id and decimals." } }, "required": [ "pinned" ], "description": "The concrete asset this request produces; it must match the approved action at this position." } }, "required": [ "kind", "input", "quantity", "output" ] } ] }, "description": "The complete ordered financial actions proposed for this execution, with concrete assets and exact quantity rules." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The explicit loss and signature-lifetime limits; these must exactly match the approved grant." } }, "required": [ "actions", "bounds" ] }, { "type": "null" } ], "description": "The original exact actions and bounds; null only for older records that did not retain the request." }, "requestApprovalId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The approval of this exact request, if one was required; null when a standing grant supplies consent." }, "requestApproval": { "anyOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The exact request approval's id." }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ], "description": "The decision state; an undecided approval past its deadline is presented as expired." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest time this approval may authorize execution, even if already approved." }, "contract": { "description": "The exact financial terms retained for this approval, when available.", "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, "executionRestriction": { "description": "Present when the reviewed action was restricted to a mode that cannot sign or move funds.", "type": "string", "const": "signing_disabled" } }, "required": [ "approvalId", "status", "expiresAt" ] }, { "type": "null" } ], "description": "The exact request's review terms and decision, readable without replaying a conversation; null when no request approval exists." }, "grantApprovalId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The approval that created the immutable authorization grant used for execution; null before a grant is bound." }, "state": { "type": "string", "enum": [ "prepared", "denied", "expired", "executing", "reported", "uncertain" ], "description": "The command lifecycle. Prepared awaits consent, denied or expired cannot start, executing has claimed authority, reported has returned an executor outcome, and uncertain records an inconclusive command ending. Later receipts may resolve settlement independently; inspect result and terminal." }, "result": { "anyOf": [ { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "no_trade", "description": "The request resolved without attempting a financial action." } }, "required": [ "status" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "refused", "description": "The financial command refused execution under its authority or safety checks." }, "scope": { "type": "string", "enum": [ "authority", "request", "transient", "insufficient_funds", "request_frozen", "verification", "stale_evidence", "account_busy", "conflict", "paused", "held", "withdrawn" ], "description": "The bounded category of the refusal; no provider text, account details or amounts are exposed here." } }, "required": [ "status", "scope" ] }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "settled", "pending", "partial", "refunded", "not_executed" ], "description": "The financial outcome: settled, unresolved, mixed or incomplete, refunded, or conclusively not executed. Partial may still await receipts; the operation's terminal field states whether reconciliation remains." }, "reason": { "description": "Present when execution was restricted to a mode that cannot sign or move funds.", "type": "string", "const": "signing_disabled" }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The recorded execution or settlement state of this actual leg." } }, "required": [ "index", "state" ] }, "description": "The actual execution legs represented by this outcome; unattempted planned legs have no invented receipt." } }, "required": [ "status", "legs" ] } ] }, { "type": "null" } ], "description": "The latest safe executor or receipt-derived outcome; null before an outcome is known, including denied or expired preparations." }, "terminal": { "type": "boolean", "description": "Whether the request is finished: consent was denied or expired before execution, or execution is conclusively resolved with no actual leg awaiting a receipt. True does not mean funds settled; inspect result and receipts." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the financial request was durably recorded." }, "startedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When execution authority was claimed; null before that claim, and never proof of provider dispatch." }, "reportedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the executor durably reported its outcome; null before reporting. Settlement may resolve later." }, "plan": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The frozen execution plan's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When these execution terms were frozen." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The deadline after which this plan cannot authorize new signing." }, "legs": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input", "description": "Spends the fixed input amount and requires at least minimumOutputRaw in return." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "actionIndex": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The zero-based index of the original requested action this leg implements." }, "input": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the asset's smallest unit as an integer string." } }, "required": [ "tokenId", "decimals", "amountRaw" ], "description": "The pinned input asset and exact amount this leg may spend." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The pinned asset this leg must receive." }, "minimumOutputRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The minimum acceptable output amount, in the output asset's smallest unit as an integer string." }, "referenceOutputRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The reference output amount from trusted price evidence before applying the approved loss bound, in the output asset's smallest unit." } }, "required": [ "kind", "index", "actionIndex", "input", "output", "minimumOutputRaw", "referenceOutputRaw" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output", "description": "Receives the fixed output amount and spends no more than maximumInputRaw." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "actionIndex": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The zero-based index of the original requested action this leg implements." }, "input": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The pinned asset this leg may spend." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the asset's smallest unit as an integer string." } }, "required": [ "tokenId", "decimals", "amountRaw" ], "description": "The pinned output asset and exact amount this leg must receive." }, "maximumInputRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The maximum permitted input amount, in the input asset's smallest unit as an integer string." }, "referenceInputRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The reference input amount from trusted price evidence before applying the approved loss bound, in the input asset's smallest unit." } }, "required": [ "kind", "index", "actionIndex", "input", "output", "maximumInputRaw", "referenceInputRaw" ] } ] }, "description": "Every ordered planned action and its frozen amounts and limits, including actions that were never attempted." } }, "required": [ "id", "createdAt", "expiresAt", "legs" ] }, { "type": "null" } ], "description": "The complete frozen plan, or null before planning. Planned legs are not evidence that an action was attempted." }, "legs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The durable claim's id for this actual execution leg." }, "index": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "This leg's zero-based position in the frozen plan." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The leg's current execution or settlement state; unresolved states require reconciliation, not a second execution." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this execution leg was claimed." }, "signedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the leg's signature was durably recorded; null before signing." }, "settledAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the leg's terminal resolution was recorded; null while unresolved. Consult the receipt to distinguish settlement, refund and non-execution." }, "receipt": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ] }, { "type": "null" } ], "description": "The complete verified public resolution for this actual leg; null while unresolved. Never contains signatures or raw provider payloads." } }, "required": [ "id", "index", "state", "createdAt", "signedAt", "settledAt", "receipt" ] }, "description": "All actual execution legs and their receipts, in plan order. Unattempted planned legs have no invented claim or receipt." } }, "required": [ "id", "kind", "origin", "conversationId", "runId", "callId", "automationOccurrenceId", "request", "requestApprovalId", "requestApproval", "grantApprovalId", "state", "result", "terminal", "createdAt", "startedAt", "reportedAt", "plan", "legs" ], "description": "A user-owned financial request with its exact consent, frozen plan, execution claims and public settlement evidence." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get a financial operation Reads one retained financial request even when signing is unavailable. Execution started means its claim committed and the outcome may remain unresolved; it does not prove a process is live. An uncertain operation must never be resubmitted automatically. Reads do not execute or retry financial work. `GET /v1/users/{userId}/financial-operations/{operationId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "operationId", "required": true, "description": "The financial operation's own id, retained across execution and reconciliation." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/financial-operations/YOUR_OPERATION_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The financial request, lifecycle and retained outcome evidence. ```json { "description": "The financial request, lifecycle and retained outcome evidence.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FinancialOperation" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "financialOperations.get", "summary": "Get a financial operation", "tags": [ "financial-operations" ], "description": "Reads one retained financial request even when signing is unavailable. Execution started means its claim committed and the outcome may remain unresolved; it does not prove a process is live. An uncertain operation must never be resubmitted automatically. Reads do not execute or retry financial work.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "operationId", "required": true, "description": "The financial operation's own id, retained across execution and reconciliation." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The financial request, lifecycle and retained outcome evidence.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FinancialOperation" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "FinancialOperation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The durable financial operation's id, independent of any conversation or run." }, "kind": { "type": "string", "enum": [ "withdraw_to_owner", "intents_execute" ], "description": "The requested capability: a direct withdrawal to the owner or an agent's exact intents request." }, "origin": { "type": "string", "enum": [ "direct", "agent" ], "description": "Whether the request came directly from the user or from a recorded agent tool call." }, "conversationId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, { "type": "null" } ], "description": "The proposing agent's conversation; null for a direct request." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The stable public agent run id, retained across approval continuations." }, { "type": "null" } ], "description": "The stable agent run that proposed the request; null for a direct request." }, "callId": { "description": "The actual recorded model tool call that proposed the request; null for a direct request.", "type": [ "string", "null" ] }, "automationOccurrenceId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The actual automation occurrence linked to the proposing run; null when none exists. An occurrence itself grants no financial consent." }, "request": { "anyOf": [ { "type": "object", "properties": { "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact input asset's token id and decimals." } }, "required": [ "pinned" ], "description": "The concrete asset this request spends; it must match the approved action at this position." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact output asset's token id and decimals." } }, "required": [ "pinned" ], "description": "The concrete asset this request produces; it must match the approved action at this position." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact input asset's token id and decimals." } }, "required": [ "pinned" ], "description": "The concrete asset this request spends; it must match the approved action at this position." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact output asset's token id and decimals." } }, "required": [ "pinned" ], "description": "The concrete asset this request produces; it must match the approved action at this position." } }, "required": [ "kind", "input", "quantity", "output" ] } ] }, "description": "The complete ordered financial actions proposed for this execution, with concrete assets and exact quantity rules." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The explicit loss and signature-lifetime limits; these must exactly match the approved grant." } }, "required": [ "actions", "bounds" ] }, { "type": "null" } ], "description": "The original exact actions and bounds; null only for older records that did not retain the request." }, "requestApprovalId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The approval of this exact request, if one was required; null when a standing grant supplies consent." }, "requestApproval": { "anyOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The exact request approval's id." }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ], "description": "The decision state; an undecided approval past its deadline is presented as expired." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest time this approval may authorize execution, even if already approved." }, "contract": { "description": "The exact financial terms retained for this approval, when available.", "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, "executionRestriction": { "description": "Present when the reviewed action was restricted to a mode that cannot sign or move funds.", "type": "string", "const": "signing_disabled" } }, "required": [ "approvalId", "status", "expiresAt" ] }, { "type": "null" } ], "description": "The exact request's review terms and decision, readable without replaying a conversation; null when no request approval exists." }, "grantApprovalId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The approval that created the immutable authorization grant used for execution; null before a grant is bound." }, "state": { "type": "string", "enum": [ "prepared", "denied", "expired", "executing", "reported", "uncertain" ], "description": "The command lifecycle. Prepared awaits consent, denied or expired cannot start, executing has claimed authority, reported has returned an executor outcome, and uncertain records an inconclusive command ending. Later receipts may resolve settlement independently; inspect result and terminal." }, "result": { "anyOf": [ { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "no_trade", "description": "The request resolved without attempting a financial action." } }, "required": [ "status" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "refused", "description": "The financial command refused execution under its authority or safety checks." }, "scope": { "type": "string", "enum": [ "authority", "request", "transient", "insufficient_funds", "request_frozen", "verification", "stale_evidence", "account_busy", "conflict", "paused", "held", "withdrawn" ], "description": "The bounded category of the refusal; no provider text, account details or amounts are exposed here." } }, "required": [ "status", "scope" ] }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "settled", "pending", "partial", "refunded", "not_executed" ], "description": "The financial outcome: settled, unresolved, mixed or incomplete, refunded, or conclusively not executed. Partial may still await receipts; the operation's terminal field states whether reconciliation remains." }, "reason": { "description": "Present when execution was restricted to a mode that cannot sign or move funds.", "type": "string", "const": "signing_disabled" }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The recorded execution or settlement state of this actual leg." } }, "required": [ "index", "state" ] }, "description": "The actual execution legs represented by this outcome; unattempted planned legs have no invented receipt." } }, "required": [ "status", "legs" ] } ] }, { "type": "null" } ], "description": "The latest safe executor or receipt-derived outcome; null before an outcome is known, including denied or expired preparations." }, "terminal": { "type": "boolean", "description": "Whether the request is finished: consent was denied or expired before execution, or execution is conclusively resolved with no actual leg awaiting a receipt. True does not mean funds settled; inspect result and receipts." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the financial request was durably recorded." }, "startedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When execution authority was claimed; null before that claim, and never proof of provider dispatch." }, "reportedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the executor durably reported its outcome; null before reporting. Settlement may resolve later." }, "plan": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The frozen execution plan's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When these execution terms were frozen." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The deadline after which this plan cannot authorize new signing." }, "legs": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input", "description": "Spends the fixed input amount and requires at least minimumOutputRaw in return." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "actionIndex": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The zero-based index of the original requested action this leg implements." }, "input": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the asset's smallest unit as an integer string." } }, "required": [ "tokenId", "decimals", "amountRaw" ], "description": "The pinned input asset and exact amount this leg may spend." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The pinned asset this leg must receive." }, "minimumOutputRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The minimum acceptable output amount, in the output asset's smallest unit as an integer string." }, "referenceOutputRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The reference output amount from trusted price evidence before applying the approved loss bound, in the output asset's smallest unit." } }, "required": [ "kind", "index", "actionIndex", "input", "output", "minimumOutputRaw", "referenceOutputRaw" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output", "description": "Receives the fixed output amount and spends no more than maximumInputRaw." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "actionIndex": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The zero-based index of the original requested action this leg implements." }, "input": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The pinned asset this leg may spend." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the asset's smallest unit as an integer string." } }, "required": [ "tokenId", "decimals", "amountRaw" ], "description": "The pinned output asset and exact amount this leg must receive." }, "maximumInputRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The maximum permitted input amount, in the input asset's smallest unit as an integer string." }, "referenceInputRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The reference input amount from trusted price evidence before applying the approved loss bound, in the input asset's smallest unit." } }, "required": [ "kind", "index", "actionIndex", "input", "output", "maximumInputRaw", "referenceInputRaw" ] } ] }, "description": "Every ordered planned action and its frozen amounts and limits, including actions that were never attempted." } }, "required": [ "id", "createdAt", "expiresAt", "legs" ] }, { "type": "null" } ], "description": "The complete frozen plan, or null before planning. Planned legs are not evidence that an action was attempted." }, "legs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The durable claim's id for this actual execution leg." }, "index": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "This leg's zero-based position in the frozen plan." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The leg's current execution or settlement state; unresolved states require reconciliation, not a second execution." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this execution leg was claimed." }, "signedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the leg's signature was durably recorded; null before signing." }, "settledAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the leg's terminal resolution was recorded; null while unresolved. Consult the receipt to distinguish settlement, refund and non-execution." }, "receipt": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ] }, { "type": "null" } ], "description": "The complete verified public resolution for this actual leg; null while unresolved. Never contains signatures or raw provider payloads." } }, "required": [ "id", "index", "state", "createdAt", "signedAt", "settledAt", "receipt" ] }, "description": "All actual execution legs and their receipts, in plan order. Unattempted planned legs have no invented claim or receipt." } }, "required": [ "id", "kind", "origin", "conversationId", "runId", "callId", "automationOccurrenceId", "request", "requestApprovalId", "requestApproval", "grantApprovalId", "state", "result", "terminal", "createdAt", "startedAt", "reportedAt", "plan", "legs" ], "description": "A user-owned financial request with its exact consent, frozen plan, execution claims and public settlement evidence." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get activity overview Combines active agent conversations, recent ordinary conversations and the newest page of historical milestones. This presentation read links to canonical agent runs and financial operations; activity.history pages older milestones. `GET /v1/users/{userId}/activity` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 }, "in": "query", "name": "limit", "required": false, "description": "How many milestones to answer, at most 50" }, { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "A `before` cursor from the previous page; omit for the newest page." }, { "schema": { "type": "string", "enum": [ "conversation", "automation", "operation" ] }, "in": "query", "name": "origin", "required": false, "description": "Only milestones of this origin: `conversation` for ordinary chats, `automation` for conversations created by automations, or `operation` for direct financial requests without a conversation. Omit to include every origin." }, { "schema": { "type": "string", "enum": [ "all", "actions" ] }, "in": "query", "name": "scope", "required": false, "description": "Which milestones count: `actions` keeps approvals, financial results and automation runs, including direct financial operations; `all` or omitted also includes the ordinary chat lifecycle." }, { "schema": { "default": 8, "type": "integer", "minimum": 1, "maximum": 20 }, "in": "query", "name": "activeLimit", "required": false, "description": "How many active threads to answer, at most 20." }, { "schema": { "default": 6, "type": "integer", "minimum": 1, "maximum": 12 }, "in": "query", "name": "recentLimit", "required": false, "description": "How many recent conversations to answer, at most 12." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/activity' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 Active conversations, recent conversations and newest milestones. ```json { "description": "Active conversations, recent conversations and newest milestones.", "content": { "application/json": { "schema": { "type": "object", "properties": { "active": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Conversation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ], "description": "Running threads or threads with pending approvals; a historical pause alone is not active work." }, "recent": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Conversation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ], "description": "Ordinary conversations ordered by recent activity, excluding automation execution conversations." }, "history": { "type": "object", "properties": { "data": { "maxItems": 50, "type": "array", "items": { "$ref": "#/components/schemas/ConversationActivityItem" }, "description": "This page's milestones, newest first." }, "nextCursor": { "description": "Exclusive descending cursor for the next page; refetch loaded pages sequentially to avoid displaced-item gaps.", "type": [ "string", "null" ] } }, "required": [ "data", "nextCursor" ], "description": "The newest historical milestones, one bounded page." } }, "required": [ "active", "recent", "history" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "activity.overview", "summary": "Get activity overview", "tags": [ "activity" ], "description": "Combines active agent conversations, recent ordinary conversations and the newest page of historical milestones. This presentation read links to canonical agent runs and financial operations; activity.history pages older milestones.", "parameters": [ { "schema": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 }, "in": "query", "name": "limit", "required": false, "description": "How many milestones to answer, at most 50" }, { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "A `before` cursor from the previous page; omit for the newest page." }, { "schema": { "type": "string", "enum": [ "conversation", "automation", "operation" ] }, "in": "query", "name": "origin", "required": false, "description": "Only milestones of this origin: `conversation` for ordinary chats, `automation` for conversations created by automations, or `operation` for direct financial requests without a conversation. Omit to include every origin." }, { "schema": { "type": "string", "enum": [ "all", "actions" ] }, "in": "query", "name": "scope", "required": false, "description": "Which milestones count: `actions` keeps approvals, financial results and automation runs, including direct financial operations; `all` or omitted also includes the ordinary chat lifecycle." }, { "schema": { "default": 8, "type": "integer", "minimum": 1, "maximum": 20 }, "in": "query", "name": "activeLimit", "required": false, "description": "How many active threads to answer, at most 20." }, { "schema": { "default": 6, "type": "integer", "minimum": 1, "maximum": 12 }, "in": "query", "name": "recentLimit", "required": false, "description": "How many recent conversations to answer, at most 12." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "Active conversations, recent conversations and newest milestones.", "content": { "application/json": { "schema": { "type": "object", "properties": { "active": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Conversation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ], "description": "Running threads or threads with pending approvals; a historical pause alone is not active work." }, "recent": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Conversation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ], "description": "Ordinary conversations ordered by recent activity, excluding automation execution conversations." }, "history": { "type": "object", "properties": { "data": { "maxItems": 50, "type": "array", "items": { "$ref": "#/components/schemas/ConversationActivityItem" }, "description": "This page's milestones, newest first." }, "nextCursor": { "description": "Exclusive descending cursor for the next page; refetch loaded pages sequentially to avoid displaced-item gaps.", "type": [ "string", "null" ] } }, "required": [ "data", "nextCursor" ], "description": "The newest historical milestones, one bounded page." } }, "required": [ "active", "recent", "history" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Conversation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "title": { "description": "The conversation's title, or null if none was set.", "type": [ "string", "null" ] }, "origin": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "conversation", "description": "An ordinary user-started conversation." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "automation", "description": "A conversation an automation created." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation that created this conversation." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The automation's name at the time this conversation started." } }, "required": [ "type", "automationId", "name" ] } ], "description": "Where this conversation came from: an ordinary conversation, or one an automation started." }, "runner": { "type": "string", "description": "Which execution engine ran this conversation's turns." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the conversation was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the conversation was last modified." }, "summary": { "type": "object", "properties": { "runStatus": { "anyOf": [ { "type": "string", "const": "idle" }, { "$ref": "#/components/schemas/RunStatus" } ], "description": "What the last run is doing: `idle` before any run, `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals in this conversation are waiting on the user." }, "userMessages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many messages the user has sent in this conversation." }, "assistantMessages": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many messages the assistant has sent in this conversation." }, "toolCalls": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many tool calls the conversation's runs have made." }, "lastEventAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the last journal event landed; null before the first." }, "lastUserText": { "description": "The user's most recent message, for a list preview; null before the first.", "type": [ "string", "null" ] }, "lastAssistantText": { "description": "The assistant's most recent message, for a list preview; null before the first.", "type": [ "string", "null" ] }, "lastRunError": { "description": "The last run's failure message, when its most recent run failed.", "type": [ "string", "null" ] } }, "required": [ "runStatus", "pendingApprovals", "userMessages", "assistantMessages", "toolCalls", "lastEventAt", "lastUserText", "lastAssistantText", "lastRunError" ], "description": "The conversation's current status and a preview, kept current on every journal append." } }, "required": [ "id", "title", "origin", "runner", "createdAt", "updatedAt", "summary" ], "description": "One conversation: its title, origin, and a live summary of its last run." }, "RunStatus": { "type": "string", "enum": [ "running", "completed", "aborted", "failed", "paused" ], "description": "What the run is doing: `running`, or how it stopped — `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending." }, "ConversationActivityItem": { "anyOf": [ { "type": "object", "properties": { "seq": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The event's global journal sequence, used to order this milestone page; not a cross-conversation commit-order guarantee." }, "title": { "description": "The conversation's current title, or null for an untitled conversation or a direct operation.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this milestone happened." }, "kind": { "type": "string", "enum": [ "run_started", "run_completed", "run_failed", "run_aborted", "run_paused", "approval_requested", "approval_approved", "approval_denied", "approval_expired", "automation_triggered", "swap_settled", "swap_refunded", "swap_not_executed", "execution_result" ], "description": "Which historical milestone this journal event records." }, "snippet": { "anyOf": [ { "type": "string", "maxLength": 280 }, { "type": "null" } ], "description": "Bounded public input, approval summary, automation name, or public failure/abort reason." }, "approval": { "description": "Historical approved terms from this event only; never an actionable approval.", "type": "object", "properties": { "contract": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The approved contract: its actions, expiry and bounds." }, "executionRestriction": { "description": "Set when this approval disallowed automatic signing.", "type": "string", "const": "signing_disabled" } }, "required": [ "contract" ] }, "settlement": { "description": "Verified receipt and separate requested terms from its own earlier frozen plan, if recorded.", "type": "object", "properties": { "receipt": { "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ], "description": "The retained terminal evidence for this financial leg: settlement, refund or non-execution." }, "input": { "description": "The frozen plan's input asset and requested amount, when retained; not a measurement of actual spend.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "requestedOutput": { "description": "Exact-output target and input ceiling are requested terms, never paid/received amounts.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "maximumInputRaw": { "description": "The most this leg would spend, in the input asset's smallest unit.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "receipt" ] }, "execution": { "description": "Only reviewed execution tools; never a raw tool result or a claim that the funds settled.", "type": "object", "properties": { "tool": { "type": "string", "enum": [ "intents_execute", "automation_create" ], "description": "Which execution tool produced this result: `intents_execute` for a swap, `automation_create` for setting up an automation." }, "status": { "type": "string", "enum": [ "completed", "failed", "denied", "unverified", "pending", "partial", "no_trade", "settled", "refunded", "not_executed" ], "description": "How the tool resolved: `completed` for a finished non-trade tool; `failed` or `denied` when it did not run (`message` explains why); `unverified` when the result could not be confirmed; `no_trade` when nothing needed to trade; `pending` while settlement is unresolved or `partial` when only part executed; `settled` once every leg settled; `refunded` or `not_executed` when it did not complete." }, "reason": { "description": "Why the tool did not execute; present only when `status` is `not_executed`.", "type": "string", "const": "signing_disabled" }, "message": { "description": "A failed or denied result's own fixed message, so a row says what the card says.", "type": "string", "maxLength": 280 }, "dispatched": { "description": "How many legs the recorded pending or partial result reports; not proof that each was dispatched.", "type": "integer", "minimum": 0, "maximum": 16 } }, "required": [ "tool", "status" ] }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation this historical milestone belongs to." }, "origin": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "conversation", "description": "An ordinary user-started conversation." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "automation", "description": "A conversation an automation created." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation that created this conversation." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The automation's name at the time this conversation started." } }, "required": [ "type", "automationId", "name" ] } ], "description": "The conversation's retained origin, including for financial work requested within it." } }, "required": [ "seq", "title", "createdAt", "kind", "snippet", "conversationId", "origin" ] }, { "type": "object", "properties": { "seq": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The event's global journal sequence, used to order this milestone page; not a cross-conversation commit-order guarantee." }, "title": { "description": "The conversation's current title, or null for an untitled conversation or a direct operation.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this milestone happened." }, "kind": { "type": "string", "enum": [ "run_started", "run_completed", "run_failed", "run_aborted", "run_paused", "approval_requested", "approval_approved", "approval_denied", "approval_expired", "automation_triggered", "swap_settled", "swap_refunded", "swap_not_executed", "execution_result" ], "description": "Which historical milestone this journal event records." }, "snippet": { "anyOf": [ { "type": "string", "maxLength": 280 }, { "type": "null" } ], "description": "Bounded public input, approval summary, automation name, or public failure/abort reason." }, "approval": { "description": "Historical approved terms from this event only; never an actionable approval.", "type": "object", "properties": { "contract": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The approved contract: its actions, expiry and bounds." }, "executionRestriction": { "description": "Set when this approval disallowed automatic signing.", "type": "string", "const": "signing_disabled" } }, "required": [ "contract" ] }, "settlement": { "description": "Verified receipt and separate requested terms from its own earlier frozen plan, if recorded.", "type": "object", "properties": { "receipt": { "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ], "description": "The retained terminal evidence for this financial leg: settlement, refund or non-execution." }, "input": { "description": "The frozen plan's input asset and requested amount, when retained; not a measurement of actual spend.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "requestedOutput": { "description": "Exact-output target and input ceiling are requested terms, never paid/received amounts.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "maximumInputRaw": { "description": "The most this leg would spend, in the input asset's smallest unit.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "receipt" ] }, "execution": { "description": "Only reviewed execution tools; never a raw tool result or a claim that the funds settled.", "type": "object", "properties": { "tool": { "type": "string", "enum": [ "intents_execute", "automation_create" ], "description": "Which execution tool produced this result: `intents_execute` for a swap, `automation_create` for setting up an automation." }, "status": { "type": "string", "enum": [ "completed", "failed", "denied", "unverified", "pending", "partial", "no_trade", "settled", "refunded", "not_executed" ], "description": "How the tool resolved: `completed` for a finished non-trade tool; `failed` or `denied` when it did not run (`message` explains why); `unverified` when the result could not be confirmed; `no_trade` when nothing needed to trade; `pending` while settlement is unresolved or `partial` when only part executed; `settled` once every leg settled; `refunded` or `not_executed` when it did not complete." }, "reason": { "description": "Why the tool did not execute; present only when `status` is `not_executed`.", "type": "string", "const": "signing_disabled" }, "message": { "description": "A failed or denied result's own fixed message, so a row says what the card says.", "type": "string", "maxLength": 280 }, "dispatched": { "description": "How many legs the recorded pending or partial result reports; not proof that each was dispatched.", "type": "integer", "minimum": 0, "maximum": 16 } }, "required": [ "tool", "status" ] }, "conversationId": { "type": "null", "description": "Null because this milestone belongs to a direct operation without a conversation." }, "origin": { "type": "object", "properties": { "type": { "type": "string", "const": "operation", "description": "A direct financial request with no conversation or agent run." }, "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The durable financial operation this activity belongs to." } }, "required": [ "type", "operationId" ], "description": "The direct financial operation that owns this milestone." } }, "required": [ "seq", "title", "createdAt", "kind", "snippet", "conversationId", "origin" ] } ], "description": "One historical journal milestone from an owned conversation or direct financial operation; it does not represent current execution authority." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List activity history Pages backward through durable user-owned milestones, including approvals, run lifecycle and settlement evidence. Omit the cursor for the newest page and pass the returned cursor to continue. `GET /v1/users/{userId}/activity/history` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 }, "in": "query", "name": "limit", "required": false, "description": "How many milestones to answer, at most 50" }, { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "A `before` cursor from the previous page; omit for the newest page." }, { "schema": { "type": "string", "enum": [ "conversation", "automation", "operation" ] }, "in": "query", "name": "origin", "required": false, "description": "Only milestones of this origin: `conversation` for ordinary chats, `automation` for conversations created by automations, or `operation` for direct financial requests without a conversation. Omit to include every origin." }, { "schema": { "type": "string", "enum": [ "all", "actions" ] }, "in": "query", "name": "scope", "required": false, "description": "Which milestones count: `actions` keeps approvals, financial results and automation runs, including direct financial operations; `all` or omitted also includes the ordinary chat lifecycle." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/activity/history' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 A page of historical milestones. ```json { "description": "A page of historical milestones.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "maxItems": 50, "type": "array", "items": { "$ref": "#/components/schemas/ConversationActivityItem" }, "description": "This page's milestones, newest first." }, "nextCursor": { "description": "Exclusive descending cursor for the next page; refetch loaded pages sequentially to avoid displaced-item gaps.", "type": [ "string", "null" ] } }, "required": [ "data", "nextCursor" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "activity.history", "summary": "List activity history", "tags": [ "activity" ], "description": "Pages backward through durable user-owned milestones, including approvals, run lifecycle and settlement evidence. Omit the cursor for the newest page and pass the returned cursor to continue.", "parameters": [ { "schema": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 }, "in": "query", "name": "limit", "required": false, "description": "How many milestones to answer, at most 50" }, { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "A `before` cursor from the previous page; omit for the newest page." }, { "schema": { "type": "string", "enum": [ "conversation", "automation", "operation" ] }, "in": "query", "name": "origin", "required": false, "description": "Only milestones of this origin: `conversation` for ordinary chats, `automation` for conversations created by automations, or `operation` for direct financial requests without a conversation. Omit to include every origin." }, { "schema": { "type": "string", "enum": [ "all", "actions" ] }, "in": "query", "name": "scope", "required": false, "description": "Which milestones count: `actions` keeps approvals, financial results and automation runs, including direct financial operations; `all` or omitted also includes the ordinary chat lifecycle." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "A page of historical milestones.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "maxItems": 50, "type": "array", "items": { "$ref": "#/components/schemas/ConversationActivityItem" }, "description": "This page's milestones, newest first." }, "nextCursor": { "description": "Exclusive descending cursor for the next page; refetch loaded pages sequentially to avoid displaced-item gaps.", "type": [ "string", "null" ] } }, "required": [ "data", "nextCursor" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "ConversationActivityItem": { "anyOf": [ { "type": "object", "properties": { "seq": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The event's global journal sequence, used to order this milestone page; not a cross-conversation commit-order guarantee." }, "title": { "description": "The conversation's current title, or null for an untitled conversation or a direct operation.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this milestone happened." }, "kind": { "type": "string", "enum": [ "run_started", "run_completed", "run_failed", "run_aborted", "run_paused", "approval_requested", "approval_approved", "approval_denied", "approval_expired", "automation_triggered", "swap_settled", "swap_refunded", "swap_not_executed", "execution_result" ], "description": "Which historical milestone this journal event records." }, "snippet": { "anyOf": [ { "type": "string", "maxLength": 280 }, { "type": "null" } ], "description": "Bounded public input, approval summary, automation name, or public failure/abort reason." }, "approval": { "description": "Historical approved terms from this event only; never an actionable approval.", "type": "object", "properties": { "contract": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The approved contract: its actions, expiry and bounds." }, "executionRestriction": { "description": "Set when this approval disallowed automatic signing.", "type": "string", "const": "signing_disabled" } }, "required": [ "contract" ] }, "settlement": { "description": "Verified receipt and separate requested terms from its own earlier frozen plan, if recorded.", "type": "object", "properties": { "receipt": { "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ], "description": "The retained terminal evidence for this financial leg: settlement, refund or non-execution." }, "input": { "description": "The frozen plan's input asset and requested amount, when retained; not a measurement of actual spend.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "requestedOutput": { "description": "Exact-output target and input ceiling are requested terms, never paid/received amounts.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "maximumInputRaw": { "description": "The most this leg would spend, in the input asset's smallest unit.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "receipt" ] }, "execution": { "description": "Only reviewed execution tools; never a raw tool result or a claim that the funds settled.", "type": "object", "properties": { "tool": { "type": "string", "enum": [ "intents_execute", "automation_create" ], "description": "Which execution tool produced this result: `intents_execute` for a swap, `automation_create` for setting up an automation." }, "status": { "type": "string", "enum": [ "completed", "failed", "denied", "unverified", "pending", "partial", "no_trade", "settled", "refunded", "not_executed" ], "description": "How the tool resolved: `completed` for a finished non-trade tool; `failed` or `denied` when it did not run (`message` explains why); `unverified` when the result could not be confirmed; `no_trade` when nothing needed to trade; `pending` while settlement is unresolved or `partial` when only part executed; `settled` once every leg settled; `refunded` or `not_executed` when it did not complete." }, "reason": { "description": "Why the tool did not execute; present only when `status` is `not_executed`.", "type": "string", "const": "signing_disabled" }, "message": { "description": "A failed or denied result's own fixed message, so a row says what the card says.", "type": "string", "maxLength": 280 }, "dispatched": { "description": "How many legs the recorded pending or partial result reports; not proof that each was dispatched.", "type": "integer", "minimum": 0, "maximum": 16 } }, "required": [ "tool", "status" ] }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation this historical milestone belongs to." }, "origin": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "conversation", "description": "An ordinary user-started conversation." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "automation", "description": "A conversation an automation created." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation that created this conversation." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The automation's name at the time this conversation started." } }, "required": [ "type", "automationId", "name" ] } ], "description": "The conversation's retained origin, including for financial work requested within it." } }, "required": [ "seq", "title", "createdAt", "kind", "snippet", "conversationId", "origin" ] }, { "type": "object", "properties": { "seq": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The event's global journal sequence, used to order this milestone page; not a cross-conversation commit-order guarantee." }, "title": { "description": "The conversation's current title, or null for an untitled conversation or a direct operation.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this milestone happened." }, "kind": { "type": "string", "enum": [ "run_started", "run_completed", "run_failed", "run_aborted", "run_paused", "approval_requested", "approval_approved", "approval_denied", "approval_expired", "automation_triggered", "swap_settled", "swap_refunded", "swap_not_executed", "execution_result" ], "description": "Which historical milestone this journal event records." }, "snippet": { "anyOf": [ { "type": "string", "maxLength": 280 }, { "type": "null" } ], "description": "Bounded public input, approval summary, automation name, or public failure/abort reason." }, "approval": { "description": "Historical approved terms from this event only; never an actionable approval.", "type": "object", "properties": { "contract": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The approved contract: its actions, expiry and bounds." }, "executionRestriction": { "description": "Set when this approval disallowed automatic signing.", "type": "string", "const": "signing_disabled" } }, "required": [ "contract" ] }, "settlement": { "description": "Verified receipt and separate requested terms from its own earlier frozen plan, if recorded.", "type": "object", "properties": { "receipt": { "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ], "description": "The retained terminal evidence for this financial leg: settlement, refund or non-execution." }, "input": { "description": "The frozen plan's input asset and requested amount, when retained; not a measurement of actual spend.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "requestedOutput": { "description": "Exact-output target and input ceiling are requested terms, never paid/received amounts.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "maximumInputRaw": { "description": "The most this leg would spend, in the input asset's smallest unit.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "receipt" ] }, "execution": { "description": "Only reviewed execution tools; never a raw tool result or a claim that the funds settled.", "type": "object", "properties": { "tool": { "type": "string", "enum": [ "intents_execute", "automation_create" ], "description": "Which execution tool produced this result: `intents_execute` for a swap, `automation_create` for setting up an automation." }, "status": { "type": "string", "enum": [ "completed", "failed", "denied", "unverified", "pending", "partial", "no_trade", "settled", "refunded", "not_executed" ], "description": "How the tool resolved: `completed` for a finished non-trade tool; `failed` or `denied` when it did not run (`message` explains why); `unverified` when the result could not be confirmed; `no_trade` when nothing needed to trade; `pending` while settlement is unresolved or `partial` when only part executed; `settled` once every leg settled; `refunded` or `not_executed` when it did not complete." }, "reason": { "description": "Why the tool did not execute; present only when `status` is `not_executed`.", "type": "string", "const": "signing_disabled" }, "message": { "description": "A failed or denied result's own fixed message, so a row says what the card says.", "type": "string", "maxLength": 280 }, "dispatched": { "description": "How many legs the recorded pending or partial result reports; not proof that each was dispatched.", "type": "integer", "minimum": 0, "maximum": 16 } }, "required": [ "tool", "status" ] }, "conversationId": { "type": "null", "description": "Null because this milestone belongs to a direct operation without a conversation." }, "origin": { "type": "object", "properties": { "type": { "type": "string", "const": "operation", "description": "A direct financial request with no conversation or agent run." }, "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The durable financial operation this activity belongs to." } }, "required": [ "type", "operationId" ], "description": "The direct financial operation that owns this milestone." } }, "required": [ "seq", "title", "createdAt", "kind", "snippet", "conversationId", "origin" ] } ], "description": "One historical journal milestone from an owned conversation or direct financial operation; it does not represent current execution authority." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List financial activity Returns presentation rows for actual persisted financial requests, newest request first, including direct withdrawals with no conversation. FinancialOperations.get provides the complete canonical request and receipts for each operation identity. `GET /v1/users/{userId}/activity/executions` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 }, "in": "query", "name": "limit", "required": false, "description": "How many financial requests to return, at most 50." }, { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "The opaque cursor returned by the preceding page; omit for the newest requests." }, { "schema": { "type": "string", "enum": [ "conversation", "automation", "operation" ] }, "in": "query", "name": "origin", "required": false, "description": "Filter by retained conversation origin, or `operation` for direct financial requests without a conversation. Omit for every origin." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/activity/executions' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 A page of financial activity and the pending approval count. ```json { "description": "A page of financial activity and the pending approval count.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "maxItems": 50, "type": "array", "items": { "$ref": "#/components/schemas/ExecutionActivityItem" }, "description": "This page of financial requests, newest request first." }, "nextCursor": { "description": "The opaque cursor for the next page of financial requests, or null at the end.", "type": [ "string", "null" ] }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "The caller's unexpired pending approvals across all conversations and direct operations." } }, "required": [ "data", "nextCursor", "pendingApprovals" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "activity.financialOperations", "summary": "List financial activity", "tags": [ "activity" ], "description": "Returns presentation rows for actual persisted financial requests, newest request first, including direct withdrawals with no conversation. FinancialOperations.get provides the complete canonical request and receipts for each operation identity.", "parameters": [ { "schema": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 }, "in": "query", "name": "limit", "required": false, "description": "How many financial requests to return, at most 50." }, { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "The opaque cursor returned by the preceding page; omit for the newest requests." }, { "schema": { "type": "string", "enum": [ "conversation", "automation", "operation" ] }, "in": "query", "name": "origin", "required": false, "description": "Filter by retained conversation origin, or `operation` for direct financial requests without a conversation. Omit for every origin." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "A page of financial activity and the pending approval count.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "maxItems": 50, "type": "array", "items": { "$ref": "#/components/schemas/ExecutionActivityItem" }, "description": "This page of financial requests, newest request first." }, "nextCursor": { "description": "The opaque cursor for the next page of financial requests, or null at the end.", "type": [ "string", "null" ] }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "The caller's unexpired pending approvals across all conversations and direct operations." } }, "required": [ "data", "nextCursor", "pendingApprovals" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "ExecutionActivityItem": { "anyOf": [ { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "maxLength": 200, "description": "The durable financial operation ID, stable across approval, execution and later receipts." }, "title": { "description": "The conversation's current title; null for an untitled conversation or a direct operation.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the financial request was first persisted." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest request or claim creation, execution start, outcome report, signature or settlement timestamp retained for this operation." }, "approval": { "description": "The request's exact human review, when one was required; absent when it uses standing consent or historical review provenance is unknown.", "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The exact single-use review bound to this financial request." }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ], "description": "The recorded human decision, with overdue pending reviews shown as expired; approval alone does not prove execution." }, "contract": { "description": "The exact reviewed financial terms, when retained and readable.", "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, "expiresAt": { "description": "When the exact review ceases to authorize an execution claim.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, "executionRestriction": { "description": "The immutable restriction that prevents automatic signing under this approval.", "type": "string", "const": "signing_disabled" } }, "required": [ "approvalId", "status" ] }, "occurrenceId": { "description": "The actual automation occurrence that requested this operation, when present; never a substitute for its operation ID.", "type": "string", "minLength": 1, "maxLength": 160 }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position in the frozen plan, counting from zero." }, "input": { "description": "The frozen input asset and requested amount when that side was fixed; not measured spend.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "output": { "description": "The frozen output asset and requested amount when that side was fixed; not measured proceeds.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "minimumOutputRaw": { "description": "The minimum output required by an exact-input leg, in the output asset's smallest unit.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" }, "maximumInputRaw": { "description": "The maximum input permitted by an exact-output leg, in the input asset's smallest unit.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" }, "stage": { "description": "The stage derived from the persisted claim while it has no terminal receipt; absent for untouched planned legs.", "type": "string", "enum": [ "quoting", "signed", "confirming", "unresolved" ] }, "legId": { "description": "The actual claim's durable ID; absent when this planned leg was never attempted.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "receipt": { "description": "The retained terminal evidence for the actual leg; untouched planned legs have no receipt.", "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ] } }, "required": [ "index" ] }, "description": "Every leg of the frozen plan in plan order, including untouched legs without claims or receipts; empty before a plan exists." }, "result": { "description": "The persisted command outcome, updated in this read by conclusive receipts; absent while no outcome exists, including denied or expired preparation.", "type": "object", "properties": { "status": { "type": "string", "enum": [ "completed", "failed", "denied", "unverified", "pending", "partial", "no_trade", "settled", "refunded", "not_executed" ], "description": "The canonical financial outcome projected for display; refused requests appear as denied, pending is unresolved and partial means only part executed." }, "reason": { "description": "Present when automatic signing was disabled for the reported non-execution.", "type": "string", "const": "signing_disabled" }, "message": { "description": "The host's fixed explanation for a refused request, when present; never raw provider text.", "type": "string", "maxLength": 280 }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The reported leg's position in the frozen plan, counting from zero." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The retained execution or settlement state for this reported leg." } }, "required": [ "index", "state" ] }, "description": "The actual legs represented by this outcome; untouched planned legs are not fabricated as results." } }, "required": [ "status", "legs" ] }, "running": { "type": "boolean", "description": "True when the operation has an execution claim and no current outcome; it does not prove a process is still running." }, "ended": { "type": "boolean", "description": "True when no outcome is available and the operation is uncertain, denied or expired. Later receipts may resolve uncertainty; this does not assert that settlement is final." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation in which the agent requested this financial operation." }, "origin": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "conversation", "description": "An ordinary user-started conversation." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "automation", "description": "A conversation an automation created." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation that created this conversation." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The automation's name at the time this conversation started." } }, "required": [ "type", "automationId", "name" ] } ], "description": "The conversation's retained origin, even if a user later continued an automation-created conversation." } }, "required": [ "key", "title", "createdAt", "updatedAt", "legs", "running", "ended", "conversationId", "origin" ] }, { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "maxLength": 200, "description": "The durable financial operation ID, stable across approval, execution and later receipts." }, "title": { "description": "The conversation's current title; null for an untitled conversation or a direct operation.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the financial request was first persisted." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest request or claim creation, execution start, outcome report, signature or settlement timestamp retained for this operation." }, "approval": { "description": "The request's exact human review, when one was required; absent when it uses standing consent or historical review provenance is unknown.", "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The exact single-use review bound to this financial request." }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ], "description": "The recorded human decision, with overdue pending reviews shown as expired; approval alone does not prove execution." }, "contract": { "description": "The exact reviewed financial terms, when retained and readable.", "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, "expiresAt": { "description": "When the exact review ceases to authorize an execution claim.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, "executionRestriction": { "description": "The immutable restriction that prevents automatic signing under this approval.", "type": "string", "const": "signing_disabled" } }, "required": [ "approvalId", "status" ] }, "occurrenceId": { "description": "The actual automation occurrence that requested this operation, when present; never a substitute for its operation ID.", "type": "string", "minLength": 1, "maxLength": 160 }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position in the frozen plan, counting from zero." }, "input": { "description": "The frozen input asset and requested amount when that side was fixed; not measured spend.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "output": { "description": "The frozen output asset and requested amount when that side was fixed; not measured proceeds.", "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ] }, "minimumOutputRaw": { "description": "The minimum output required by an exact-input leg, in the output asset's smallest unit.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" }, "maximumInputRaw": { "description": "The maximum input permitted by an exact-output leg, in the input asset's smallest unit.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" }, "stage": { "description": "The stage derived from the persisted claim while it has no terminal receipt; absent for untouched planned legs.", "type": "string", "enum": [ "quoting", "signed", "confirming", "unresolved" ] }, "legId": { "description": "The actual claim's durable ID; absent when this planned leg was never attempted.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "receipt": { "description": "The retained terminal evidence for the actual leg; untouched planned legs have no receipt.", "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ] } }, "required": [ "index" ] }, "description": "Every leg of the frozen plan in plan order, including untouched legs without claims or receipts; empty before a plan exists." }, "result": { "description": "The persisted command outcome, updated in this read by conclusive receipts; absent while no outcome exists, including denied or expired preparation.", "type": "object", "properties": { "status": { "type": "string", "enum": [ "completed", "failed", "denied", "unverified", "pending", "partial", "no_trade", "settled", "refunded", "not_executed" ], "description": "The canonical financial outcome projected for display; refused requests appear as denied, pending is unresolved and partial means only part executed." }, "reason": { "description": "Present when automatic signing was disabled for the reported non-execution.", "type": "string", "const": "signing_disabled" }, "message": { "description": "The host's fixed explanation for a refused request, when present; never raw provider text.", "type": "string", "maxLength": 280 }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The reported leg's position in the frozen plan, counting from zero." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The retained execution or settlement state for this reported leg." } }, "required": [ "index", "state" ] }, "description": "The actual legs represented by this outcome; untouched planned legs are not fabricated as results." } }, "required": [ "status", "legs" ] }, "running": { "type": "boolean", "description": "True when the operation has an execution claim and no current outcome; it does not prove a process is still running." }, "ended": { "type": "boolean", "description": "True when no outcome is available and the operation is uncertain, denied or expired. Later receipts may resolve uncertainty; this does not assert that settlement is final." }, "conversationId": { "type": "null", "description": "Null because this financial request was made directly, without a conversation or agent run." }, "origin": { "type": "object", "properties": { "type": { "type": "string", "const": "operation", "description": "A direct financial request with no conversation or agent run." }, "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The durable financial operation this activity belongs to." } }, "required": [ "type", "operationId" ], "description": "The direct financial operation that owns this activity." } }, "required": [ "key", "title", "createdAt", "updatedAt", "legs", "running", "ended", "conversationId", "origin" ] } ], "description": "One named financial request with its exact review, frozen plan and safe receipts, read from canonical records without reconstructing identity from journal events." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List events The conversation's durable journal, oldest first: every `FinEvent` a run, an approval, an automation trigger or a settlement appended, from the beginning or after the given cursor. `conversations.stream` delivers the same events live; this is how a client backfills what it missed or reads history without holding a connection open. `GET /v1/users/{userId}/conversations/{conversationId}/events` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "An `after` cursor from the previous page; omit to read from the beginning." }, { "schema": { "default": 500, "type": "integer", "minimum": 1, "maximum": 1000 }, "in": "query", "name": "limit", "required": false, "description": "How many events to answer, at most 1000" } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/conversations/YOUR_CONVERSATION_ID/events' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 A page of the conversation's journal. ```json { "description": "A page of the conversation's journal.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/FinEvent" }, "description": "This page's events, oldest first." }, "nextCursor": { "description": "The cursor for the next page, or null at the end as of this read; a live conversation may append more.", "type": [ "string", "null" ] } }, "required": [ "data", "nextCursor" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "events.list", "summary": "List events", "tags": [ "events" ], "description": "The conversation's durable journal, oldest first: every `FinEvent` a run, an approval, an automation trigger or a settlement appended, from the beginning or after the given cursor. `conversations.stream` delivers the same events live; this is how a client backfills what it missed or reads history without holding a connection open.", "parameters": [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "An `after` cursor from the previous page; omit to read from the beginning." }, { "schema": { "default": 500, "type": "integer", "minimum": 1, "maximum": 1000 }, "in": "query", "name": "limit", "required": false, "description": "How many events to answer, at most 1000" }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "A page of the conversation's journal.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/FinEvent" }, "description": "This page's events, oldest first." }, "nextCursor": { "description": "The cursor for the next page, or null at the end as of this read; a live conversation may append more.", "type": [ "string", "null" ] } }, "required": [ "data", "nextCursor" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "FinEvent": { "oneOf": [ { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "run.started", "description": "Identifies this as a `run.started` event." }, "payload": { "type": "object", "properties": { "input": { "type": "string", "description": "The user's message, or the automation's triggering text, that this run processes." }, "origin": { "description": "Which automation triggered this run; absent for an ordinary user turn.", "type": "object", "properties": { "automationId": { "type": "string", "description": "The automation that started this run." }, "name": { "type": "string", "description": "The automation's name at the time it started this run." } }, "required": [ "automationId", "name" ] }, "runId": { "description": "The run this event opened, so a client following the stream can name it (to stop it).", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } }, "required": [ "input" ], "description": "The `run.started` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "Opens a new run: the engine admitted it and is about to process the input, whether an ordinary turn or an automation firing. Emitted once, at admission — a run resumed after an approval does not get a second one. `run.ended` closes what this event opened." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "run.ended", "description": "Identifies this as a `run.ended` event." }, "payload": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "completed", "aborted", "failed", "paused" ], "description": "How the run stopped occupying its execution slot: `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending." }, "usage": { "description": "Token counts and cost for this run, once its accounting settles.", "type": "object", "properties": { "inputTokens": { "type": "number", "description": "How many input tokens the run consumed." }, "outputTokens": { "type": "number", "description": "How many output tokens the run produced." }, "costCents": { "type": "string", "pattern": "^(0|[1-9]\\d*)$", "description": "The run's cost, in whole USD cents." }, "costUncertain": { "type": "boolean", "description": "True when the exact provider cost could not be confirmed and `costCents` is a best-effort estimate." } }, "required": [ "inputTokens", "outputTokens", "costCents", "costUncertain" ] }, "error": { "description": "The run's failure message, present when `status` is `failed`.", "type": "string" }, "failure": { "description": "Structured cause of a failed run: its `code`, `stage` and optional provider detail. Present when `status` is `failed`; absent on runs that failed before this field existed.", "type": "object", "properties": { "code": { "type": "string", "enum": [ "model_timeout", "execution_deadline", "provider_rate_limit", "provider_unavailable", "internal_error", "unknown" ], "description": "Why the execution failed: `model_timeout` (the model was too slow to respond), `execution_deadline` (the run's active time limit elapsed before it finished), `provider_rate_limit` or `provider_unavailable` (classified from the provider's own HTTP status), `internal_error` (a host-side fault), or `unknown` when nothing more specific was classified." }, "stage": { "type": "string", "enum": [ "model_request", "tool_execution", "finalization" ], "description": "Which phase of the run was executing when it failed: `model_request` while calling or awaiting the model provider, `tool_execution` while running or resuming a tool call, or `finalization` while settling the run's output and accounting after the model finished." }, "providerMessage": { "description": "The model provider's own error text, when one was available: credential values are redacted and it is cut to 256 characters, but it is not a content classifier, so other sensitive detail may remain. Treat it as diagnostic context only — never branch on it, and review before showing it to an end user.", "type": "string", "minLength": 1, "maxLength": 256 }, "diagnosticReference": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "This failed run's own id, repeated here as one field to cite when asking support to check the host's internal logs for this execution; it carries no meaning beyond that." } }, "required": [ "code", "stage", "diagnosticReference" ] } }, "required": [ "status" ], "description": "The `run.ended` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "The run stopped occupying its execution slot: `completed` or `failed` once the model finished, `aborted` when stopped early, or `paused` while an approval is pending. Carries token usage and cost once known, and the failure message when it failed. A paused run resumes without a fresh `run.started`." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "agent.entry", "description": "Identifies this as an `agent.entry` event." }, "payload": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "user", "assistant", "tool" ], "description": "Who this message is from: `user`, `assistant`, or `tool` for a tool's own display text." }, "text": { "type": "string", "description": "The message's display text." }, "tool": { "description": "Which tool this entry displays the result of; present only when `role` is `tool`.", "type": "object", "properties": { "name": { "type": "string", "description": "The tool's public name." }, "outcome": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "completed", "description": "The tool ran and returned a result." }, "result": { "description": "The tool's own result value." }, "providerRef": { "description": "The upstream provider's own reference, when it returned one.", "type": "string" } }, "required": [ "status", "result" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "denied", "description": "The call was refused before it ran." }, "error": { "type": "object", "properties": { "code": { "type": "string", "enum": [ "denied", "egress_denied", "invalid_input", "execution_failed" ], "description": "Why the tool call did not produce a result: `denied` by policy or the user, `egress_denied` for a network destination the tool cannot reach, `invalid_input` for arguments the tool rejected, or `execution_failed` for a fault while it ran." }, "message": { "type": "string", "description": "A human-readable explanation of the failure." }, "hint": { "description": "A suggestion for what to try instead, when there is one.", "type": "string" }, "reference": { "description": "Correlation for diagnosis: the request id, or the workflow id of background work. Never a cause.", "type": "string", "maxLength": 128 } }, "required": [ "code", "message" ], "description": "Why the call was denied." } }, "required": [ "status", "error" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "pending_approval", "description": "The call is parked, waiting on a human decision." }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "summary": { "type": "string", "description": "A short human-readable summary of what approving this would do." } }, "required": [ "status", "approvalId", "summary" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "failed", "description": "The call ran but did not complete successfully." }, "error": { "type": "object", "properties": { "code": { "type": "string", "enum": [ "denied", "egress_denied", "invalid_input", "execution_failed" ], "description": "Why the tool call did not produce a result: `denied` by policy or the user, `egress_denied` for a network destination the tool cannot reach, `invalid_input` for arguments the tool rejected, or `execution_failed` for a fault while it ran." }, "message": { "type": "string", "description": "A human-readable explanation of the failure." }, "hint": { "description": "A suggestion for what to try instead, when there is one.", "type": "string" }, "reference": { "description": "Correlation for diagnosis: the request id, or the workflow id of background work. Never a cause.", "type": "string", "maxLength": 128 } }, "required": [ "code", "message" ], "description": "Why the call failed." } }, "required": [ "status", "error" ] } ], "description": "The call's outcome: completed, denied, parked for a human decision, or failed." } }, "required": [ "name", "outcome" ] } }, "required": [ "role", "text" ], "description": "The `agent.entry` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "One durable message in the conversation: the user's message, the assistant's completed reply, or a tool's display text once it resolves. Streaming assistant text arrives first as `agent.text_delta` and lands here only when the turn completes." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "agent.text_delta", "description": "Identifies this as an `agent.text_delta` event." }, "payload": { "type": "object", "properties": { "text": { "type": "string", "description": "The chunk of assistant reply text this delta adds." } }, "required": [ "text" ], "description": "The `agent.text_delta` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "A chunk of the assistant's reply while it is still generating. Delivered live only — never written to the durable journal or replayed on reconnect — and superseded by the complete text in the `agent.entry` that follows." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "tool.call", "description": "Identifies this as a `tool.call` event." }, "payload": { "type": "object", "properties": { "callId": { "description": "This call's id, so later events (`approval.opened`, `tool.result`) can be matched to it.", "type": "string" }, "tool": { "type": "string", "description": "The tool's public name." }, "input": { "description": "The call's arguments, scrubbed for public display." }, "origin": { "description": "Written by the retired standalone CLI door; kept so its journals still parse.", "type": "string", "const": "cli" } }, "required": [ "tool", "input" ], "description": "The `tool.call` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "The assistant asked to call a tool. Emitted once the call is committed to the conversation, before it runs; `approval.opened` follows if a human must decide first, otherwise the call proceeds straight to `tool.result`." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "tool.result", "description": "Identifies this as a `tool.result` event." }, "payload": { "type": "object", "properties": { "callId": { "description": "This call's id, matching the `tool.call` it resolves.", "type": "string" }, "callSeq": { "description": "With `origin`, the retired CLI door's way of pairing a result to its call; historical only.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "tool": { "type": "string", "description": "The tool's public name." }, "outcome": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "completed", "description": "The tool ran and returned a result." }, "result": { "description": "The tool's own result value." }, "providerRef": { "description": "The upstream provider's own reference, when it returned one.", "type": "string" } }, "required": [ "status", "result" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "denied", "description": "The call was refused before it ran." }, "error": { "type": "object", "properties": { "code": { "type": "string", "enum": [ "denied", "egress_denied", "invalid_input", "execution_failed" ], "description": "Why the tool call did not produce a result: `denied` by policy or the user, `egress_denied` for a network destination the tool cannot reach, `invalid_input` for arguments the tool rejected, or `execution_failed` for a fault while it ran." }, "message": { "type": "string", "description": "A human-readable explanation of the failure." }, "hint": { "description": "A suggestion for what to try instead, when there is one.", "type": "string" }, "reference": { "description": "Correlation for diagnosis: the request id, or the workflow id of background work. Never a cause.", "type": "string", "maxLength": 128 } }, "required": [ "code", "message" ], "description": "Why the call was denied." } }, "required": [ "status", "error" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "pending_approval", "description": "The call is parked, waiting on a human decision." }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "summary": { "type": "string", "description": "A short human-readable summary of what approving this would do." } }, "required": [ "status", "approvalId", "summary" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "failed", "description": "The call ran but did not complete successfully." }, "error": { "type": "object", "properties": { "code": { "type": "string", "enum": [ "denied", "egress_denied", "invalid_input", "execution_failed" ], "description": "Why the tool call did not produce a result: `denied` by policy or the user, `egress_denied` for a network destination the tool cannot reach, `invalid_input` for arguments the tool rejected, or `execution_failed` for a fault while it ran." }, "message": { "type": "string", "description": "A human-readable explanation of the failure." }, "hint": { "description": "A suggestion for what to try instead, when there is one.", "type": "string" }, "reference": { "description": "Correlation for diagnosis: the request id, or the workflow id of background work. Never a cause.", "type": "string", "maxLength": 128 } }, "required": [ "code", "message" ], "description": "Why the call failed." } }, "required": [ "status", "error" ] } ], "description": "The call's outcome: completed, denied, parked for a human decision, or failed." }, "origin": { "description": "Written by the retired standalone CLI door; kept so its journals still parse.", "type": "string", "const": "cli" } }, "required": [ "tool", "outcome" ], "description": "The `tool.result` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "One tool call resolved: `outcome` says what happened (completed, denied, parked for approval, or failed). Immediately followed by an `agent.entry` (role `tool`) carrying that outcome's own display text." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "approval.opened", "description": "Identifies this as an `approval.opened` event." }, "payload": { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "callId": { "description": "The tool call this approval parks; absent for direct operations without a model call.", "type": "string" }, "tool": { "type": "string", "description": "The tool name awaiting approval." }, "input": { "description": "The call's arguments, as shown on the approval card." }, "summary": { "type": "string", "description": "A short human-readable summary of what approving this would do." }, "contract": { "description": "Effective terms rendered before approval; absent for tools without authorization contracts.", "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, "executionRestriction": { "description": "Set when this approval disallows automatic signing; fixed when the approval opened, never inferred from the current UI mode.", "type": "string", "const": "signing_disabled" }, "expiresAt": { "description": "When the parked decision lapses; optional so journal entries written before it still parse.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" } }, "required": [ "approvalId", "tool", "input", "summary" ], "description": "The `approval.opened` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "A tool call is parked, waiting on a human decision. Carries the terms the approval card renders: the call's input, a summary, and the authorization contract in effect, if any. `approval.decided` or `approval.expired` closes it." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "approval.decided", "description": "Identifies this as an `approval.decided` event." }, "payload": { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "approve": { "type": "boolean", "description": "True when the user approved; false when denied." }, "reason": { "description": "The user's reason, mainly given with a denial.", "type": "string" }, "attestation": { "description": "The partner-side confirmation cited for the decision; never verified by fin.", "type": "object", "properties": { "reference": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The partner's own reference for its confirmation." } }, "required": [ "reference" ] }, "decidedBy": { "description": "Which integration released it; absent on journals written before v1, null for the deployment's own app.", "type": "object", "properties": { "partnerKeyId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The partner key that released this decision; null for the deployment's own app." } }, "required": [ "partnerKeyId" ] } }, "required": [ "approvalId", "approve" ], "description": "The `approval.decided` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "The user, or a partner integration, approved or denied a parked approval. `approve` says which way; a denial may carry `reason`. Consuming the decision to execute the tool follows as `approval.consumed`, but only when the decision was an approval — a denial never reaches consumption." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "approval.consumed", "description": "Identifies this as an `approval.consumed` event." }, "payload": { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." } }, "required": [ "approvalId" ], "description": "The `approval.consumed` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "The approval was spent to authorize its tool call, immediately before that call runs. This is when the call is authorized, not when it finishes: the call can still fail after this event lands, and nothing here rolls it back. Marks the approval used; it cannot authorize a second execution." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "approval.expired", "description": "Identifies this as an `approval.expired` event." }, "payload": { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "reason": { "type": "string", "description": "Why the approval expired: the deadline passed, or its run stopped first." } }, "required": [ "approvalId", "reason" ], "description": "The `approval.expired` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "A parked approval lapsed before anyone decided: its deadline passed, or the run it belongs to stopped while it was still pending." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "automation.fired", "description": "Identifies this as an `automation.fired` event." }, "payload": { "type": "object", "properties": { "automationId": { "type": "string", "description": "The automation that fired this run." }, "name": { "type": "string", "description": "The automation's name at the time it fired." } }, "required": [ "automationId", "name" ], "description": "The `automation.fired` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "An automation triggered this conversation's run. Emitted once, immediately before the `run.started` it precedes, naming the automation and its name at fire time." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "intents.settlement", "description": "Identifies this as an `intents.settlement` event." }, "payload": { "oneOf": [ { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "settled", "description": "The leg settled: its output asset moved as planned." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What the leg produced." } }, "required": [ "approvalId", "legId", "index", "state", "output" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "refunded", "description": "The leg did not settle and its input asset was returned." }, "refund": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "What was returned." } }, "required": [ "approvalId", "legId", "index", "state", "refund" ] }, { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "legId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "Which leg of the plan this receipt settles." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current receipts use `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "state": { "type": "string", "const": "not_executed", "description": "The leg did not settle. Most reasons mean it never reached the provider; `rejected` means it did and was refused there — see `reason`." }, "reason": { "description": "Why nothing executed: `signing_disabled` when automatic signing was off, `signing_failed` when signing itself failed, `rejected` when the provider refused the submission outright (it did reach the provider), `expired` when the leg's own signing/deposit window elapsed before a terminal fact arrived, or `failed` otherwise. Optional so receipts written before the reason was carried still parse.", "type": "string", "enum": [ "signing_disabled", "signing_failed", "rejected", "expired", "failed" ] } }, "required": [ "approvalId", "legId", "index", "state" ] } ], "description": "The `intents.settlement` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "A later, independently verified financial fact about one leg of an authorized swap — settled, refunded, or never executed — never inferred from the model's own tool result. Appended whenever the provider confirms the outcome, independent of the run that requested it; `legId` and `operationId` join it back to its financial request, progress and authorizing approval. Archived receipts retain their original `occurrenceId`." }, { "type": "object", "properties": { "seq": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The event's position in the conversation's journal; strictly increasing." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event was appended to the journal." }, "requestId": { "description": "The request that produced this event, when one did; null for scheduler and recovery writes.", "type": [ "string", "null" ] }, "type": { "type": "string", "const": "intents.progress", "description": "Identifies this as an `intents.progress` event." }, "payload": { "oneOf": [ { "type": "object", "properties": { "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current progress uses `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The grant's approval id: the chat approval for a one-shot, the creation approval for an automation." }, "kind": { "type": "string", "const": "planning", "description": "Authorized; reading balances and prices to freeze the plan." } }, "required": [ "approvalId", "kind" ] }, { "type": "object", "properties": { "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current progress uses `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The grant's approval id: the chat approval for a one-shot, the creation approval for an automation." }, "kind": { "type": "string", "const": "planned", "description": "The frozen plan: every swap, with the amount on the side the plan fixed." }, "legs": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "This leg's position within the plan, counting from zero." }, "input": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "The input asset and, when the plan fixed this side, the exact amount it spends." }, "output": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's NEP-141 token id." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." }, "amountRaw": { "description": "The amount, in the token's smallest unit, when it is known.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "tokenId", "decimals" ], "description": "The output asset and, when the plan fixed this side, the exact amount it receives." }, "minimumOutputRaw": { "description": "The floor an exact-input swap's output must clear; present only when the input side is fixed.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" }, "maximumInputRaw": { "description": "The ceiling an exact-output swap's input may spend; present only when the output side is fixed.", "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$" } }, "required": [ "index", "input", "output" ] }, "description": "Every swap in the frozen plan, indexed from zero." } }, "required": [ "approvalId", "kind", "legs" ] }, { "type": "object", "properties": { "operationId": { "description": "The durable financial request this evidence belongs to.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "occurrenceId": { "description": "The archived event's original identity, retained verbatim; current progress uses `operationId`.", "type": "string", "minLength": 1, "maxLength": 160 }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The grant's approval id: the chat approval for a one-shot, the creation approval for an automation." }, "kind": { "type": "string", "const": "stage", "description": "One swap moved; `legId` joins it to its receipt once the swap is claimed." }, "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "Which leg, by position, this update is about." }, "stage": { "type": "string", "enum": [ "quoting", "signed", "confirming", "unresolved" ], "description": "What the executor is doing right now, between approval and a receipt: `quoting` while it fetches and validates the provider quote, then claims and signs; `signed` once the signature is persisted, about to submit; `confirming` once submitted (or recovered), waiting for the provider's terminal fact; `unresolved` when the run's settle budget ended before a terminal fact and the sweep continues." }, "legId": { "description": "Joins this stage to its settlement receipt once the swap is claimed; absent before then.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" } }, "required": [ "approvalId", "kind", "index", "stage" ] } ], "description": "The `intents.progress` event's own fields." } }, "required": [ "seq", "conversationId", "createdAt", "requestId", "type", "payload" ], "description": "Best-effort, display-only progress for an authorized swap, between approval and its settlement receipt: freezing the plan (`planning`), the frozen legs (`planned`), then each leg's own stage (`stage`). Never gates execution and may arrive out of order or not at all; an `intents.settlement` receipt always takes precedence, and a terminal outcome is never reported here." } ], "description": "One journal entry: the event type and its payload, in the order it happened." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Stream events Opens a live `text/event-stream` (SSE) for one conversation: replays durable journal events strictly after the cursor, then delivers new events — durable and live — as they happen. Reconnect with `Last-Event-ID` or `?cursor=` to resume exactly where a dropped connection left off; `events.list` reads the same durable history without holding a connection open. `GET /v1/users/{userId}/conversations/{conversationId}/stream` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ] ``` ## Query parameters ```json [ { "schema": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "in": "query", "name": "cursor", "required": false, "description": "Resume strictly after this journal `seq`; omit or 0 to start from the beginning. The `Last-Event-ID` header overrides it on reconnect." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/conversations/YOUR_CONVERSATION_ID/stream' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 A `text/event-stream` of conversation events. Each frame's SSE `id` is the journal `seq` (durable frames only), `event` is the `FinEvent` type, and `data` is `{ delivery, seq, payload }`: `delivery: "durable"` for a journaled event (with `seq` and `requestId`), or `delivery: "live"` for a presentation-only frame such as `agent.text_delta` (no `seq`, never replayed). Resume with the `Last-Event-ID` header or `?cursor=`. ```json { "description": "A `text/event-stream` of conversation events. Each frame's SSE `id` is the journal `seq` (durable frames only), `event` is the `FinEvent` type, and `data` is `{ delivery, seq, payload }`: `delivery: \"durable\"` for a journaled event (with `seq` and `requestId`), or `delivery: \"live\"` for a presentation-only frame such as `agent.text_delta` (no `seq`, never replayed). Resume with the `Last-Event-ID` header or `?cursor=`.", "content": { "text/event-stream": { "schema": { "type": "string" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` - `stream_capacity` — no stream socket is free on this replica or for this user; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` — no stream socket is free on this replica or for this user; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "conversations.stream", "summary": "Stream events", "tags": [ "events" ], "description": "Opens a live `text/event-stream` (SSE) for one conversation: replays durable journal events strictly after the cursor, then delivers new events — durable and live — as they happen. Reconnect with `Last-Event-ID` or `?cursor=` to resume exactly where a dropped connection left off; `events.list` reads the same durable history without holding a connection open.", "parameters": [ { "schema": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "in": "query", "name": "cursor", "required": false, "description": "Resume strictly after this journal `seq`; omit or 0 to start from the beginning. The `Last-Event-ID` header overrides it on reconnect." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "A `text/event-stream` of conversation events. Each frame's SSE `id` is the journal `seq` (durable frames only), `event` is the `FinEvent` type, and `data` is `{ delivery, seq, payload }`: `delivery: \"durable\"` for a journaled event (with `seq` and `requestId`), or `delivery: \"live\"` for a presentation-only frame such as `agent.text_delta` (no `seq`, never replayed). Resume with the `Last-Event-ID` header or `?cursor=`.", "content": { "text/event-stream": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` — no stream socket is free on this replica or for this user; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List approvals Lists the caller's approvals, newest first. Defaults to `pending`; pass `status` to include decided or expired ones instead, or `all` for every status. `GET /v1/users/{userId}/approvals` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "default": "pending", "type": "string", "enum": [ "pending", "approved", "denied", "expired", "all" ] }, "in": "query", "name": "status", "required": false, "description": "Which approvals to include: `pending` (the default, since it is the only status a caller can act on), `approved`, `denied`, `expired`, or `all`." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/approvals' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 A page of the caller's approvals. ```json { "description": "A page of the caller's approvals.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Approval" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "approvals.list", "summary": "List approvals", "tags": [ "approvals" ], "description": "Lists the caller's approvals, newest first. Defaults to `pending`; pass `status` to include decided or expired ones instead, or `all` for every status.", "parameters": [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "default": "pending", "type": "string", "enum": [ "pending", "approved", "denied", "expired", "all" ] }, "in": "query", "name": "status", "required": false, "description": "Which approvals to include: `pending` (the default, since it is the only status a caller can act on), `approved`, `denied`, `expired`, or `all`." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "A page of the caller's approvals.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Approval" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Approval": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "tool": { "type": "string", "description": "The name of the tool call parked for a decision." }, "fingerprint": { "type": "string", "description": "Fingerprint binding this decision to the exact reviewed action." }, "input": { "description": "The exact public tool input retained for review.", "$ref": "#/components/schemas/JsonValue" }, "contract": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, { "type": "null" } ], "description": "The exact financial terms this decision authorizes, or null for an ordinary tool." }, "summary": { "type": "string", "description": "A short human-readable summary of what approving this would do." }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ], "description": "The parked decision's state: `pending` while it awaits a decision and has not expired, `approved` or `denied` once the caller decided, or `expired` when no decision arrived before `expiresAt`." }, "reason": { "description": "Why it was decided, if the decider gave one.", "type": [ "string", "null" ] }, "requestedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the tool call was parked." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the parked decision lapses if nobody decides it." }, "decidedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When it was approved or denied; null until then." }, "consumedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the approval was spent to authorize its call, immediately before that call ran; null until then, and always null when denied. The call itself can still fail after this is set — this is not proof the call succeeded, or even that it finished." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The stable public run that opened this decision; null for older unlinked history." }, "operationId": { "type": "null", "description": "Absent for a run-owned approval; the financial operation may link to this approval separately." } }, "required": [ "id", "tool", "fingerprint", "input", "contract", "summary", "status", "reason", "requestedAt", "expiresAt", "decidedAt", "consumedAt", "conversationId", "runId", "operationId" ] }, { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "tool": { "type": "string", "description": "The name of the tool call parked for a decision." }, "fingerprint": { "type": "string", "description": "Fingerprint binding this decision to the exact reviewed action." }, "input": { "description": "The exact public tool input retained for review.", "$ref": "#/components/schemas/JsonValue" }, "contract": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, { "type": "null" } ], "description": "The exact financial terms this decision authorizes, or null for an ordinary tool." }, "summary": { "type": "string", "description": "A short human-readable summary of what approving this would do." }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ], "description": "The parked decision's state: `pending` while it awaits a decision and has not expired, `approved` or `denied` once the caller decided, or `expired` when no decision arrived before `expiresAt`." }, "reason": { "description": "Why it was decided, if the decider gave one.", "type": [ "string", "null" ] }, "requestedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the tool call was parked." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the parked decision lapses if nobody decides it." }, "decidedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When it was approved or denied; null until then." }, "consumedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the approval was spent to authorize its call, immediately before that call ran; null until then, and always null when denied. The call itself can still fail after this is set — this is not proof the call succeeded, or even that it finished." }, "conversationId": { "type": "null", "description": "Always null: a direct financial review belongs to its operation, not a conversation." }, "runId": { "type": "null", "description": "Always null: a direct financial review has no agent run." }, "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The direct financial operation this review authorizes." } }, "required": [ "id", "tool", "fingerprint", "input", "contract", "summary", "status", "reason", "requestedAt", "expiresAt", "decidedAt", "consumedAt", "conversationId", "runId", "operationId" ] } ], "description": "An exact user-owned decision, its review terms and durable consent state." }, "JsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/JsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/JsonValue" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get an approval Returns the caller-owned approval and exact review input for agent or direct financial work. `GET /v1/users/{userId}/approvals/{approvalId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "approvalId", "required": true, "description": "The approval's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/approvals/YOUR_APPROVAL_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The approval and its immutable review input. ```json { "description": "The approval and its immutable review input.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Approval" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "approvals.get", "summary": "Get an approval", "tags": [ "approvals" ], "description": "Returns the caller-owned approval and exact review input for agent or direct financial work.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "approvalId", "required": true, "description": "The approval's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The approval and its immutable review input.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Approval" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Approval": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "tool": { "type": "string", "description": "The name of the tool call parked for a decision." }, "fingerprint": { "type": "string", "description": "Fingerprint binding this decision to the exact reviewed action." }, "input": { "description": "The exact public tool input retained for review.", "$ref": "#/components/schemas/JsonValue" }, "contract": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, { "type": "null" } ], "description": "The exact financial terms this decision authorizes, or null for an ordinary tool." }, "summary": { "type": "string", "description": "A short human-readable summary of what approving this would do." }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ], "description": "The parked decision's state: `pending` while it awaits a decision and has not expired, `approved` or `denied` once the caller decided, or `expired` when no decision arrived before `expiresAt`." }, "reason": { "description": "Why it was decided, if the decider gave one.", "type": [ "string", "null" ] }, "requestedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the tool call was parked." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the parked decision lapses if nobody decides it." }, "decidedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When it was approved or denied; null until then." }, "consumedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the approval was spent to authorize its call, immediately before that call ran; null until then, and always null when denied. The call itself can still fail after this is set — this is not proof the call succeeded, or even that it finished." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The stable public run that opened this decision; null for older unlinked history." }, "operationId": { "type": "null", "description": "Absent for a run-owned approval; the financial operation may link to this approval separately." } }, "required": [ "id", "tool", "fingerprint", "input", "contract", "summary", "status", "reason", "requestedAt", "expiresAt", "decidedAt", "consumedAt", "conversationId", "runId", "operationId" ] }, { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval's id." }, "tool": { "type": "string", "description": "The name of the tool call parked for a decision." }, "fingerprint": { "type": "string", "description": "Fingerprint binding this decision to the exact reviewed action." }, "input": { "description": "The exact public tool input retained for review.", "$ref": "#/components/schemas/JsonValue" }, "contract": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ] }, { "type": "null" } ], "description": "The exact financial terms this decision authorizes, or null for an ordinary tool." }, "summary": { "type": "string", "description": "A short human-readable summary of what approving this would do." }, "status": { "type": "string", "enum": [ "pending", "approved", "denied", "expired" ], "description": "The parked decision's state: `pending` while it awaits a decision and has not expired, `approved` or `denied` once the caller decided, or `expired` when no decision arrived before `expiresAt`." }, "reason": { "description": "Why it was decided, if the decider gave one.", "type": [ "string", "null" ] }, "requestedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the tool call was parked." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the parked decision lapses if nobody decides it." }, "decidedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When it was approved or denied; null until then." }, "consumedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the approval was spent to authorize its call, immediately before that call ran; null until then, and always null when denied. The call itself can still fail after this is set — this is not proof the call succeeded, or even that it finished." }, "conversationId": { "type": "null", "description": "Always null: a direct financial review belongs to its operation, not a conversation." }, "runId": { "type": "null", "description": "Always null: a direct financial review has no agent run." }, "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The direct financial operation this review authorizes." } }, "required": [ "id", "tool", "fingerprint", "input", "contract", "summary", "status", "reason", "requestedAt", "expiresAt", "decidedAt", "consumedAt", "conversationId", "runId", "operationId" ] } ], "description": "An exact user-owned decision, its review terms and durable consent state." }, "JsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/JsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/JsonValue" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Approve a tool call Approves the parked tool call named in the path and resumes the run that opened it, which takes its execution slot again exactly as new work does. If the resume cannot be admitted, the decision is not recorded and the approval stays pending; the call otherwise answers once the decision is durable. `approval.decided` follows at once on the journal, and `approval.consumed` follows once the approval is spent to authorize the call — immediately before it runs, not once it finishes; the call can still fail afterward. `POST /v1/users/{userId}/approvals/{approvalId}/approve` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "approvalId", "required": true, "description": "The approval's id." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "reason": { "description": "Why the call was approved, for the record.", "type": "string", "maxLength": 1024 }, "attestation": { "description": "A partner-side confirmation reference, recorded on the journal event; never verified by fin.", "type": "object", "properties": { "reference": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The partner's own reference for this confirmation." } }, "required": [ "reference" ], "additionalProperties": false } }, "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/approvals/YOUR_APPROVAL_ID/approve' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data '{}' ``` ## Responses ### 200 The decision was recorded. ```json { "description": "The decision was recorded.", "content": { "application/json": { "schema": { "type": "object", "properties": { "decided": { "type": "boolean", "description": "Always true: the call answers only once the decision is durable.", "enum": [ true ] } }, "required": [ "decided" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `approval_not_pending` — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation - `run_active` — a run already holds this conversation - `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again - `execution_unavailable` — the execution engine could not take the work - `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed ```json { "description": "The operation lost to the current state.\n\n- `approval_not_pending` — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `run_active` — a run already holds this conversation\n- `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` — the execution engine could not take the work\n- `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "approvals.approve", "summary": "Approve a tool call", "tags": [ "approvals" ], "description": "Approves the parked tool call named in the path and resumes the run that opened it, which takes its execution slot again exactly as new work does. If the resume cannot be admitted, the decision is not recorded and the approval stays pending; the call otherwise answers once the decision is durable. `approval.decided` follows at once on the journal, and `approval.consumed` follows once the approval is spent to authorize the call — immediately before it runs, not once it finishes; the call can still fail afterward.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "reason": { "description": "Why the call was approved, for the record.", "type": "string", "maxLength": 1024 }, "attestation": { "description": "A partner-side confirmation reference, recorded on the journal event; never verified by fin.", "type": "object", "properties": { "reference": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The partner's own reference for this confirmation." } }, "required": [ "reference" ], "additionalProperties": false } }, "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "approvalId", "required": true, "description": "The approval's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The decision was recorded.", "content": { "application/json": { "schema": { "type": "object", "properties": { "decided": { "type": "boolean", "description": "Always true: the call answers only once the decision is durable.", "enum": [ true ] } }, "required": [ "decided" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `approval_not_pending` — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `run_active` — a run already holds this conversation\n- `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` — the execution engine could not take the work\n- `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Deny a tool call Denies the parked tool call named in the path and resumes the run that opened it so it can continue without the call's result, which takes its execution slot again exactly as new work does. If the resume cannot be admitted, the decision is not recorded and the approval stays pending; the call otherwise answers once the decision is durable, and `approval.decided` follows at once on the journal. `POST /v1/users/{userId}/approvals/{approvalId}/deny` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "approvalId", "required": true, "description": "The approval's id." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "reason": { "description": "Why the call was denied, for the record.", "type": "string", "maxLength": 1024 } }, "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/approvals/YOUR_APPROVAL_ID/deny' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data '{}' ``` ## Responses ### 200 The decision was recorded. ```json { "description": "The decision was recorded.", "content": { "application/json": { "schema": { "type": "object", "properties": { "decided": { "type": "boolean", "description": "Always true: the call answers only once the decision is durable.", "enum": [ true ] } }, "required": [ "decided" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `approval_not_pending` — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation - `run_active` — a run already holds this conversation - `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again - `execution_unavailable` — the execution engine could not take the work - `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed ```json { "description": "The operation lost to the current state.\n\n- `approval_not_pending` — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `run_active` — a run already holds this conversation\n- `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` — the execution engine could not take the work\n- `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "approvals.deny", "summary": "Deny a tool call", "tags": [ "approvals" ], "description": "Denies the parked tool call named in the path and resumes the run that opened it so it can continue without the call's result, which takes its execution slot again exactly as new work does. If the resume cannot be admitted, the decision is not recorded and the approval stays pending; the call otherwise answers once the decision is durable, and `approval.decided` follows at once on the journal.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "reason": { "description": "Why the call was denied, for the record.", "type": "string", "maxLength": 1024 } }, "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "approvalId", "required": true, "description": "The approval's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The decision was recorded.", "content": { "application/json": { "schema": { "type": "object", "properties": { "decided": { "type": "boolean", "description": "Always true: the call answers only once the decision is durable.", "enum": [ true ] } }, "required": [ "decided" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `approval_not_pending` — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `run_active` — a run already holds this conversation\n- `execution_capacity` — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` — the execution engine could not take the work\n- `stop_pending` — a stop is already in progress and its cleanup is not yet confirmed", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List files Lists the conversation's files, oldest first: uploads and files a sandbox command left in its outbox. Read one back with `artifacts.download`. `GET /v1/users/{userId}/conversations/{conversationId}/artifacts` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/conversations/YOUR_CONVERSATION_ID/artifacts' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The conversation's files. ```json { "description": "The conversation's files.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Artifact" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "artifacts.list", "summary": "List files", "tags": [ "artifacts" ], "description": "Lists the conversation's files, oldest first: uploads and files a sandbox command left in its outbox. Read one back with `artifacts.download`.", "parameters": [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The conversation's files.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Artifact" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Artifact": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The artifact's id." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The run whose sandbox produced it; null for uploads and standalone tool calls." }, "origin": { "type": "string", "enum": [ "upload", "sandbox" ], "description": "How the file entered the conversation: `upload` from the caller, or `sandbox` from a run's sandbox command." }, "name": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$", "description": "The file's name: one path segment of letters, digits, `.`, `_` and `-`." }, "mediaType": { "type": "string", "maxLength": 128, "description": "As declared by the uploader; downloads are always served as opaque bytes." }, "bytes": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "The file's size in bytes." }, "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "The file's SHA-256 digest, lowercase hex." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the file was attached." } }, "required": [ "id", "conversationId", "runId", "origin", "name", "mediaType", "bytes", "sha256", "createdAt" ], "description": "One file attached to a conversation: an upload, or a file a sandbox command produced." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Attach a file Attaches a file to the conversation. The request body is the file's raw bytes; `Content-Type` declares its media type, and `?name=` names it. The upload answers with the new artifact. `POST /v1/users/{userId}/conversations/{conversationId}/artifacts` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$" }, "in": "query", "name": "name", "required": true, "description": "The file's name: one path segment of letters, digits, `.`, `_` and `-`." } ] ``` ## Request body ```json { "required": true, "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/conversations/YOUR_CONVERSATION_ID/artifacts?name=YOUR_NAME' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/octet-stream' \ --data-binary '@file.bin' ``` ## Responses ### 201 The new artifact. ```json { "description": "The new artifact.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Artifact" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "artifacts.upload", "summary": "Attach a file", "tags": [ "artifacts" ], "description": "Attaches a file to the conversation. The request body is the file's raw bytes; `Content-Type` declares its media type, and `?name=` names it. The upload answers with the new artifact.", "requestBody": { "required": true, "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "parameters": [ { "schema": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$" }, "in": "query", "name": "name", "required": true, "description": "The file's name: one path segment of letters, digits, `.`, `_` and `-`." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "201": { "description": "The new artifact.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Artifact" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Artifact": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The artifact's id." }, "conversationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The run whose sandbox produced it; null for uploads and standalone tool calls." }, "origin": { "type": "string", "enum": [ "upload", "sandbox" ], "description": "How the file entered the conversation: `upload` from the caller, or `sandbox` from a run's sandbox command." }, "name": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$", "description": "The file's name: one path segment of letters, digits, `.`, `_` and `-`." }, "mediaType": { "type": "string", "maxLength": 128, "description": "As declared by the uploader; downloads are always served as opaque bytes." }, "bytes": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "The file's size in bytes." }, "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "The file's SHA-256 digest, lowercase hex." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the file was attached." } }, "required": [ "id", "conversationId", "runId", "origin", "name", "mediaType", "bytes", "sha256", "createdAt" ], "description": "One file attached to a conversation: an upload, or a file a sandbox command produced." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Download a file Downloads one file as an opaque attachment (`application/octet-stream`), whatever media type its uploader declared; a file is never rendered on the API's own origin. `GET /v1/users/{userId}/conversations/{conversationId}/artifacts/{artifactId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "artifactId", "required": true, "description": "The artifact's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/conversations/YOUR_CONVERSATION_ID/artifacts/YOUR_ARTIFACT_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The file's bytes, as an attachment ```json { "description": "The file's bytes, as an attachment", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "artifacts.download", "summary": "Download a file", "tags": [ "artifacts" ], "description": "Downloads one file as an opaque attachment (`application/octet-stream`), whatever media type its uploader declared; a file is never rendered on the API's own origin.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "conversationId", "required": true, "description": "The conversation's id." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "artifactId", "required": true, "description": "The artifact's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The file's bytes, as an attachment", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get agent wallet Returns the user's agent wallet, or `null` if `wallets.ensure` has not created one yet. Never returns key material. `GET /v1/users/{userId}/wallet` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/wallet' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The user's agent wallet, or null. ```json { "description": "The user's agent wallet, or null.", "content": { "application/json": { "schema": { "type": "object", "properties": { "wallet": { "anyOf": [ { "$ref": "#/components/schemas/Wallet" }, { "type": "null" } ], "description": "The user's agent wallet, or `null` until `wallets.ensure` creates one." } }, "required": [ "wallet" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it - `provider_unavailable` — an external provider the call depends on did not answer ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "wallets.get", "summary": "Get agent wallet", "tags": [ "wallets" ], "description": "Returns the user's agent wallet, or `null` if `wallets.ensure` has not created one yet. Never returns key material.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The user's agent wallet, or null.", "content": { "application/json": { "schema": { "type": "object", "properties": { "wallet": { "anyOf": [ { "$ref": "#/components/schemas/Wallet" }, { "type": "null" } ], "description": "The user's agent wallet, or `null` until `wallets.ensure` creates one." } }, "required": [ "wallet" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } } }, "components": { "schemas": { "Wallet": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The agent wallet's own id, distinct from the user's." }, "address": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "The agent wallet's NEAR implicit account, as 64 lowercase hex characters." }, "intentsAccountId": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "The same account as the intents system addresses it; today identical to `address`." }, "status": { "type": "string", "enum": [ "active", "disabled" ], "description": "Whether the wallet can act: `active`, or `disabled` after an operator turns it off." }, "authStatus": { "type": "string", "enum": [ "pending", "ready", "authorization_required" ], "description": "Whether the wallet can reach its provider session: `pending` before the first connection, `ready` once one is stored, `authorization_required` after the provider rejects it and the owner must reconnect (`wallets.ensure`)." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the wallet was created." } }, "required": [ "id", "address", "intentsAccountId", "status", "authStatus", "createdAt" ], "description": "The user's agent wallet: its accounts and whether it can act right now. Never a key." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Create agent wallet Creates the user's agent wallet if one does not exist yet, or returns the existing one — safe to call more than once. Also reconnects the provider session, so this is the call that clears `authorization_required`. `POST /v1/users/{userId}/wallet` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/wallet' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The user's agent wallet. ```json { "description": "The user's agent wallet.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Wallet" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it - `provider_unavailable` — an external provider the call depends on did not answer ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "wallets.ensure", "summary": "Create agent wallet", "tags": [ "wallets" ], "description": "Creates the user's agent wallet if one does not exist yet, or returns the existing one — safe to call more than once. Also reconnects the provider session, so this is the call that clears `authorization_required`.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The user's agent wallet.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Wallet" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } } }, "components": { "schemas": { "Wallet": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The agent wallet's own id, distinct from the user's." }, "address": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "The agent wallet's NEAR implicit account, as 64 lowercase hex characters." }, "intentsAccountId": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "The same account as the intents system addresses it; today identical to `address`." }, "status": { "type": "string", "enum": [ "active", "disabled" ], "description": "Whether the wallet can act: `active`, or `disabled` after an operator turns it off." }, "authStatus": { "type": "string", "enum": [ "pending", "ready", "authorization_required" ], "description": "Whether the wallet can reach its provider session: `pending` before the first connection, `ready` once one is stored, `authorization_required` after the provider rejects it and the owner must reconnect (`wallets.ensure`)." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the wallet was created." } }, "required": [ "id", "address", "intentsAccountId", "status", "authStatus", "createdAt" ], "description": "The user's agent wallet: its accounts and whether it can act right now. Never a key." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get wallet balances Returns the wallet's current portfolio: every held asset with its provider price and USD value, and the total. Prices and balances are read live from the provider on each call. `GET /v1/users/{userId}/wallet/balances` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/wallet/balances' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The wallet's portfolio: its assets, their total value, and the wallet itself. ```json { "description": "The wallet's portfolio: its assets, their total value, and the wallet itself.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WalletBalances" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it - `provider_unavailable` — an external provider the call depends on did not answer ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "wallets.balances", "summary": "Get wallet balances", "tags": [ "wallets" ], "description": "Returns the wallet's current portfolio: every held asset with its provider price and USD value, and the total. Prices and balances are read live from the provider on each call.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The wallet's portfolio: its assets, their total value, and the wallet itself.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WalletBalances" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } } }, "components": { "schemas": { "WalletBalances": { "type": "object", "properties": { "assets": { "maxItems": 10000, "type": "array", "items": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 512, "description": "Which asset this is, as the provider identifies it (for example `nep141:usdc.omft.near`)." }, "symbol": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The asset's ticker symbol, as the provider reports it." }, "name": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's display name, as the provider reports it." }, "decimals": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 255 }, { "type": "null" } ], "description": "How many decimal places `amountRaw` carries; `null` if the provider does not name this asset." }, "amountRaw": { "type": "string", "maxLength": 160, "pattern": "^(0|[1-9]\\d*)$", "description": "The held amount, as a decimal string in the asset's smallest unit, never a float; scale by `decimals` for a human amount." }, "priceUsdDecimal": { "anyOf": [ { "type": "string", "maxLength": 500, "pattern": "^(0|[1-9]\\d*)(\\.\\d+)?$" }, { "type": "null" } ], "description": "The asset's price in USD, as a decimal string, never a float; `null` if the provider has no price for it." }, "valueUsdCents": { "anyOf": [ { "type": "string", "maxLength": 160, "pattern": "^(0|[1-9]\\d*)$" }, { "type": "null" } ], "description": "This holding's value, in US cents as a decimal integer string, never a float; `null` if `priceUsdDecimal` is `null`." }, "iconUrl": { "anyOf": [ { "type": "string", "format": "uri" }, { "type": "null" } ], "description": "An https icon for the asset, or `null` if the provider has none." } }, "required": [ "tokenId", "symbol", "name", "decimals", "amountRaw", "priceUsdDecimal", "valueUsdCents", "iconUrl" ] }, "description": "Every asset the wallet holds, by USD value highest first; unpriced assets sort last." }, "totalUsdCents": { "anyOf": [ { "type": "string", "maxLength": 160, "pattern": "^(0|[1-9]\\d*)$" }, { "type": "null" } ], "description": "The sum of every priced asset's value, in US cents as a decimal integer string, never a float; `null` if any asset's price is unknown." }, "asOf": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this snapshot was read from the provider." }, "wallet": { "$ref": "#/components/schemas/Wallet" } }, "required": [ "assets", "totalUsdCents", "asOf", "wallet" ], "description": "The wallet's portfolio: every held asset, their total value, and the wallet itself." }, "Wallet": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The agent wallet's own id, distinct from the user's." }, "address": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "The agent wallet's NEAR implicit account, as 64 lowercase hex characters." }, "intentsAccountId": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "The same account as the intents system addresses it; today identical to `address`." }, "status": { "type": "string", "enum": [ "active", "disabled" ], "description": "Whether the wallet can act: `active`, or `disabled` after an operator turns it off." }, "authStatus": { "type": "string", "enum": [ "pending", "ready", "authorization_required" ], "description": "Whether the wallet can reach its provider session: `pending` before the first connection, `ready` once one is stored, `authorization_required` after the provider rejects it and the owner must reconnect (`wallets.ensure`)." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the wallet was created." } }, "required": [ "id", "address", "intentsAccountId", "status", "authStatus", "createdAt" ], "description": "The user's agent wallet: its accounts and whether it can act right now. Never a key." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List withdrawal sources Lists what the wallet can withdraw right now: each asset with a positive, transferable balance held in the agent wallet's own account, and the owner's main account a withdrawal would pay out to. Feeds `wallets.prepareWithdrawal`. `GET /v1/users/{userId}/wallet/withdrawals/sources` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/wallet/withdrawals/sources' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 What can be withdrawn right now, and where it would go. ```json { "description": "What can be withdrawn right now, and where it would go.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WithdrawalSources" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it - `provider_unavailable` — an external provider the call depends on did not answer ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "wallets.withdrawalSources", "summary": "List withdrawal sources", "tags": [ "wallets" ], "description": "Lists what the wallet can withdraw right now: each asset with a positive, transferable balance held in the agent wallet's own account, and the owner's main account a withdrawal would pay out to. Feeds `wallets.prepareWithdrawal`.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "What can be withdrawn right now, and where it would go.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WithdrawalSources" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } } }, "components": { "schemas": { "WithdrawalSources": { "type": "object", "properties": { "assets": { "type": "array", "items": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 512, "description": "Which asset this is, as the provider identifies it (for example `nep141:usdc.omft.near`)." }, "symbol": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The asset's ticker symbol, as the provider reports it." }, "name": { "type": "string", "minLength": 1, "maxLength": 256, "description": "The asset's display name, as the provider reports it." }, "decimals": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 255 }, { "type": "null" } ], "description": "How many decimal places `amountRaw` carries; `null` if the provider does not name this asset." }, "amountRaw": { "type": "string", "maxLength": 160, "pattern": "^(0|[1-9]\\d*)$", "description": "The held amount, as a decimal string in the asset's smallest unit, never a float; scale by `decimals` for a human amount." }, "priceUsdDecimal": { "anyOf": [ { "type": "string", "maxLength": 500, "pattern": "^(0|[1-9]\\d*)(\\.\\d+)?$" }, { "type": "null" } ], "description": "The asset's price in USD, as a decimal string, never a float; `null` if the provider has no price for it." }, "valueUsdCents": { "anyOf": [ { "type": "string", "maxLength": 160, "pattern": "^(0|[1-9]\\d*)$" }, { "type": "null" } ], "description": "This holding's value, in US cents as a decimal integer string, never a float; `null` if `priceUsdDecimal` is `null`." }, "iconUrl": { "anyOf": [ { "type": "string", "format": "uri" }, { "type": "null" } ], "description": "An https icon for the asset, or `null` if the provider has none." } }, "required": [ "tokenId", "symbol", "name", "decimals", "amountRaw", "priceUsdDecimal", "valueUsdCents", "iconUrl" ] }, "description": "Assets the wallet holds with a positive balance and known decimals; only these can be withdrawn, richest first." }, "mainAccountId": { "type": "string", "description": "The owner's main wallet account; where a withdrawal lands. Shown for display only — the contract itself never names a destination." }, "agentAccountId": { "type": "string", "description": "The agent wallet's own intents account; where these balances are held today." }, "asOf": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When these balances were read from the provider." } }, "required": [ "assets", "mainAccountId", "agentAccountId", "asOf" ], "description": "What the wallet can withdraw right now, and where it would go." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Prepare a withdrawal Builds the exact withdrawal contract for the given asset and amount, and opens the approval that stands for it. Nothing is signed and no key is touched: this only returns the terms to review and the `fingerprint` that `wallets.confirmWithdrawal` must echo back unchanged. `POST /v1/users/{userId}/wallet/withdrawals` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 512, "description": "Which asset to withdraw, as the provider identifies it: one of `wallets.withdrawalSources`' assets." }, "amountRaw": { "type": "string", "maxLength": 160, "pattern": "^(0|[1-9]\\d*)$", "description": "How much to withdraw, as a decimal string in the asset's smallest unit, never a float. Must be positive and no more than the current balance." } }, "required": [ "tokenId", "amountRaw" ], "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/wallet/withdrawals' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data-binary '@request.json' ``` ## Responses ### 200 The withdrawal's exact terms and the approval opened for them. ```json { "description": "The withdrawal's exact terms and the approval opened for them.", "content": { "application/json": { "schema": { "type": "object", "properties": { "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "This withdrawal's id; pass it to `wallets.confirmWithdrawal`." }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval opened for this withdrawal; echo it back to confirm." }, "fingerprint": { "type": "string", "description": "What `wallets.confirmWithdrawal` must echo back exactly, so confirming something other than what was reviewed here cannot happen." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this approval expires; confirm before then, or prepare again." }, "mainAccountId": { "type": "string", "description": "The owner's main wallet account this withdrawal would pay out to." }, "contract": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "description": "Which contract template this is.", "enum": [ "near_intents_transfer" ] }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Exchange one asset for another; custody never leaves the agent wallet.", "enum": [ "swap" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Return an asset to the account that owns the agent wallet.", "enum": [ "withdraw_to_owner" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Pay a pinned destination outside the agent wallet.", "enum": [ "send" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The exact authorization contract this withdrawal runs under, precisely as the approval card shows it." } }, "required": [ "operationId", "approvalId", "fingerprint", "expiresAt", "mainAccountId", "contract" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `withdrawal_changed` — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress ```json { "description": "The operation lost to the current state.\n\n- `withdrawal_changed` — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it - `provider_unavailable` — an external provider the call depends on did not answer ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "wallets.prepareWithdrawal", "summary": "Prepare a withdrawal", "tags": [ "wallets" ], "description": "Builds the exact withdrawal contract for the given asset and amount, and opens the approval that stands for it. Nothing is signed and no key is touched: this only returns the terms to review and the `fingerprint` that `wallets.confirmWithdrawal` must echo back unchanged.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "tokenId": { "type": "string", "minLength": 1, "maxLength": 512, "description": "Which asset to withdraw, as the provider identifies it: one of `wallets.withdrawalSources`' assets." }, "amountRaw": { "type": "string", "maxLength": 160, "pattern": "^(0|[1-9]\\d*)$", "description": "How much to withdraw, as a decimal string in the asset's smallest unit, never a float. Must be positive and no more than the current balance." } }, "required": [ "tokenId", "amountRaw" ], "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The withdrawal's exact terms and the approval opened for them.", "content": { "application/json": { "schema": { "type": "object", "properties": { "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "This withdrawal's id; pass it to `wallets.confirmWithdrawal`." }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval opened for this withdrawal; echo it back to confirm." }, "fingerprint": { "type": "string", "description": "What `wallets.confirmWithdrawal` must echo back exactly, so confirming something other than what was reviewed here cannot happen." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this approval expires; confirm before then, or prepare again." }, "mainAccountId": { "type": "string", "description": "The owner's main wallet account this withdrawal would pay out to." }, "contract": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "description": "Which contract template this is.", "enum": [ "near_intents_transfer" ] }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Exchange one asset for another; custody never leaves the agent wallet.", "enum": [ "swap" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Return an asset to the account that owns the agent wallet.", "enum": [ "withdraw_to_owner" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Pay a pinned destination outside the agent wallet.", "enum": [ "send" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The exact authorization contract this withdrawal runs under, precisely as the approval card shows it." } }, "required": [ "operationId", "approvalId", "fingerprint", "expiresAt", "mainAccountId", "contract" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `withdrawal_changed` — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it\n- `provider_unavailable` — an external provider the call depends on did not answer", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get a withdrawal Reads the retained direct withdrawal resource without requiring a signing provider. After an interrupted confirmation, query this id to recover the recorded outcome; execution_started or uncertain must not cause automatic resubmission. `GET /v1/users/{userId}/wallet/withdrawals/{operationId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "operationId", "required": true, "description": "The withdrawal's id, from `wallets.prepareWithdrawal`." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/wallet/withdrawals/YOUR_OPERATION_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The withdrawal request, consent state and retained outcome. ```json { "description": "The withdrawal request, consent state and retained outcome.", "content": { "application/json": { "schema": { "type": "object", "properties": { "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "This withdrawal's id; pass it to `wallets.confirmWithdrawal`." }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval opened for this withdrawal; echo it back to confirm." }, "fingerprint": { "type": "string", "description": "What `wallets.confirmWithdrawal` must echo back exactly, so confirming something other than what was reviewed here cannot happen." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this approval expires; confirm before then, or prepare again." }, "mainAccountId": { "type": "string", "description": "The owner's main wallet account this withdrawal would pay out to." }, "contract": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "description": "Which contract template this is.", "enum": [ "near_intents_transfer" ] }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Exchange one asset for another; custody never leaves the agent wallet.", "enum": [ "swap" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Return an asset to the account that owns the agent wallet.", "enum": [ "withdraw_to_owner" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Pay a pinned destination outside the agent wallet.", "enum": [ "send" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The exact authorization contract this withdrawal runs under, precisely as the approval card shows it." }, "state": { "type": "string", "enum": [ "pending_approval", "expired", "denied", "execution_started", "pending_settlement", "completed", "uncertain" ], "description": "Durable withdrawal state; a claimed execution is not evidence of settlement." }, "result": { "anyOf": [ { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "description": "The request resolved without attempting a financial action.", "enum": [ "no_trade" ] } }, "required": [ "status" ] }, { "type": "object", "properties": { "status": { "type": "string", "description": "The financial command refused execution under its authority or safety checks.", "enum": [ "refused" ] }, "scope": { "type": "string", "enum": [ "authority", "request", "transient", "insufficient_funds", "request_frozen", "verification", "stale_evidence", "account_busy", "conflict", "paused", "held", "withdrawn" ], "description": "The bounded category of the refusal; no provider text, account details or amounts are exposed here." } }, "required": [ "status", "scope" ] }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "settled", "pending", "partial", "refunded", "not_executed" ], "description": "The financial outcome: settled, unresolved, mixed or incomplete, refunded, or conclusively not executed. Partial may still await receipts; the operation's terminal field states whether reconciliation remains." }, "reason": { "description": "Present when execution was restricted to a mode that cannot sign or move funds.", "type": "string", "enum": [ "signing_disabled" ] }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The recorded execution or settlement state of this actual leg." } }, "required": [ "index", "state" ] }, "description": "The actual execution legs represented by this outcome; unattempted planned legs have no invented receipt." } }, "required": [ "status", "legs" ] } ] }, { "type": "null" } ], "description": "The recorded command outcome, or null before a result is recorded; pending and uncertain outcomes do not prove settlement." }, "planId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The frozen execution plan id, or null before a plan was admitted." } }, "required": [ "operationId", "approvalId", "fingerprint", "expiresAt", "mainAccountId", "contract", "state", "result", "planId" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "wallets.getWithdrawal", "summary": "Get a withdrawal", "tags": [ "wallets" ], "description": "Reads the retained direct withdrawal resource without requiring a signing provider. After an interrupted confirmation, query this id to recover the recorded outcome; execution_started or uncertain must not cause automatic resubmission.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "operationId", "required": true, "description": "The withdrawal's id, from `wallets.prepareWithdrawal`." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The withdrawal request, consent state and retained outcome.", "content": { "application/json": { "schema": { "type": "object", "properties": { "operationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "This withdrawal's id; pass it to `wallets.confirmWithdrawal`." }, "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval opened for this withdrawal; echo it back to confirm." }, "fingerprint": { "type": "string", "description": "What `wallets.confirmWithdrawal` must echo back exactly, so confirming something other than what was reviewed here cannot happen." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this approval expires; confirm before then, or prepare again." }, "mainAccountId": { "type": "string", "description": "The owner's main wallet account this withdrawal would pay out to." }, "contract": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "description": "Which contract template this is.", "enum": [ "near_intents_transfer" ] }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Exchange one asset for another; custody never leaves the agent wallet.", "enum": [ "swap" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Return an asset to the account that owns the agent wallet.", "enum": [ "withdraw_to_owner" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Pay a pinned destination outside the agent wallet.", "enum": [ "send" ] }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend an exact amount of the input token.", "enum": [ "exact_input_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a USD-denominated value of the input token.", "enum": [ "exact_input_value_usd" ] }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Receive an exact amount of the output token.", "enum": [ "exact_output_tokens" ] }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend everything the agent wallet holds of the input asset.", "enum": [ "all_of_input" ] } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "description": "Spend a fraction of the input asset.", "enum": [ "fraction_of_input" ] }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "description": "Any token the agent wallet holds; the executor picks one at execution.", "enum": [ true ] } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The exact authorization contract this withdrawal runs under, precisely as the approval card shows it." }, "state": { "type": "string", "enum": [ "pending_approval", "expired", "denied", "execution_started", "pending_settlement", "completed", "uncertain" ], "description": "Durable withdrawal state; a claimed execution is not evidence of settlement." }, "result": { "anyOf": [ { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "description": "The request resolved without attempting a financial action.", "enum": [ "no_trade" ] } }, "required": [ "status" ] }, { "type": "object", "properties": { "status": { "type": "string", "description": "The financial command refused execution under its authority or safety checks.", "enum": [ "refused" ] }, "scope": { "type": "string", "enum": [ "authority", "request", "transient", "insufficient_funds", "request_frozen", "verification", "stale_evidence", "account_busy", "conflict", "paused", "held", "withdrawn" ], "description": "The bounded category of the refusal; no provider text, account details or amounts are exposed here." } }, "required": [ "status", "scope" ] }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "settled", "pending", "partial", "refunded", "not_executed" ], "description": "The financial outcome: settled, unresolved, mixed or incomplete, refunded, or conclusively not executed. Partial may still await receipts; the operation's terminal field states whether reconciliation remains." }, "reason": { "description": "Present when execution was restricted to a mode that cannot sign or move funds.", "type": "string", "enum": [ "signing_disabled" ] }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The recorded execution or settlement state of this actual leg." } }, "required": [ "index", "state" ] }, "description": "The actual execution legs represented by this outcome; unattempted planned legs have no invented receipt." } }, "required": [ "status", "legs" ] } ] }, { "type": "null" } ], "description": "The recorded command outcome, or null before a result is recorded; pending and uncertain outcomes do not prove settlement." }, "planId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The frozen execution plan id, or null before a plan was admitted." } }, "required": [ "operationId", "approvalId", "fingerprint", "expiresAt", "mainAccountId", "contract", "state", "result", "planId" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Confirm a withdrawal Confirms the exact reviewed withdrawal and atomically spends its approval while claiming the financial operation. A duplicate confirmation returns the retained outcome or unresolved resource without executing again. Authority and terms are rechecked before dispatch; a consumed approval does not imply funds moved. The durable withdrawal lookup and financial operation resource retain pending, refused, uncertain and settled outcomes. Never automatically retry an unresolved financial action. `POST /v1/users/{userId}/wallet/withdrawals/{operationId}/confirm` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "operationId", "required": true, "description": "The withdrawal's id, from `wallets.prepareWithdrawal`." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval id `wallets.prepareWithdrawal` returned." }, "fingerprint": { "type": "string", "minLength": 1, "maxLength": 200, "description": "The exact fingerprint `wallets.prepareWithdrawal` returned." } }, "required": [ "approvalId", "fingerprint" ], "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/wallet/withdrawals/YOUR_OPERATION_ID/confirm' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data-binary '@request.json' ``` ## Responses ### 200 The outcome reached before answering. ```json { "description": "The outcome reached before answering.", "content": { "application/json": { "schema": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "description": "The request resolved without attempting a financial action.", "enum": [ "no_trade" ] } }, "required": [ "status" ] }, { "type": "object", "properties": { "status": { "type": "string", "description": "The financial command refused execution under its authority or safety checks.", "enum": [ "refused" ] }, "scope": { "type": "string", "enum": [ "authority", "request", "transient", "insufficient_funds", "request_frozen", "verification", "stale_evidence", "account_busy", "conflict", "paused", "held", "withdrawn" ], "description": "The bounded category of the refusal; no provider text, account details or amounts are exposed here." } }, "required": [ "status", "scope" ] }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "settled", "pending", "partial", "refunded", "not_executed" ], "description": "The financial outcome: settled, unresolved, mixed or incomplete, refunded, or conclusively not executed. Partial may still await receipts; the operation's terminal field states whether reconciliation remains." }, "reason": { "description": "Present when execution was restricted to a mode that cannot sign or move funds.", "type": "string", "enum": [ "signing_disabled" ] }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The recorded execution or settlement state of this actual leg." } }, "required": [ "index", "state" ] }, "description": "The actual execution legs represented by this outcome; unattempted planned legs have no invented receipt." } }, "required": [ "status", "legs" ] } ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `withdrawal_changed` — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress ```json { "description": "The operation lost to the current state.\n\n- `withdrawal_changed` — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "wallets.confirmWithdrawal", "summary": "Confirm a withdrawal", "tags": [ "wallets" ], "description": "Confirms the exact reviewed withdrawal and atomically spends its approval while claiming the financial operation. A duplicate confirmation returns the retained outcome or unresolved resource without executing again. Authority and terms are rechecked before dispatch; a consumed approval does not imply funds moved. The durable withdrawal lookup and financial operation resource retain pending, refused, uncertain and settled outcomes. Never automatically retry an unresolved financial action.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "approvalId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The approval id `wallets.prepareWithdrawal` returned." }, "fingerprint": { "type": "string", "minLength": 1, "maxLength": 200, "description": "The exact fingerprint `wallets.prepareWithdrawal` returned." } }, "required": [ "approvalId", "fingerprint" ], "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "operationId", "required": true, "description": "The withdrawal's id, from `wallets.prepareWithdrawal`." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The outcome reached before answering.", "content": { "application/json": { "schema": { "anyOf": [ { "type": "object", "properties": { "status": { "type": "string", "description": "The request resolved without attempting a financial action.", "enum": [ "no_trade" ] } }, "required": [ "status" ] }, { "type": "object", "properties": { "status": { "type": "string", "description": "The financial command refused execution under its authority or safety checks.", "enum": [ "refused" ] }, "scope": { "type": "string", "enum": [ "authority", "request", "transient", "insufficient_funds", "request_frozen", "verification", "stale_evidence", "account_busy", "conflict", "paused", "held", "withdrawn" ], "description": "The bounded category of the refusal; no provider text, account details or amounts are exposed here." } }, "required": [ "status", "scope" ] }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "settled", "pending", "partial", "refunded", "not_executed" ], "description": "The financial outcome: settled, unresolved, mixed or incomplete, refunded, or conclusively not executed. Partial may still await receipts; the operation's terminal field states whether reconciliation remains." }, "reason": { "description": "Present when execution was restricted to a mode that cannot sign or move funds.", "type": "string", "enum": [ "signing_disabled" ] }, "legs": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": 0, "maximum": 15, "description": "The leg's zero-based position in the frozen plan." }, "state": { "type": "string", "enum": [ "claimed", "signed", "uncertain", "settled", "refunded", "not_executed" ], "description": "The recorded execution or settlement state of this actual leg." } }, "required": [ "index", "state" ] }, "description": "The actual execution legs represented by this outcome; unattempted planned legs have no invented receipt." } }, "required": [ "status", "legs" ] } ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `withdrawal_changed` — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get spend headroom Reports whether the caller can spend right now: the day and month caps, what is reserved by runs in flight, what is already spent, and any operator freeze. Admission checks this same headroom before it lets a run start. `GET /v1/users/{userId}/budget` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/budget' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The user's current budget headroom. ```json { "description": "The user's current budget headroom.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Budget" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "budgets.headroom", "summary": "Get spend headroom", "tags": [ "budgets" ], "description": "Reports whether the caller can spend right now: the day and month caps, what is reserved by runs in flight, what is already spent, and any operator freeze. Admission checks this same headroom before it lets a run start.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The user's current budget headroom.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Budget" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Budget": { "type": "object", "properties": { "ok": { "type": "boolean", "description": "True while every period still has headroom and the pool is not frozen." }, "frozen": { "type": "boolean", "description": "The operator's per-user freeze: no headroom at all, whatever the periods hold." }, "snapshots": { "type": "array", "items": { "type": "object", "properties": { "periodKind": { "type": "string", "enum": [ "day", "month" ], "description": "Which period this snapshot covers: `day` (the UTC calendar day) or `month` (the calendar month)." }, "capCents": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The spend cap for this period, in cents, as a JSON integer (not a string)." }, "reservedCents": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Cents held by runs still in flight against this period's cap, as a JSON integer (not a string)." }, "spentCents": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Cents already spent and settled against this period's cap, as a JSON integer (not a string)." } }, "required": [ "periodKind", "capCents", "reservedCents", "spentCents" ] }, "description": "The day and month periods this pool tracks, each with its cap and current usage." } }, "required": [ "ok", "frozen", "snapshots" ], "description": "The user's spend headroom for the current periods: whether they can spend, and the day/month caps that decide it." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List event sources Lists the event sources an automation's rule may watch, each with its configuration schema, its data fields, and this owner's current ability to use it. Reading the catalog does not fetch a live value or create a connection. `GET /v1/users/{userId}/automation-sources` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/automation-sources' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The event sources an automation may watch. ```json { "description": "The event sources an automation may watch.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AutomationSource" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automationSources.list", "summary": "List event sources", "tags": [ "automations" ], "description": "Lists the event sources an automation's rule may watch, each with its configuration schema, its data fields, and this owner's current ability to use it. Reading the catalog does not fetch a live value or create a connection.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The event sources an automation may watch.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AutomationSource" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "AutomationSource": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The operation's id within the catalog." }, "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The operation's version." }, "label": { "type": "string", "minLength": 1, "maxLength": 120, "description": "A short display name for this source." }, "description": { "type": "string", "maxLength": 2048, "description": "What this source reads, in the catalog's own words." }, "semanticIdentity": { "type": "string", "minLength": 1, "maxLength": 2048, "description": "What this operation actually reads, independent of its exact configuration; used to tell equivalent sources apart." }, "schemaFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of this operation's exact configuration and result field types, derived from the registry." }, "configSchema": { "type": "object", "properties": { "type": { "type": "string", "const": "object", "description": "Always `object`: a source's configuration is a flat set of named fields." }, "properties": { "type": "object", "propertyNames": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "additionalProperties": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "title": { "description": "A short label for this configuration field, for display.", "type": "string", "maxLength": 120 }, "description": { "description": "Help text for this configuration field, for display.", "type": "string", "maxLength": 2048 }, "type": { "type": "string", "const": "string", "description": "A text value." }, "enum": { "description": "The exact values allowed, when this field is closed to a fixed list.", "minItems": 1, "maxItems": 128, "type": "array", "items": { "type": "string", "maxLength": 4096 } }, "minLength": { "description": "The shortest allowed length, in characters.", "type": "integer", "minimum": 0, "maximum": 4096 }, "maxLength": { "description": "The longest allowed length, in characters.", "type": "integer", "minimum": 0, "maximum": 4096 }, "pattern": { "description": "A regular expression this field's value must match, when its shape is constrained.", "type": "string", "maxLength": 1024 }, "default": { "description": "The value used when this field is left unset.", "type": "string", "maxLength": 4096 } }, "required": [ "type" ] }, { "type": "object", "properties": { "title": { "description": "A short label for this configuration field, for display.", "type": "string", "maxLength": 120 }, "description": { "description": "Help text for this configuration field, for display.", "type": "string", "maxLength": 2048 }, "type": { "type": "string", "const": "boolean", "description": "A true/false value." }, "default": { "description": "The value used when this field is left unset.", "type": "boolean" } }, "required": [ "type" ] }, { "type": "object", "properties": { "title": { "description": "A short label for this configuration field, for display.", "type": "string", "maxLength": 120 }, "description": { "description": "Help text for this configuration field, for display.", "type": "string", "maxLength": 2048 }, "type": { "type": "string", "const": "integer", "description": "A whole-number value." }, "minimum": { "description": "The smallest allowed value.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "maximum": { "description": "The largest allowed value.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "enum": { "description": "The exact values allowed, when this field is closed to a fixed list.", "minItems": 1, "maxItems": 128, "type": "array", "items": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "default": { "description": "The value used when this field is left unset.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "type" ] } ] }, { "type": "object", "properties": { "title": { "description": "A short label for this configuration field, for display.", "type": "string", "maxLength": 120 }, "description": { "description": "Help text for this configuration field, for display.", "type": "string", "maxLength": 2048 }, "type": { "type": "string", "const": "array", "description": "A list of scalar values." }, "items": { "oneOf": [ { "type": "object", "properties": { "title": { "description": "A short label for this configuration field, for display.", "type": "string", "maxLength": 120 }, "description": { "description": "Help text for this configuration field, for display.", "type": "string", "maxLength": 2048 }, "type": { "type": "string", "const": "string", "description": "A text value." }, "enum": { "description": "The exact values allowed, when this field is closed to a fixed list.", "minItems": 1, "maxItems": 128, "type": "array", "items": { "type": "string", "maxLength": 4096 } }, "minLength": { "description": "The shortest allowed length, in characters.", "type": "integer", "minimum": 0, "maximum": 4096 }, "maxLength": { "description": "The longest allowed length, in characters.", "type": "integer", "minimum": 0, "maximum": 4096 }, "pattern": { "description": "A regular expression this field's value must match, when its shape is constrained.", "type": "string", "maxLength": 1024 }, "default": { "description": "The value used when this field is left unset.", "type": "string", "maxLength": 4096 } }, "required": [ "type" ] }, { "type": "object", "properties": { "title": { "description": "A short label for this configuration field, for display.", "type": "string", "maxLength": 120 }, "description": { "description": "Help text for this configuration field, for display.", "type": "string", "maxLength": 2048 }, "type": { "type": "string", "const": "boolean", "description": "A true/false value." }, "default": { "description": "The value used when this field is left unset.", "type": "boolean" } }, "required": [ "type" ] }, { "type": "object", "properties": { "title": { "description": "A short label for this configuration field, for display.", "type": "string", "maxLength": 120 }, "description": { "description": "Help text for this configuration field, for display.", "type": "string", "maxLength": 2048 }, "type": { "type": "string", "const": "integer", "description": "A whole-number value." }, "minimum": { "description": "The smallest allowed value.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "maximum": { "description": "The largest allowed value.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "enum": { "description": "The exact values allowed, when this field is closed to a fixed list.", "minItems": 1, "maxItems": 128, "type": "array", "items": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "default": { "description": "The value used when this field is left unset.", "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "type" ] } ], "description": "The type each item in the list must match." }, "minItems": { "description": "The fewest items allowed.", "type": "integer", "minimum": 0, "maximum": 64 }, "maxItems": { "description": "The most items allowed.", "type": "integer", "minimum": 0, "maximum": 64 } }, "required": [ "type", "items" ] } ] }, "description": "Each configuration field this source accepts, keyed by field name." }, "required": { "default": [], "description": "Which configuration fields must be set.", "maxItems": 64, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" } }, "additionalProperties": { "type": "boolean", "const": false, "description": "Always `false`: no configuration field outside `properties` is accepted." } }, "required": [ "type", "properties", "required", "additionalProperties" ], "description": "This source's configuration, as a bounded JSON Schema subset the generic source editor can render." }, "fields": { "minItems": 1, "maxItems": 64, "type": "array", "items": { "type": "object", "properties": { "path": { "minItems": 1, "maxItems": 8, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "description": "The keys to walk, in order, from an observation's top level down to this field." }, "valueType": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "boolean", "description": "A true/false value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "string", "description": "A text value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "integer", "description": "A whole-number value, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "decimal", "description": "An exact decimal value, as text, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] } ], "description": "What type this field's value has, and the unit it carries when it has one." }, "optional": { "description": "Whether the provider may genuinely not observe this field, rather than fail to read it. When true, a missing value resolves a condition over it to `missing_field` and the rule's verdict to `unknown`, rather than zero, null or false.", "type": "boolean" } }, "required": [ "path", "valueType" ], "description": "One data field an event or a source's observation carries: where it lives, and its type." }, "description": "The data fields this source's observations carry." }, "public": { "type": "boolean", "description": "Whether this source reads data anyone can read, rather than data scoped to the owner's own connection." }, "requiredConnectionScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "description": "The connection scopes a binding needs before this source is available, when it needs any." }, "supportedSubjects": { "type": "object", "properties": { "subjects": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "description": "The subjects this source can be configured to read, when it is bounded to a known list." }, "assets": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "description": "The assets this source can be configured to read, when it is bounded to a known list." }, "networks": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "description": "The networks this source can be configured to read, when it is bounded to a known list." }, "filters": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "description": "The other filters this source accepts, when it is bounded to a known list." } }, "required": [ "subjects", "assets", "networks", "filters" ], "description": "What this source can be configured to read, where the catalog knows the bounds; empty where any value is accepted." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "presentation": { "type": "object", "properties": { "subjectConfigKey": { "description": "Which configuration field names the subject being watched, when the editor should highlight one.", "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "fields": { "minItems": 1, "maxItems": 64, "type": "array", "items": { "type": "object", "properties": { "path": { "minItems": 1, "maxItems": 8, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "description": "The keys to walk, in order, from an observation's top level down to this field." }, "label": { "type": "string", "minLength": 1, "maxLength": 120, "description": "A short display label for this field." } }, "required": [ "path", "label" ] }, "description": "Reviewed display labels for a subset of this source's fields." } }, "required": [ "fields" ], "description": "Reviewed display copy for the source editor: cosmetic only, never part of an execution descriptor or a saved source pin." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "availability": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "available", "needs_connection", "unavailable", "unknown" ], "description": "Whether this source is usable for the current owner: `available` ready to use, `needs_connection` a connection must be granted first, `unknown` availability has not been checked yet, or an earlier check's validity window has expired. `unavailable` marks a source this deployment cannot offer at all; `automationSources.list` never returns it today." }, "configured": { "type": "boolean", "description": "Whether the owner has set up a connection for this source." }, "verified": { "type": "boolean", "description": "Whether that connection has been confirmed to work." }, "grantedScopes": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 256 }, "description": "The connection scopes the owner has actually granted." }, "checkedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When availability was last checked, when it has been." }, "expiresAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this availability check expires and must be re-checked, when it has an expiry." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 2048 }, { "type": "null" } ], "description": "Why this source is not available, when it is not." } }, "required": [ "status", "configured", "verified", "grantedScopes", "checkedAt", "expiresAt", "reason" ], "description": "This owner's ability to use this source right now: whether it is connected and verified. Carries no credential, account or provider connection identifier." } }, "required": [ "id", "version", "label", "description", "semanticIdentity", "schemaFingerprint", "configSchema", "fields", "public", "requiredConnectionScopes", "supportedSubjects", "guarantees", "availability" ], "description": "One event source an automation may watch: its configuration schema, its data fields, and this owner's current ability to use it." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List automations Lists the user's automations, oldest first, each with its current monitoring health and its active or most recent occurrence. `filter` narrows by lifecycle state. `GET /v1/users/{userId}/automations` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "default": "all", "type": "string", "enum": [ "all", "enabled", "paused", "archived" ] }, "in": "query", "name": "filter", "required": false, "description": "Which automations to list: `all` every one, `enabled` currently firing, `paused` disabled but not archived, `archived` removed." }, { "schema": { "type": "string", "maxLength": 120 }, "in": "query", "name": "query", "required": false, "description": "Distinctive search words, not the whole user request. Every word must match a whole token in the name, instructions or reviewed rule description; matching is case-insensitive. Omit to browse." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/automations' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The user's automations. ```json { "description": "The user's automations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Automation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.list", "summary": "List automations", "tags": [ "automations" ], "description": "Lists the user's automations, oldest first, each with its current monitoring health and its active or most recent occurrence. `filter` narrows by lifecycle state.", "parameters": [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "default": "all", "type": "string", "enum": [ "all", "enabled", "paused", "archived" ] }, "in": "query", "name": "filter", "required": false, "description": "Which automations to list: `all` every one, `enabled` currently firing, `paused` disabled but not archived, `archived` removed." }, { "schema": { "type": "string", "maxLength": 120 }, "in": "query", "name": "query", "required": false, "description": "Distinctive search words, not the whole user request. Every word must match a whole token in the name, instructions or reviewed rule description; matching is case-insensitive. Omit to browse." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The user's automations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Automation" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Automation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "name": { "type": "string", "description": "The automation's name." }, "prompt": { "type": "string", "description": "The instructions given to the model each time this automation fires." }, "rule": { "$ref": "#/components/schemas/AutomationRule" }, "sourcePlans": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "result": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "ready", "description": "The binding is fully planned and ready to collect." }, "plan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "How one binding will actually be collected: the operation, its guarantees and its configuration." } }, "required": [ "status", "plan" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "needs_connection", "description": "The binding is plannable but needs a connection the owner has not granted yet." }, "candidatePlan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "The plan that would apply once the missing connection is granted." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "candidatePlan", "reasons" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "unsupported", "description": "The binding cannot be planned at all, as asked." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "reasons" ] } ], "description": "Whether this binding is ready, needs a connection, or is unsupported, and why." } }, "required": [ "binding", "result" ] }, "description": "How each of the rule's bindings will actually be collected." }, "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." }, "enabled": { "type": "boolean", "description": "Whether this automation is currently firing." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this automation was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this automation was last changed." }, "archivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this automation was archived, when it has been." }, "hold": { "anyOf": [ { "type": "object", "properties": { "at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the hold began." }, "reason": { "description": "Why an operator placed the hold, when they gave one.", "type": [ "string", "null" ] } }, "required": [ "at", "reason" ] }, { "type": "null" } ], "description": "An operator's hold: why future work is stopped, so the owner does not read it as their own doing." }, "nextFireAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this automation's clock will next wake it, when it has a schedule and is enabled." }, "monitoring": { "$ref": "#/components/schemas/AutomationMonitoring" }, "activeOccurrence": { "anyOf": [ { "$ref": "#/components/schemas/AutomationOccurrence" }, { "type": "null" } ], "description": "The occurrence currently running, when one is." }, "latestOccurrence": { "anyOf": [ { "$ref": "#/components/schemas/AutomationOccurrence" }, { "type": "null" } ], "description": "The most recent occurrence, running or not, when there has been one." }, "contract": { "anyOf": [ { "type": "object", "properties": { "terms": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The approved contract's exact terms." }, "accountId": { "type": "string", "minLength": 1, "description": "The intents account this contract authorizes." }, "approvedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the owner approved this contract." }, "revokedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this contract was withdrawn, when it has been." }, "executionsUsed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Plans that consumed allowance, from the plan and leg ledger." } }, "required": [ "terms", "accountId", "approvedAt", "revokedAt", "executionsUsed" ] }, { "type": "null" } ], "description": "The standing financial authority this automation's engine-fired runs execute under; null for an automation without one." } }, "required": [ "id", "name", "prompt", "rule", "sourcePlans", "revision", "enabled", "createdAt", "updatedAt", "archivedAt", "hold", "nextFireAt", "monitoring", "activeOccurrence", "latestOccurrence", "contract" ], "description": "One automation: its rule, its current sources, its monitoring health, and the occurrences it has fired." }, "AutomationRule": { "type": "object", "properties": { "schemaVersion": { "type": "number", "const": 1, "description": "The rule schema's version; always `1`." }, "delivery": { "default": { "overlap": "queue", "maxPendingOccurrences": 100 }, "oneOf": [ { "type": "object", "properties": { "overlap": { "type": "string", "const": "queue", "description": "Queue a new occurrence and run it once the active one finishes." }, "maxPendingOccurrences": { "type": "integer", "minimum": 1, "maximum": 100, "description": "How many occurrences may wait in the queue, not counting the one currently active, including one whose run is itself waiting on an approval." } }, "required": [ "overlap", "maxPendingOccurrences" ] }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "coalesce", "description": "Close the occurrence already pending as `coalesced` and record the new match as a fresh occurrence, rather than queuing a second." } }, "required": [ "overlap" ] }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "skip", "description": "Drop a new match while an occurrence is already active." } }, "required": [ "overlap" ] } ], "description": "What happens when a new occurrence is ready before the previous one has finished." }, "maxDeliveryLatenessSeconds": { "default": 86400, "description": "How long a new occurrence may wait to be delivered before its deadline passes and it is refused, in seconds.", "type": "integer", "minimum": 1, "maximum": 86400 }, "maxEvaluationGapSeconds": { "default": 600, "description": "The longest gap allowed between evaluations before `firing.mode: rising_edge` treats its history as broken and waits for a fresh baseline, in seconds.", "type": "integer", "minimum": 1, "maximum": 2678400 }, "wakes": { "minItems": 1, "maxItems": 7, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "at", "description": "A one-time wake at an exact moment; exhausted after that check, even if its condition is false." }, "runAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$", "description": "The exact moment this wake fires, as an ISO 8601 timestamp with an offset." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "runAt", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "interval", "description": "A wake that repeats on a fixed elapsed interval." }, "intervalMinutes": { "type": "integer", "minimum": 1, "maximum": 44640, "description": "How often this wake repeats, in minutes." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "intervalMinutes", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "calendar", "description": "A wake on a recurring calendar schedule: local times, weekdays, months and days of the month." }, "timeZone": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The IANA time zone a calendar wake's local times are interpreted in." }, "localTimes": { "minItems": 1, "maxItems": 24, "type": "array", "items": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" }, "description": "The times of day this wake fires, each in 24-hour `HH:MM` form, in `timeZone`." }, "weekdays": { "default": [ 1, 2, 3, 4, 5, 6, 7 ], "description": "Which ISO weekdays this wake fires on, 1 (Monday) through 7 (Sunday). Defaults to every day.", "minItems": 1, "maxItems": 7, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "months": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ], "description": "Which months this wake fires in, 1 (January) through 12 (December). Defaults to every month.", "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 12 } }, "monthDays": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ], "description": "Which days of the month this wake fires on, 1 through 31. Defaults to every day.", "minItems": 1, "maxItems": 31, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 31 } }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "timeZone", "localTimes", "weekdays", "months", "monthDays", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event", "description": "A wake evaluated each time a matching custom webhook event arrives." }, "eventType": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_.:-]{0,79}$", "description": "The event `type` this wake matches; a live webhook delivery of a different type is ignored before it reaches the condition." }, "fields": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "path": { "minItems": 1, "maxItems": 8, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "description": "The keys to walk, in order, from an observation's top level down to this field." }, "valueType": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "boolean", "description": "A true/false value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "string", "description": "A text value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "integer", "description": "A whole-number value, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "decimal", "description": "An exact decimal value, as text, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] } ], "description": "What type this field's value has, and the unit it carries when it has one." }, "optional": { "description": "Whether the provider may genuinely not observe this field, rather than fail to read it. When true, a missing value resolves a condition over it to `missing_field` and the rule's verdict to `unknown`, rather than zero, null or false.", "type": "boolean" } }, "required": [ "path", "valueType" ], "description": "One data field an event or a source's observation carries: where it lives, and its type." }, "description": "The data fields an event of this type is declared to carry." } }, "required": [ "kind", "eventType", "fields" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "reader_update", "description": "A wake evaluated each time the named reader delivers a fresh observation." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "kind", "binding" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "manual", "description": "A wake fired only by `automations.invoke` or `automations.signal`, never on its own." } }, "required": [ "kind" ] } ] }, "description": "Occasions to evaluate the rule's condition: alternatives, not an AND of conditions. At most one clock, one event stream and one manual wake." }, "readers": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "readerId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The installed source operation's id, as returned by `automationSources.list`." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "pollIntervalSeconds": { "type": "integer", "minimum": 1, "maximum": 2147483, "description": "How often this reader polls its source, in seconds." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum retained input age at evaluation, matching requirement.maxAgeSeconds when present. Snapshots use observation time; events use trusted receipt time. Collection separately enforces the provider's acquisition-age guarantee." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." } }, "required": [ "name", "readerId", "config", "pollIntervalSeconds", "maxAgeSeconds" ] }, "description": "The named source bindings this rule reads from, referenced by `condition` and by each `reader_update` wake's `binding`." }, "condition": { "description": "The rule's condition tree, up to 8 levels deep and 128 nodes total, built from five node kinds: `{op:\"bool\", value}` a fixed true/false leaf; `{op:\"compare\", comparator, left, right}` one of `eq`/`ne`/`lt`/`lte`/`gt`/`gte` between two operands — `lt`/`lte`/`gt`/`gte` require both operands to be `integer` or `decimal`, and both sides must share the same type and, for `integer`/`decimal`, the same unit; `{op:\"all\", args}` / `{op:\"any\", args}` AND/OR over one or more child nodes; `{op:\"not\", arg}` negates one child node. An operand is either `{kind:\"field\", binding, path}` — a bound reader's name and the key path into its data — or `{kind:\"literal\", type, value, unit?}` with `type` one of `boolean`/`string`/`integer`/`decimal` (`integer`/`decimal` values are exact decimal strings and carry `unit`). `automations.testCondition` evaluates the tree against a given event without firing." }, "firing": { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "each_match", "rising_edge" ], "description": "When a qualifying evaluation fires: `each_match` fires on every qualifying evaluation, including the first; `rising_edge` fires only on a known false-to-true transition." }, "repeat": { "type": "string", "enum": [ "once", "repeating" ], "description": "Whether this rule fires at most once, or keeps watching after it fires." }, "maxRuns": { "description": "Maximum deliverable runs recorded for this automation across pauses and resumes. Missed or refused deliveries do not count; recorded runs count even if later canceled, coalesced or failed. Omit for no finite limit beyond repeat=once.", "type": "integer", "minimum": 1, "maximum": 1000000 }, "initial": { "type": "string", "enum": [ "baseline", "fire_if_true" ], "description": "How `rising_edge` treats the first known state: `baseline` records it without firing, `fire_if_true` fires immediately if it is already true." }, "cooldownSeconds": { "type": "integer", "minimum": 0, "maximum": 2678400, "description": "The minimum time between firings, in seconds; it does not require the condition to stay true that whole time. For `rising_edge`, a false-to-true edge that lands inside cooldown is discarded, not queued: it is not replayed once cooldown ends, so the rule needs an entirely fresh edge after cooldown lapses before it fires again — simply remaining true past the cooldown boundary does not trigger a firing." } }, "required": [ "mode", "repeat", "initial", "cooldownSeconds" ], "description": "How this rule turns a qualifying evaluation into a firing: which ones count, how often, and how many." }, "maxSnapshotSkewSeconds": { "type": "integer", "minimum": 0, "maximum": 86400, "description": "The most that bound readers' observation times may disagree before evaluation reports `snapshot_skew`, in seconds." } }, "required": [ "schemaVersion", "delivery", "maxDeliveryLatenessSeconds", "maxEvaluationGapSeconds", "wakes", "readers", "condition", "firing", "maxSnapshotSkewSeconds" ], "description": "One automation's rule: when it wakes, what condition it evaluates, and how it fires." }, "AutomationJsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" } } ] }, "AutomationMonitoring": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable", "paused", "completed" ], "description": "The automation's overall monitoring status: `waiting` no evaluation yet, `healthy` sources and evaluation are current, `stale` an input is older than expected, `unavailable` a source could not be reached, `paused` firing is paused, `completed` its run policy is spent." }, "lastCheckedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When monitoring last checked this automation's sources." }, "sources": { "maxItems": 5, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "description": "The source's id within its provider." }, "check": { "description": "The most recent recipe check against this source, when evidence review is configured.", "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ] }, "status": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable" ], "description": "This source's health: `waiting` no observation yet, `healthy` fresh, `stale` older than expected, `unavailable` the provider could not be reached." }, "sourceTime": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider says the most recent observation was true." }, "receivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine received the most recent observation." }, "reason": { "description": "Why the source is not healthy, when it is not.", "type": [ "string", "null" ] } }, "required": [ "binding", "sourceId", "status", "sourceTime", "receivedAt", "reason" ] }, "description": "Each bound source's own health." }, "lastEvaluation": { "anyOf": [ { "type": "object", "properties": { "verdict": { "type": "string", "enum": [ "true", "false", "unknown" ], "description": "Whether the rule's condition holds: `true` it fires, `false` it does not, `unknown` an input could not be read, so the rule neither fires nor is treated as false." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this evaluation ran." }, "reasons": { "maxItems": 256, "type": "array", "items": { "type": "object", "properties": { "nodePath": { "maxItems": 8, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "description": "The path to the condition node this reason explains, as indices into the rule tree." }, "code": { "type": "string", "enum": [ "missing_source", "unavailable", "gap", "stale", "future", "missing_field", "invalid_value", "snapshot_skew" ], "description": "Why this node could not cleanly resolve: `missing_source` no binding was configured, `unavailable` the provider did not answer, `gap` a break in coverage was recorded, `stale` or `future` a timestamp was out of range, `missing_field` the observation lacked this field, `invalid_value` the value did not match its declared type, `snapshot_skew` the inputs disagreed on when they were true." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "nodePath", "code" ] }, "description": "Why the verdict is what it is, one entry per condition node that did not cleanly resolve." }, "inputs": { "maxItems": 5, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "const": "snapshot", "description": "A point-in-time read of current state." }, "sourceTime": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the provider says this snapshot was true." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime" ] }, { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "const": "received_event", "description": "An event the source pushed, or the engine collected as it happened." }, "sourceTime": { "type": "null", "description": "Not applicable to a received event; see `occurredAt` and `providerPublishedAt` instead." }, "providerPublishedAt": { "anyOf": [ { "type": "string", "maxLength": 64, "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" }, { "type": "null" } ], "description": "When the provider says it published this event, when it reports one." }, "occurredAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the event actually happened, when the provider reports that separately from when it was published." }, "finalizedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider considers this event no longer subject to correction, when it reports one." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime", "providerPublishedAt", "occurredAt", "finalizedAt" ] } ] }, "description": "Each input this evaluation read, without its raw data." } }, "required": [ "verdict", "evaluatedAt", "reasons", "inputs" ] }, { "type": "null" } ], "description": "The rule's most recent evaluation, when it has run at least once." }, "webhook": { "anyOf": [ { "type": "object", "properties": { "configured": { "type": "boolean", "description": "Whether a webhook secret has been minted." }, "keyId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The current webhook secret's id, for rotation." }, "lastReceivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the webhook last received a request." } }, "required": [ "configured", "keyId", "lastReceivedAt" ] }, { "type": "null" } ], "description": "This automation's inbound webhook, when its rule listens for one." }, "reason": { "description": "Why status is not healthy, when it is not.", "type": [ "string", "null" ] } }, "required": [ "status", "lastCheckedAt", "sources", "lastEvaluation", "webhook", "reason" ], "description": "An automation's current health: its sources, its most recent evaluation, and its inbound webhook, if it has one." }, "AutomationOccurrence": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The occurrence's id." }, "deliverySequence": { "type": "string", "pattern": "^[1-9]\\d*$", "description": "This occurrence's place in its automation's delivery order, as a string so it sorts and compares exactly at any size." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The automation definition version this occurrence fired under." }, "activationEpoch": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The activation epoch this occurrence fired under." }, "name": { "type": "string", "description": "The automation's name at the time this occurrence fired." }, "prompt": { "type": "string", "description": "The automation's prompt at the time this occurrence fired." }, "evidence": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "decision", "manual", "external" ], "description": "What produced this occurrence: `decision` the rule's own condition, `manual` an owner's invoke or signal, `external` a source that decided on the engine's behalf." }, "identity": { "type": "string", "minLength": 1, "maxLength": 256, "description": "A stable string identifying this exact decision, used to deduplicate replays." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this decision was made." }, "data": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "The observations behind one decision, exactly as evaluated. Bounded to 256 KiB, 24 levels of nesting and 16384 entries." }, "sourceChecks": { "description": "Recipe checks recorded for each source this decision read, when evidence review is configured.", "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding this check was collected for." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The specific event or observation this check backs." }, "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this check ran." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "check": { "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ], "description": "A recorded run of a recipe's steps against the real source, kept as evidence." } }, "required": [ "binding", "sourceId", "eventId", "operationId", "operationVersion", "check" ], "description": "Frozen recipe evidence tied to the actual observation used by one decision." } } }, "required": [ "kind", "identity", "evaluatedAt", "data" ], "description": "What triggered this occurrence: the decision, its evaluated data, and any recipe checks behind it." }, "state": { "type": "string", "enum": [ "pending", "deferred", "accepted", "rejected", "canceled", "skipped", "coalesced" ], "description": "This occurrence's delivery state: `pending` waiting to run, `deferred` an admission attempt failed and is waiting to retry, `accepted` handed to a run, `rejected` the delivery policy refused it outright, or a non-retryable admission failure (or an exhausted retry deadline) stopped it, `canceled` stopped before running, `skipped` a previous occurrence was still active, `coalesced` merged into a newer match." }, "reason": { "description": "Why the occurrence is in this state, when there is one to give.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this occurrence was recorded." }, "deliveryDeadline": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest this occurrence could still be delivered." }, "nextAttemptAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine will next try to deliver this occurrence." }, "lastAttemptAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine last tried to deliver this occurrence, when it has tried." }, "attempts": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many delivery attempts this occurrence has had." }, "conversationId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, { "type": "null" } ], "description": "The conversation this occurrence ran in, once it has one." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The run this occurrence produced, once it has one." }, "runStatus": { "anyOf": [ { "type": "string", "enum": [ "running", "paused", "completed", "failed", "aborted" ] }, { "type": "null" } ], "description": "That run's status, once it has one: `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "runError": { "description": "Why the run failed, when it did.", "type": [ "string", "null" ] }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals this occurrence's run is waiting on." } }, "required": [ "id", "deliverySequence", "automationId", "definitionVersion", "activationEpoch", "name", "prompt", "evidence", "state", "reason", "createdAt", "deliveryDeadline", "nextAttemptAt", "lastAttemptAt", "attempts", "conversationId", "runId", "runStatus", "runError", "pendingApprovals" ], "description": "One firing of an automation: what evidence triggered it, its delivery state, and the run it produced, if any." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Preview rule Checks a rule without saving it, and reports what it would do: its next scheduled wake times, a plain-language summary of its behavior, and how each of its source bindings would be collected. `POST /v1/users/{userId}/automations/preview` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "rule": { "$ref": "#/components/schemas/AutomationRuleInput" } }, "required": [ "rule" ], "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/automations/preview' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data-binary '@request.json' ``` ## Responses ### 200 What the rule would do. ```json { "description": "What the rule would do.", "content": { "application/json": { "schema": { "type": "object", "properties": { "nextTimes": { "maxItems": 5, "type": "array", "items": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, "description": "Up to 5 of this rule's next scheduled wake times, when it has a clock." }, "summary": { "type": "string", "description": "A plain-language sentence describing when this rule wakes, its condition, and how it fires." }, "sourcePlans": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "result": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "description": "The binding is fully planned and ready to collect.", "enum": [ "ready" ] }, "plan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "How one binding will actually be collected: the operation, its guarantees and its configuration." } }, "required": [ "status", "plan" ] }, { "type": "object", "properties": { "status": { "type": "string", "description": "The binding is plannable but needs a connection the owner has not granted yet.", "enum": [ "needs_connection" ] }, "candidatePlan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "The plan that would apply once the missing connection is granted." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "candidatePlan", "reasons" ] }, { "type": "object", "properties": { "status": { "type": "string", "description": "The binding cannot be planned at all, as asked.", "enum": [ "unsupported" ] }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "reasons" ] } ], "description": "Whether this binding is ready, needs a connection, or is unsupported, and why." } }, "required": [ "binding", "result" ] }, "description": "How each of the rule's bindings would be collected, were this rule saved." } }, "required": [ "nextTimes", "summary", "sourcePlans" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `automation_invalid` — the automation's definition cannot run as written ```json { "description": "The operation lost to the current state.\n\n- `automation_invalid` — the automation's definition cannot run as written", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.preview", "summary": "Preview rule", "tags": [ "automations" ], "description": "Checks a rule without saving it, and reports what it would do: its next scheduled wake times, a plain-language summary of its behavior, and how each of its source bindings would be collected.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "rule": { "$ref": "#/components/schemas/AutomationRuleInput" } }, "required": [ "rule" ], "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "What the rule would do.", "content": { "application/json": { "schema": { "type": "object", "properties": { "nextTimes": { "maxItems": 5, "type": "array", "items": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, "description": "Up to 5 of this rule's next scheduled wake times, when it has a clock." }, "summary": { "type": "string", "description": "A plain-language sentence describing when this rule wakes, its condition, and how it fires." }, "sourcePlans": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "result": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "description": "The binding is fully planned and ready to collect.", "enum": [ "ready" ] }, "plan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "How one binding will actually be collected: the operation, its guarantees and its configuration." } }, "required": [ "status", "plan" ] }, { "type": "object", "properties": { "status": { "type": "string", "description": "The binding is plannable but needs a connection the owner has not granted yet.", "enum": [ "needs_connection" ] }, "candidatePlan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "The plan that would apply once the missing connection is granted." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "candidatePlan", "reasons" ] }, { "type": "object", "properties": { "status": { "type": "string", "description": "The binding cannot be planned at all, as asked.", "enum": [ "unsupported" ] }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "reasons" ] } ], "description": "Whether this binding is ready, needs a connection, or is unsupported, and why." } }, "required": [ "binding", "result" ] }, "description": "How each of the rule's bindings would be collected, were this rule saved." } }, "required": [ "nextTimes", "summary", "sourcePlans" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `automation_invalid` — the automation's definition cannot run as written", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "AutomationRuleInput": { "type": "object", "properties": { "schemaVersion": { "type": "number", "const": 1, "description": "The rule schema's version; always `1`." }, "delivery": { "default": { "overlap": "queue", "maxPendingOccurrences": 100 }, "oneOf": [ { "type": "object", "properties": { "overlap": { "type": "string", "const": "queue", "description": "Queue a new occurrence and run it once the active one finishes." }, "maxPendingOccurrences": { "type": "integer", "minimum": 1, "maximum": 100, "description": "How many occurrences may wait in the queue, not counting the one currently active, including one whose run is itself waiting on an approval." } }, "required": [ "overlap", "maxPendingOccurrences" ], "additionalProperties": false }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "coalesce", "description": "Close the occurrence already pending as `coalesced` and record the new match as a fresh occurrence, rather than queuing a second." } }, "required": [ "overlap" ], "additionalProperties": false }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "skip", "description": "Drop a new match while an occurrence is already active." } }, "required": [ "overlap" ], "additionalProperties": false } ], "description": "What happens when a new occurrence is ready before the previous one has finished." }, "maxDeliveryLatenessSeconds": { "default": 86400, "description": "How long a new occurrence may wait to be delivered before its deadline passes and it is refused, in seconds.", "type": "integer", "minimum": 1, "maximum": 86400 }, "maxEvaluationGapSeconds": { "default": 600, "description": "The longest gap allowed between evaluations before `firing.mode: rising_edge` treats its history as broken and waits for a fresh baseline, in seconds.", "type": "integer", "minimum": 1, "maximum": 2678400 }, "wakes": { "minItems": 1, "maxItems": 7, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "at", "description": "A one-time wake at an exact moment; exhausted after that check, even if its condition is false." }, "runAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$", "description": "The exact moment this wake fires, as an ISO 8601 timestamp with an offset." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode" ], "additionalProperties": false }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode" ], "additionalProperties": false }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode" ], "additionalProperties": false } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "runAt" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "interval", "description": "A wake that repeats on a fixed elapsed interval." }, "intervalMinutes": { "type": "integer", "minimum": 1, "maximum": 44640, "description": "How often this wake repeats, in minutes." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode" ], "additionalProperties": false }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode" ], "additionalProperties": false }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode" ], "additionalProperties": false } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "intervalMinutes" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "calendar", "description": "A wake on a recurring calendar schedule: local times, weekdays, months and days of the month." }, "timeZone": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The IANA time zone a calendar wake's local times are interpreted in." }, "localTimes": { "minItems": 1, "maxItems": 24, "type": "array", "items": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" }, "description": "The times of day this wake fires, each in 24-hour `HH:MM` form, in `timeZone`." }, "weekdays": { "default": [ 1, 2, 3, 4, 5, 6, 7 ], "description": "Which ISO weekdays this wake fires on, 1 (Monday) through 7 (Sunday). Defaults to every day.", "minItems": 1, "maxItems": 7, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "months": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ], "description": "Which months this wake fires in, 1 (January) through 12 (December). Defaults to every month.", "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 12 } }, "monthDays": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ], "description": "Which days of the month this wake fires on, 1 through 31. Defaults to every day.", "minItems": 1, "maxItems": 31, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 31 } }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode" ], "additionalProperties": false }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode" ], "additionalProperties": false }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode" ], "additionalProperties": false } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "timeZone", "localTimes" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event", "description": "A wake evaluated each time a matching custom webhook event arrives." }, "eventType": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_.:-]{0,79}$", "description": "The event `type` this wake matches; a live webhook delivery of a different type is ignored before it reaches the condition." }, "fields": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "path": { "minItems": 1, "maxItems": 8, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "description": "The keys to walk, in order, from an observation's top level down to this field." }, "valueType": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "boolean", "description": "A true/false value." } }, "required": [ "type" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "string", "description": "A text value." } }, "required": [ "type" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "integer", "description": "A whole-number value, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "decimal", "description": "An exact decimal value, as text, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ], "additionalProperties": false } ], "description": "What type this field's value has, and the unit it carries when it has one." }, "optional": { "description": "Whether the provider may genuinely not observe this field, rather than fail to read it. When true, a missing value resolves a condition over it to `missing_field` and the rule's verdict to `unknown`, rather than zero, null or false.", "type": "boolean" } }, "required": [ "path", "valueType" ], "additionalProperties": false, "description": "One data field an event or a source's observation carries: where it lives, and its type." }, "description": "The data fields an event of this type is declared to carry." } }, "required": [ "kind", "eventType", "fields" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "reader_update", "description": "A wake evaluated each time the named reader delivers a fresh observation." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "kind", "binding" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "manual", "description": "A wake fired only by `automations.invoke` or `automations.signal`, never on its own." } }, "required": [ "kind" ], "additionalProperties": false } ] }, "description": "Occasions to evaluate the rule's condition: alternatives, not an AND of conditions. At most one clock, one event stream and one manual wake." }, "readers": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "readerId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The installed source operation's id, as returned by `automationSources.list`." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "pollIntervalSeconds": { "type": "integer", "minimum": 1, "maximum": 2147483, "description": "How often this reader polls its source, in seconds." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum retained input age at evaluation, matching requirement.maxAgeSeconds when present. Snapshots use observation time; events use trusted receipt time. Collection separately enforces the provider's acquisition-age guarantee." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "additionalProperties": false, "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." } }, "required": [ "name", "readerId", "config", "pollIntervalSeconds", "maxAgeSeconds" ], "additionalProperties": false }, "description": "The named source bindings this rule reads from, referenced by `condition` and by each `reader_update` wake's `binding`." }, "condition": { "description": "The rule's condition tree, up to 8 levels deep and 128 nodes total, built from five node kinds: `{op:\"bool\", value}` a fixed true/false leaf; `{op:\"compare\", comparator, left, right}` one of `eq`/`ne`/`lt`/`lte`/`gt`/`gte` between two operands — `lt`/`lte`/`gt`/`gte` require both operands to be `integer` or `decimal`, and both sides must share the same type and, for `integer`/`decimal`, the same unit; `{op:\"all\", args}` / `{op:\"any\", args}` AND/OR over one or more child nodes; `{op:\"not\", arg}` negates one child node. An operand is either `{kind:\"field\", binding, path}` — a bound reader's name and the key path into its data — or `{kind:\"literal\", type, value, unit?}` with `type` one of `boolean`/`string`/`integer`/`decimal` (`integer`/`decimal` values are exact decimal strings and carry `unit`). `automations.testCondition` evaluates the tree against a given event without firing." }, "firing": { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "each_match", "rising_edge" ], "description": "When a qualifying evaluation fires: `each_match` fires on every qualifying evaluation, including the first; `rising_edge` fires only on a known false-to-true transition." }, "repeat": { "type": "string", "enum": [ "once", "repeating" ], "description": "Whether this rule fires at most once, or keeps watching after it fires." }, "maxRuns": { "description": "Maximum deliverable runs recorded for this automation across pauses and resumes. Missed or refused deliveries do not count; recorded runs count even if later canceled, coalesced or failed. Omit for no finite limit beyond repeat=once.", "type": "integer", "minimum": 1, "maximum": 1000000 }, "initial": { "type": "string", "enum": [ "baseline", "fire_if_true" ], "description": "How `rising_edge` treats the first known state: `baseline` records it without firing, `fire_if_true` fires immediately if it is already true." }, "cooldownSeconds": { "type": "integer", "minimum": 0, "maximum": 2678400, "description": "The minimum time between firings, in seconds; it does not require the condition to stay true that whole time. For `rising_edge`, a false-to-true edge that lands inside cooldown is discarded, not queued: it is not replayed once cooldown ends, so the rule needs an entirely fresh edge after cooldown lapses before it fires again — simply remaining true past the cooldown boundary does not trigger a firing." } }, "required": [ "mode", "repeat", "initial", "cooldownSeconds" ], "additionalProperties": false, "description": "How this rule turns a qualifying evaluation into a firing: which ones count, how often, and how many." }, "maxSnapshotSkewSeconds": { "type": "integer", "minimum": 0, "maximum": 86400, "description": "The most that bound readers' observation times may disagree before evaluation reports `snapshot_skew`, in seconds." } }, "required": [ "schemaVersion", "wakes", "readers", "condition", "firing", "maxSnapshotSkewSeconds" ], "additionalProperties": false, "description": "One automation's rule: when it wakes, what condition it evaluates, and how it fires." }, "AutomationJsonValueInput": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValueInput" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" } } ] }, "AutomationJsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get automation Returns one automation: its rule, its current sources, its monitoring health, and its active or most recent occurrence. `GET /v1/users/{userId}/automations/{automationId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The automation. ```json { "description": "The automation.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Automation" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.get", "summary": "Get automation", "tags": [ "automations" ], "description": "Returns one automation: its rule, its current sources, its monitoring health, and its active or most recent occurrence.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The automation.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Automation" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Automation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "name": { "type": "string", "description": "The automation's name." }, "prompt": { "type": "string", "description": "The instructions given to the model each time this automation fires." }, "rule": { "$ref": "#/components/schemas/AutomationRule" }, "sourcePlans": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "result": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "ready", "description": "The binding is fully planned and ready to collect." }, "plan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "How one binding will actually be collected: the operation, its guarantees and its configuration." } }, "required": [ "status", "plan" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "needs_connection", "description": "The binding is plannable but needs a connection the owner has not granted yet." }, "candidatePlan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "The plan that would apply once the missing connection is granted." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "candidatePlan", "reasons" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "unsupported", "description": "The binding cannot be planned at all, as asked." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "reasons" ] } ], "description": "Whether this binding is ready, needs a connection, or is unsupported, and why." } }, "required": [ "binding", "result" ] }, "description": "How each of the rule's bindings will actually be collected." }, "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." }, "enabled": { "type": "boolean", "description": "Whether this automation is currently firing." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this automation was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this automation was last changed." }, "archivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this automation was archived, when it has been." }, "hold": { "anyOf": [ { "type": "object", "properties": { "at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the hold began." }, "reason": { "description": "Why an operator placed the hold, when they gave one.", "type": [ "string", "null" ] } }, "required": [ "at", "reason" ] }, { "type": "null" } ], "description": "An operator's hold: why future work is stopped, so the owner does not read it as their own doing." }, "nextFireAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this automation's clock will next wake it, when it has a schedule and is enabled." }, "monitoring": { "$ref": "#/components/schemas/AutomationMonitoring" }, "activeOccurrence": { "anyOf": [ { "$ref": "#/components/schemas/AutomationOccurrence" }, { "type": "null" } ], "description": "The occurrence currently running, when one is." }, "latestOccurrence": { "anyOf": [ { "$ref": "#/components/schemas/AutomationOccurrence" }, { "type": "null" } ], "description": "The most recent occurrence, running or not, when there has been one." }, "contract": { "anyOf": [ { "type": "object", "properties": { "terms": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The approved contract's exact terms." }, "accountId": { "type": "string", "minLength": 1, "description": "The intents account this contract authorizes." }, "approvedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the owner approved this contract." }, "revokedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this contract was withdrawn, when it has been." }, "executionsUsed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Plans that consumed allowance, from the plan and leg ledger." } }, "required": [ "terms", "accountId", "approvedAt", "revokedAt", "executionsUsed" ] }, { "type": "null" } ], "description": "The standing financial authority this automation's engine-fired runs execute under; null for an automation without one." } }, "required": [ "id", "name", "prompt", "rule", "sourcePlans", "revision", "enabled", "createdAt", "updatedAt", "archivedAt", "hold", "nextFireAt", "monitoring", "activeOccurrence", "latestOccurrence", "contract" ], "description": "One automation: its rule, its current sources, its monitoring health, and the occurrences it has fired." }, "AutomationRule": { "type": "object", "properties": { "schemaVersion": { "type": "number", "const": 1, "description": "The rule schema's version; always `1`." }, "delivery": { "default": { "overlap": "queue", "maxPendingOccurrences": 100 }, "oneOf": [ { "type": "object", "properties": { "overlap": { "type": "string", "const": "queue", "description": "Queue a new occurrence and run it once the active one finishes." }, "maxPendingOccurrences": { "type": "integer", "minimum": 1, "maximum": 100, "description": "How many occurrences may wait in the queue, not counting the one currently active, including one whose run is itself waiting on an approval." } }, "required": [ "overlap", "maxPendingOccurrences" ] }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "coalesce", "description": "Close the occurrence already pending as `coalesced` and record the new match as a fresh occurrence, rather than queuing a second." } }, "required": [ "overlap" ] }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "skip", "description": "Drop a new match while an occurrence is already active." } }, "required": [ "overlap" ] } ], "description": "What happens when a new occurrence is ready before the previous one has finished." }, "maxDeliveryLatenessSeconds": { "default": 86400, "description": "How long a new occurrence may wait to be delivered before its deadline passes and it is refused, in seconds.", "type": "integer", "minimum": 1, "maximum": 86400 }, "maxEvaluationGapSeconds": { "default": 600, "description": "The longest gap allowed between evaluations before `firing.mode: rising_edge` treats its history as broken and waits for a fresh baseline, in seconds.", "type": "integer", "minimum": 1, "maximum": 2678400 }, "wakes": { "minItems": 1, "maxItems": 7, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "at", "description": "A one-time wake at an exact moment; exhausted after that check, even if its condition is false." }, "runAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$", "description": "The exact moment this wake fires, as an ISO 8601 timestamp with an offset." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "runAt", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "interval", "description": "A wake that repeats on a fixed elapsed interval." }, "intervalMinutes": { "type": "integer", "minimum": 1, "maximum": 44640, "description": "How often this wake repeats, in minutes." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "intervalMinutes", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "calendar", "description": "A wake on a recurring calendar schedule: local times, weekdays, months and days of the month." }, "timeZone": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The IANA time zone a calendar wake's local times are interpreted in." }, "localTimes": { "minItems": 1, "maxItems": 24, "type": "array", "items": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" }, "description": "The times of day this wake fires, each in 24-hour `HH:MM` form, in `timeZone`." }, "weekdays": { "default": [ 1, 2, 3, 4, 5, 6, 7 ], "description": "Which ISO weekdays this wake fires on, 1 (Monday) through 7 (Sunday). Defaults to every day.", "minItems": 1, "maxItems": 7, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "months": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ], "description": "Which months this wake fires in, 1 (January) through 12 (December). Defaults to every month.", "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 12 } }, "monthDays": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ], "description": "Which days of the month this wake fires on, 1 through 31. Defaults to every day.", "minItems": 1, "maxItems": 31, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 31 } }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "timeZone", "localTimes", "weekdays", "months", "monthDays", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event", "description": "A wake evaluated each time a matching custom webhook event arrives." }, "eventType": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_.:-]{0,79}$", "description": "The event `type` this wake matches; a live webhook delivery of a different type is ignored before it reaches the condition." }, "fields": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "path": { "minItems": 1, "maxItems": 8, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "description": "The keys to walk, in order, from an observation's top level down to this field." }, "valueType": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "boolean", "description": "A true/false value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "string", "description": "A text value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "integer", "description": "A whole-number value, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "decimal", "description": "An exact decimal value, as text, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] } ], "description": "What type this field's value has, and the unit it carries when it has one." }, "optional": { "description": "Whether the provider may genuinely not observe this field, rather than fail to read it. When true, a missing value resolves a condition over it to `missing_field` and the rule's verdict to `unknown`, rather than zero, null or false.", "type": "boolean" } }, "required": [ "path", "valueType" ], "description": "One data field an event or a source's observation carries: where it lives, and its type." }, "description": "The data fields an event of this type is declared to carry." } }, "required": [ "kind", "eventType", "fields" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "reader_update", "description": "A wake evaluated each time the named reader delivers a fresh observation." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "kind", "binding" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "manual", "description": "A wake fired only by `automations.invoke` or `automations.signal`, never on its own." } }, "required": [ "kind" ] } ] }, "description": "Occasions to evaluate the rule's condition: alternatives, not an AND of conditions. At most one clock, one event stream and one manual wake." }, "readers": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "readerId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The installed source operation's id, as returned by `automationSources.list`." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "pollIntervalSeconds": { "type": "integer", "minimum": 1, "maximum": 2147483, "description": "How often this reader polls its source, in seconds." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum retained input age at evaluation, matching requirement.maxAgeSeconds when present. Snapshots use observation time; events use trusted receipt time. Collection separately enforces the provider's acquisition-age guarantee." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." } }, "required": [ "name", "readerId", "config", "pollIntervalSeconds", "maxAgeSeconds" ] }, "description": "The named source bindings this rule reads from, referenced by `condition` and by each `reader_update` wake's `binding`." }, "condition": { "description": "The rule's condition tree, up to 8 levels deep and 128 nodes total, built from five node kinds: `{op:\"bool\", value}` a fixed true/false leaf; `{op:\"compare\", comparator, left, right}` one of `eq`/`ne`/`lt`/`lte`/`gt`/`gte` between two operands — `lt`/`lte`/`gt`/`gte` require both operands to be `integer` or `decimal`, and both sides must share the same type and, for `integer`/`decimal`, the same unit; `{op:\"all\", args}` / `{op:\"any\", args}` AND/OR over one or more child nodes; `{op:\"not\", arg}` negates one child node. An operand is either `{kind:\"field\", binding, path}` — a bound reader's name and the key path into its data — or `{kind:\"literal\", type, value, unit?}` with `type` one of `boolean`/`string`/`integer`/`decimal` (`integer`/`decimal` values are exact decimal strings and carry `unit`). `automations.testCondition` evaluates the tree against a given event without firing." }, "firing": { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "each_match", "rising_edge" ], "description": "When a qualifying evaluation fires: `each_match` fires on every qualifying evaluation, including the first; `rising_edge` fires only on a known false-to-true transition." }, "repeat": { "type": "string", "enum": [ "once", "repeating" ], "description": "Whether this rule fires at most once, or keeps watching after it fires." }, "maxRuns": { "description": "Maximum deliverable runs recorded for this automation across pauses and resumes. Missed or refused deliveries do not count; recorded runs count even if later canceled, coalesced or failed. Omit for no finite limit beyond repeat=once.", "type": "integer", "minimum": 1, "maximum": 1000000 }, "initial": { "type": "string", "enum": [ "baseline", "fire_if_true" ], "description": "How `rising_edge` treats the first known state: `baseline` records it without firing, `fire_if_true` fires immediately if it is already true." }, "cooldownSeconds": { "type": "integer", "minimum": 0, "maximum": 2678400, "description": "The minimum time between firings, in seconds; it does not require the condition to stay true that whole time. For `rising_edge`, a false-to-true edge that lands inside cooldown is discarded, not queued: it is not replayed once cooldown ends, so the rule needs an entirely fresh edge after cooldown lapses before it fires again — simply remaining true past the cooldown boundary does not trigger a firing." } }, "required": [ "mode", "repeat", "initial", "cooldownSeconds" ], "description": "How this rule turns a qualifying evaluation into a firing: which ones count, how often, and how many." }, "maxSnapshotSkewSeconds": { "type": "integer", "minimum": 0, "maximum": 86400, "description": "The most that bound readers' observation times may disagree before evaluation reports `snapshot_skew`, in seconds." } }, "required": [ "schemaVersion", "delivery", "maxDeliveryLatenessSeconds", "maxEvaluationGapSeconds", "wakes", "readers", "condition", "firing", "maxSnapshotSkewSeconds" ], "description": "One automation's rule: when it wakes, what condition it evaluates, and how it fires." }, "AutomationJsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" } } ] }, "AutomationMonitoring": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable", "paused", "completed" ], "description": "The automation's overall monitoring status: `waiting` no evaluation yet, `healthy` sources and evaluation are current, `stale` an input is older than expected, `unavailable` a source could not be reached, `paused` firing is paused, `completed` its run policy is spent." }, "lastCheckedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When monitoring last checked this automation's sources." }, "sources": { "maxItems": 5, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "description": "The source's id within its provider." }, "check": { "description": "The most recent recipe check against this source, when evidence review is configured.", "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ] }, "status": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable" ], "description": "This source's health: `waiting` no observation yet, `healthy` fresh, `stale` older than expected, `unavailable` the provider could not be reached." }, "sourceTime": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider says the most recent observation was true." }, "receivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine received the most recent observation." }, "reason": { "description": "Why the source is not healthy, when it is not.", "type": [ "string", "null" ] } }, "required": [ "binding", "sourceId", "status", "sourceTime", "receivedAt", "reason" ] }, "description": "Each bound source's own health." }, "lastEvaluation": { "anyOf": [ { "type": "object", "properties": { "verdict": { "type": "string", "enum": [ "true", "false", "unknown" ], "description": "Whether the rule's condition holds: `true` it fires, `false` it does not, `unknown` an input could not be read, so the rule neither fires nor is treated as false." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this evaluation ran." }, "reasons": { "maxItems": 256, "type": "array", "items": { "type": "object", "properties": { "nodePath": { "maxItems": 8, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "description": "The path to the condition node this reason explains, as indices into the rule tree." }, "code": { "type": "string", "enum": [ "missing_source", "unavailable", "gap", "stale", "future", "missing_field", "invalid_value", "snapshot_skew" ], "description": "Why this node could not cleanly resolve: `missing_source` no binding was configured, `unavailable` the provider did not answer, `gap` a break in coverage was recorded, `stale` or `future` a timestamp was out of range, `missing_field` the observation lacked this field, `invalid_value` the value did not match its declared type, `snapshot_skew` the inputs disagreed on when they were true." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "nodePath", "code" ] }, "description": "Why the verdict is what it is, one entry per condition node that did not cleanly resolve." }, "inputs": { "maxItems": 5, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "const": "snapshot", "description": "A point-in-time read of current state." }, "sourceTime": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the provider says this snapshot was true." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime" ] }, { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "const": "received_event", "description": "An event the source pushed, or the engine collected as it happened." }, "sourceTime": { "type": "null", "description": "Not applicable to a received event; see `occurredAt` and `providerPublishedAt` instead." }, "providerPublishedAt": { "anyOf": [ { "type": "string", "maxLength": 64, "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" }, { "type": "null" } ], "description": "When the provider says it published this event, when it reports one." }, "occurredAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the event actually happened, when the provider reports that separately from when it was published." }, "finalizedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider considers this event no longer subject to correction, when it reports one." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime", "providerPublishedAt", "occurredAt", "finalizedAt" ] } ] }, "description": "Each input this evaluation read, without its raw data." } }, "required": [ "verdict", "evaluatedAt", "reasons", "inputs" ] }, { "type": "null" } ], "description": "The rule's most recent evaluation, when it has run at least once." }, "webhook": { "anyOf": [ { "type": "object", "properties": { "configured": { "type": "boolean", "description": "Whether a webhook secret has been minted." }, "keyId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The current webhook secret's id, for rotation." }, "lastReceivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the webhook last received a request." } }, "required": [ "configured", "keyId", "lastReceivedAt" ] }, { "type": "null" } ], "description": "This automation's inbound webhook, when its rule listens for one." }, "reason": { "description": "Why status is not healthy, when it is not.", "type": [ "string", "null" ] } }, "required": [ "status", "lastCheckedAt", "sources", "lastEvaluation", "webhook", "reason" ], "description": "An automation's current health: its sources, its most recent evaluation, and its inbound webhook, if it has one." }, "AutomationOccurrence": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The occurrence's id." }, "deliverySequence": { "type": "string", "pattern": "^[1-9]\\d*$", "description": "This occurrence's place in its automation's delivery order, as a string so it sorts and compares exactly at any size." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The automation definition version this occurrence fired under." }, "activationEpoch": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The activation epoch this occurrence fired under." }, "name": { "type": "string", "description": "The automation's name at the time this occurrence fired." }, "prompt": { "type": "string", "description": "The automation's prompt at the time this occurrence fired." }, "evidence": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "decision", "manual", "external" ], "description": "What produced this occurrence: `decision` the rule's own condition, `manual` an owner's invoke or signal, `external` a source that decided on the engine's behalf." }, "identity": { "type": "string", "minLength": 1, "maxLength": 256, "description": "A stable string identifying this exact decision, used to deduplicate replays." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this decision was made." }, "data": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "The observations behind one decision, exactly as evaluated. Bounded to 256 KiB, 24 levels of nesting and 16384 entries." }, "sourceChecks": { "description": "Recipe checks recorded for each source this decision read, when evidence review is configured.", "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding this check was collected for." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The specific event or observation this check backs." }, "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this check ran." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "check": { "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ], "description": "A recorded run of a recipe's steps against the real source, kept as evidence." } }, "required": [ "binding", "sourceId", "eventId", "operationId", "operationVersion", "check" ], "description": "Frozen recipe evidence tied to the actual observation used by one decision." } } }, "required": [ "kind", "identity", "evaluatedAt", "data" ], "description": "What triggered this occurrence: the decision, its evaluated data, and any recipe checks behind it." }, "state": { "type": "string", "enum": [ "pending", "deferred", "accepted", "rejected", "canceled", "skipped", "coalesced" ], "description": "This occurrence's delivery state: `pending` waiting to run, `deferred` an admission attempt failed and is waiting to retry, `accepted` handed to a run, `rejected` the delivery policy refused it outright, or a non-retryable admission failure (or an exhausted retry deadline) stopped it, `canceled` stopped before running, `skipped` a previous occurrence was still active, `coalesced` merged into a newer match." }, "reason": { "description": "Why the occurrence is in this state, when there is one to give.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this occurrence was recorded." }, "deliveryDeadline": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest this occurrence could still be delivered." }, "nextAttemptAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine will next try to deliver this occurrence." }, "lastAttemptAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine last tried to deliver this occurrence, when it has tried." }, "attempts": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many delivery attempts this occurrence has had." }, "conversationId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, { "type": "null" } ], "description": "The conversation this occurrence ran in, once it has one." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The run this occurrence produced, once it has one." }, "runStatus": { "anyOf": [ { "type": "string", "enum": [ "running", "paused", "completed", "failed", "aborted" ] }, { "type": "null" } ], "description": "That run's status, once it has one: `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "runError": { "description": "Why the run failed, when it did.", "type": [ "string", "null" ] }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals this occurrence's run is waiting on." } }, "required": [ "id", "deliverySequence", "automationId", "definitionVersion", "activationEpoch", "name", "prompt", "evidence", "state", "reason", "createdAt", "deliveryDeadline", "nextAttemptAt", "lastAttemptAt", "attempts", "conversationId", "runId", "runStatus", "runError", "pendingApprovals" ], "description": "One firing of an automation: what evidence triggered it, its delivery state, and the run it produced, if any." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Archive automation Archives the automation: it stops firing for good and cannot be resumed. Already-archived is answered the same way, so calling this more than once is safe. `DELETE /v1/users/{userId}/automations/{automationId}` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request DELETE 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 204 The automation was archived. ```json { "description": "The automation was archived." } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `automation_changed` — the `revision` sent is stale; reload the automation ```json { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.remove", "summary": "Archive automation", "tags": [ "automations" ], "description": "Archives the automation: it stops firing for good and cannot be resumed. Already-archived is answered the same way, so calling this more than once is safe.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "204": { "description": "The automation was archived." }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # List occurrences Lists the automation's occurrences, newest first: what fired, when, and the run it produced, if any. `GET /v1/users/{userId}/automations/{automationId}/history` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID/history' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The automation's occurrences. ```json { "description": "The automation's occurrences.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AutomationOccurrence" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.history", "summary": "List occurrences", "tags": [ "automations" ], "description": "Lists the automation's occurrences, newest first: what fired, when, and the run it produced, if any.", "parameters": [ { "schema": { "type": "string", "maxLength": 256 }, "in": "query", "name": "cursor", "required": false, "description": "Where the previous page ended; omit for the first page" }, { "schema": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 }, "in": "query", "name": "limit", "required": false, "description": "How many rows to answer, at most 100" }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The automation's occurrences.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AutomationOccurrence" }, "description": "This page's rows." }, "nextCursor": { "description": "The cursor for the next page; null once there are no more rows.", "type": [ "string", "null" ] }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many rows the list holds in all." } }, "required": [ "data", "nextCursor", "total" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "AutomationOccurrence": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The occurrence's id." }, "deliverySequence": { "type": "string", "pattern": "^[1-9]\\d*$", "description": "This occurrence's place in its automation's delivery order, as a string so it sorts and compares exactly at any size." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The automation definition version this occurrence fired under." }, "activationEpoch": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The activation epoch this occurrence fired under." }, "name": { "type": "string", "description": "The automation's name at the time this occurrence fired." }, "prompt": { "type": "string", "description": "The automation's prompt at the time this occurrence fired." }, "evidence": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "decision", "manual", "external" ], "description": "What produced this occurrence: `decision` the rule's own condition, `manual` an owner's invoke or signal, `external` a source that decided on the engine's behalf." }, "identity": { "type": "string", "minLength": 1, "maxLength": 256, "description": "A stable string identifying this exact decision, used to deduplicate replays." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this decision was made." }, "data": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "The observations behind one decision, exactly as evaluated. Bounded to 256 KiB, 24 levels of nesting and 16384 entries." }, "sourceChecks": { "description": "Recipe checks recorded for each source this decision read, when evidence review is configured.", "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding this check was collected for." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The specific event or observation this check backs." }, "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this check ran." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "check": { "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ], "description": "A recorded run of a recipe's steps against the real source, kept as evidence." } }, "required": [ "binding", "sourceId", "eventId", "operationId", "operationVersion", "check" ], "description": "Frozen recipe evidence tied to the actual observation used by one decision." } } }, "required": [ "kind", "identity", "evaluatedAt", "data" ], "description": "What triggered this occurrence: the decision, its evaluated data, and any recipe checks behind it." }, "state": { "type": "string", "enum": [ "pending", "deferred", "accepted", "rejected", "canceled", "skipped", "coalesced" ], "description": "This occurrence's delivery state: `pending` waiting to run, `deferred` an admission attempt failed and is waiting to retry, `accepted` handed to a run, `rejected` the delivery policy refused it outright, or a non-retryable admission failure (or an exhausted retry deadline) stopped it, `canceled` stopped before running, `skipped` a previous occurrence was still active, `coalesced` merged into a newer match." }, "reason": { "description": "Why the occurrence is in this state, when there is one to give.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this occurrence was recorded." }, "deliveryDeadline": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest this occurrence could still be delivered." }, "nextAttemptAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine will next try to deliver this occurrence." }, "lastAttemptAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine last tried to deliver this occurrence, when it has tried." }, "attempts": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many delivery attempts this occurrence has had." }, "conversationId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, { "type": "null" } ], "description": "The conversation this occurrence ran in, once it has one." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The run this occurrence produced, once it has one." }, "runStatus": { "anyOf": [ { "type": "string", "enum": [ "running", "paused", "completed", "failed", "aborted" ] }, { "type": "null" } ], "description": "That run's status, once it has one: `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "runError": { "description": "Why the run failed, when it did.", "type": [ "string", "null" ] }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals this occurrence's run is waiting on." } }, "required": [ "id", "deliverySequence", "automationId", "definitionVersion", "activationEpoch", "name", "prompt", "evidence", "state", "reason", "createdAt", "deliveryDeadline", "nextAttemptAt", "lastAttemptAt", "attempts", "conversationId", "runId", "runStatus", "runError", "pendingApprovals" ], "description": "One firing of an automation: what evidence triggered it, its delivery state, and the run it produced, if any." }, "AutomationJsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Resume firing Resumes a paused automation: its clock and readers restart, and its sources are re-planned before firing resumes. Refused if an operator holds the automation, if its rule no longer compiles or plans cleanly, or if the automation carries a contract — once withdrawn, a contract's standing authority cannot be re-approved by resuming; create a new automation instead. `POST /v1/users/{userId}/automations/{automationId}/enable` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID/enable' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The automation, updated. ```json { "description": "The automation, updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Automation" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `automation_held` — an operator holds the automation; it fires again when released - `automation_invalid` — the automation's definition cannot run as written - `automation_changed` — the `revision` sent is stale; reload the automation ```json { "description": "The operation lost to the current state.\n\n- `automation_held` — an operator holds the automation; it fires again when released\n- `automation_invalid` — the automation's definition cannot run as written\n- `automation_changed` — the `revision` sent is stale; reload the automation", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.enable", "summary": "Resume firing", "tags": [ "automations" ], "description": "Resumes a paused automation: its clock and readers restart, and its sources are re-planned before firing resumes. Refused if an operator holds the automation, if its rule no longer compiles or plans cleanly, or if the automation carries a contract — once withdrawn, a contract's standing authority cannot be re-approved by resuming; create a new automation instead.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The automation, updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Automation" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `automation_held` — an operator holds the automation; it fires again when released\n- `automation_invalid` — the automation's definition cannot run as written\n- `automation_changed` — the `revision` sent is stale; reload the automation", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Automation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "name": { "type": "string", "description": "The automation's name." }, "prompt": { "type": "string", "description": "The instructions given to the model each time this automation fires." }, "rule": { "$ref": "#/components/schemas/AutomationRule" }, "sourcePlans": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "result": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "ready", "description": "The binding is fully planned and ready to collect." }, "plan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "How one binding will actually be collected: the operation, its guarantees and its configuration." } }, "required": [ "status", "plan" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "needs_connection", "description": "The binding is plannable but needs a connection the owner has not granted yet." }, "candidatePlan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "The plan that would apply once the missing connection is granted." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "candidatePlan", "reasons" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "unsupported", "description": "The binding cannot be planned at all, as asked." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "reasons" ] } ], "description": "Whether this binding is ready, needs a connection, or is unsupported, and why." } }, "required": [ "binding", "result" ] }, "description": "How each of the rule's bindings will actually be collected." }, "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." }, "enabled": { "type": "boolean", "description": "Whether this automation is currently firing." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this automation was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this automation was last changed." }, "archivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this automation was archived, when it has been." }, "hold": { "anyOf": [ { "type": "object", "properties": { "at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the hold began." }, "reason": { "description": "Why an operator placed the hold, when they gave one.", "type": [ "string", "null" ] } }, "required": [ "at", "reason" ] }, { "type": "null" } ], "description": "An operator's hold: why future work is stopped, so the owner does not read it as their own doing." }, "nextFireAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this automation's clock will next wake it, when it has a schedule and is enabled." }, "monitoring": { "$ref": "#/components/schemas/AutomationMonitoring" }, "activeOccurrence": { "anyOf": [ { "$ref": "#/components/schemas/AutomationOccurrence" }, { "type": "null" } ], "description": "The occurrence currently running, when one is." }, "latestOccurrence": { "anyOf": [ { "$ref": "#/components/schemas/AutomationOccurrence" }, { "type": "null" } ], "description": "The most recent occurrence, running or not, when there has been one." }, "contract": { "anyOf": [ { "type": "object", "properties": { "terms": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The approved contract's exact terms." }, "accountId": { "type": "string", "minLength": 1, "description": "The intents account this contract authorizes." }, "approvedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the owner approved this contract." }, "revokedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this contract was withdrawn, when it has been." }, "executionsUsed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Plans that consumed allowance, from the plan and leg ledger." } }, "required": [ "terms", "accountId", "approvedAt", "revokedAt", "executionsUsed" ] }, { "type": "null" } ], "description": "The standing financial authority this automation's engine-fired runs execute under; null for an automation without one." } }, "required": [ "id", "name", "prompt", "rule", "sourcePlans", "revision", "enabled", "createdAt", "updatedAt", "archivedAt", "hold", "nextFireAt", "monitoring", "activeOccurrence", "latestOccurrence", "contract" ], "description": "One automation: its rule, its current sources, its monitoring health, and the occurrences it has fired." }, "AutomationRule": { "type": "object", "properties": { "schemaVersion": { "type": "number", "const": 1, "description": "The rule schema's version; always `1`." }, "delivery": { "default": { "overlap": "queue", "maxPendingOccurrences": 100 }, "oneOf": [ { "type": "object", "properties": { "overlap": { "type": "string", "const": "queue", "description": "Queue a new occurrence and run it once the active one finishes." }, "maxPendingOccurrences": { "type": "integer", "minimum": 1, "maximum": 100, "description": "How many occurrences may wait in the queue, not counting the one currently active, including one whose run is itself waiting on an approval." } }, "required": [ "overlap", "maxPendingOccurrences" ] }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "coalesce", "description": "Close the occurrence already pending as `coalesced` and record the new match as a fresh occurrence, rather than queuing a second." } }, "required": [ "overlap" ] }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "skip", "description": "Drop a new match while an occurrence is already active." } }, "required": [ "overlap" ] } ], "description": "What happens when a new occurrence is ready before the previous one has finished." }, "maxDeliveryLatenessSeconds": { "default": 86400, "description": "How long a new occurrence may wait to be delivered before its deadline passes and it is refused, in seconds.", "type": "integer", "minimum": 1, "maximum": 86400 }, "maxEvaluationGapSeconds": { "default": 600, "description": "The longest gap allowed between evaluations before `firing.mode: rising_edge` treats its history as broken and waits for a fresh baseline, in seconds.", "type": "integer", "minimum": 1, "maximum": 2678400 }, "wakes": { "minItems": 1, "maxItems": 7, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "at", "description": "A one-time wake at an exact moment; exhausted after that check, even if its condition is false." }, "runAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$", "description": "The exact moment this wake fires, as an ISO 8601 timestamp with an offset." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "runAt", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "interval", "description": "A wake that repeats on a fixed elapsed interval." }, "intervalMinutes": { "type": "integer", "minimum": 1, "maximum": 44640, "description": "How often this wake repeats, in minutes." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "intervalMinutes", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "calendar", "description": "A wake on a recurring calendar schedule: local times, weekdays, months and days of the month." }, "timeZone": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The IANA time zone a calendar wake's local times are interpreted in." }, "localTimes": { "minItems": 1, "maxItems": 24, "type": "array", "items": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" }, "description": "The times of day this wake fires, each in 24-hour `HH:MM` form, in `timeZone`." }, "weekdays": { "default": [ 1, 2, 3, 4, 5, 6, 7 ], "description": "Which ISO weekdays this wake fires on, 1 (Monday) through 7 (Sunday). Defaults to every day.", "minItems": 1, "maxItems": 7, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "months": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ], "description": "Which months this wake fires in, 1 (January) through 12 (December). Defaults to every month.", "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 12 } }, "monthDays": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ], "description": "Which days of the month this wake fires on, 1 through 31. Defaults to every day.", "minItems": 1, "maxItems": 31, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 31 } }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "timeZone", "localTimes", "weekdays", "months", "monthDays", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event", "description": "A wake evaluated each time a matching custom webhook event arrives." }, "eventType": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_.:-]{0,79}$", "description": "The event `type` this wake matches; a live webhook delivery of a different type is ignored before it reaches the condition." }, "fields": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "path": { "minItems": 1, "maxItems": 8, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "description": "The keys to walk, in order, from an observation's top level down to this field." }, "valueType": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "boolean", "description": "A true/false value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "string", "description": "A text value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "integer", "description": "A whole-number value, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "decimal", "description": "An exact decimal value, as text, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] } ], "description": "What type this field's value has, and the unit it carries when it has one." }, "optional": { "description": "Whether the provider may genuinely not observe this field, rather than fail to read it. When true, a missing value resolves a condition over it to `missing_field` and the rule's verdict to `unknown`, rather than zero, null or false.", "type": "boolean" } }, "required": [ "path", "valueType" ], "description": "One data field an event or a source's observation carries: where it lives, and its type." }, "description": "The data fields an event of this type is declared to carry." } }, "required": [ "kind", "eventType", "fields" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "reader_update", "description": "A wake evaluated each time the named reader delivers a fresh observation." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "kind", "binding" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "manual", "description": "A wake fired only by `automations.invoke` or `automations.signal`, never on its own." } }, "required": [ "kind" ] } ] }, "description": "Occasions to evaluate the rule's condition: alternatives, not an AND of conditions. At most one clock, one event stream and one manual wake." }, "readers": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "readerId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The installed source operation's id, as returned by `automationSources.list`." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "pollIntervalSeconds": { "type": "integer", "minimum": 1, "maximum": 2147483, "description": "How often this reader polls its source, in seconds." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum retained input age at evaluation, matching requirement.maxAgeSeconds when present. Snapshots use observation time; events use trusted receipt time. Collection separately enforces the provider's acquisition-age guarantee." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." } }, "required": [ "name", "readerId", "config", "pollIntervalSeconds", "maxAgeSeconds" ] }, "description": "The named source bindings this rule reads from, referenced by `condition` and by each `reader_update` wake's `binding`." }, "condition": { "description": "The rule's condition tree, up to 8 levels deep and 128 nodes total, built from five node kinds: `{op:\"bool\", value}` a fixed true/false leaf; `{op:\"compare\", comparator, left, right}` one of `eq`/`ne`/`lt`/`lte`/`gt`/`gte` between two operands — `lt`/`lte`/`gt`/`gte` require both operands to be `integer` or `decimal`, and both sides must share the same type and, for `integer`/`decimal`, the same unit; `{op:\"all\", args}` / `{op:\"any\", args}` AND/OR over one or more child nodes; `{op:\"not\", arg}` negates one child node. An operand is either `{kind:\"field\", binding, path}` — a bound reader's name and the key path into its data — or `{kind:\"literal\", type, value, unit?}` with `type` one of `boolean`/`string`/`integer`/`decimal` (`integer`/`decimal` values are exact decimal strings and carry `unit`). `automations.testCondition` evaluates the tree against a given event without firing." }, "firing": { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "each_match", "rising_edge" ], "description": "When a qualifying evaluation fires: `each_match` fires on every qualifying evaluation, including the first; `rising_edge` fires only on a known false-to-true transition." }, "repeat": { "type": "string", "enum": [ "once", "repeating" ], "description": "Whether this rule fires at most once, or keeps watching after it fires." }, "maxRuns": { "description": "Maximum deliverable runs recorded for this automation across pauses and resumes. Missed or refused deliveries do not count; recorded runs count even if later canceled, coalesced or failed. Omit for no finite limit beyond repeat=once.", "type": "integer", "minimum": 1, "maximum": 1000000 }, "initial": { "type": "string", "enum": [ "baseline", "fire_if_true" ], "description": "How `rising_edge` treats the first known state: `baseline` records it without firing, `fire_if_true` fires immediately if it is already true." }, "cooldownSeconds": { "type": "integer", "minimum": 0, "maximum": 2678400, "description": "The minimum time between firings, in seconds; it does not require the condition to stay true that whole time. For `rising_edge`, a false-to-true edge that lands inside cooldown is discarded, not queued: it is not replayed once cooldown ends, so the rule needs an entirely fresh edge after cooldown lapses before it fires again — simply remaining true past the cooldown boundary does not trigger a firing." } }, "required": [ "mode", "repeat", "initial", "cooldownSeconds" ], "description": "How this rule turns a qualifying evaluation into a firing: which ones count, how often, and how many." }, "maxSnapshotSkewSeconds": { "type": "integer", "minimum": 0, "maximum": 86400, "description": "The most that bound readers' observation times may disagree before evaluation reports `snapshot_skew`, in seconds." } }, "required": [ "schemaVersion", "delivery", "maxDeliveryLatenessSeconds", "maxEvaluationGapSeconds", "wakes", "readers", "condition", "firing", "maxSnapshotSkewSeconds" ], "description": "One automation's rule: when it wakes, what condition it evaluates, and how it fires." }, "AutomationJsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" } } ] }, "AutomationMonitoring": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable", "paused", "completed" ], "description": "The automation's overall monitoring status: `waiting` no evaluation yet, `healthy` sources and evaluation are current, `stale` an input is older than expected, `unavailable` a source could not be reached, `paused` firing is paused, `completed` its run policy is spent." }, "lastCheckedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When monitoring last checked this automation's sources." }, "sources": { "maxItems": 5, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "description": "The source's id within its provider." }, "check": { "description": "The most recent recipe check against this source, when evidence review is configured.", "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ] }, "status": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable" ], "description": "This source's health: `waiting` no observation yet, `healthy` fresh, `stale` older than expected, `unavailable` the provider could not be reached." }, "sourceTime": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider says the most recent observation was true." }, "receivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine received the most recent observation." }, "reason": { "description": "Why the source is not healthy, when it is not.", "type": [ "string", "null" ] } }, "required": [ "binding", "sourceId", "status", "sourceTime", "receivedAt", "reason" ] }, "description": "Each bound source's own health." }, "lastEvaluation": { "anyOf": [ { "type": "object", "properties": { "verdict": { "type": "string", "enum": [ "true", "false", "unknown" ], "description": "Whether the rule's condition holds: `true` it fires, `false` it does not, `unknown` an input could not be read, so the rule neither fires nor is treated as false." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this evaluation ran." }, "reasons": { "maxItems": 256, "type": "array", "items": { "type": "object", "properties": { "nodePath": { "maxItems": 8, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "description": "The path to the condition node this reason explains, as indices into the rule tree." }, "code": { "type": "string", "enum": [ "missing_source", "unavailable", "gap", "stale", "future", "missing_field", "invalid_value", "snapshot_skew" ], "description": "Why this node could not cleanly resolve: `missing_source` no binding was configured, `unavailable` the provider did not answer, `gap` a break in coverage was recorded, `stale` or `future` a timestamp was out of range, `missing_field` the observation lacked this field, `invalid_value` the value did not match its declared type, `snapshot_skew` the inputs disagreed on when they were true." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "nodePath", "code" ] }, "description": "Why the verdict is what it is, one entry per condition node that did not cleanly resolve." }, "inputs": { "maxItems": 5, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "const": "snapshot", "description": "A point-in-time read of current state." }, "sourceTime": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the provider says this snapshot was true." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime" ] }, { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "const": "received_event", "description": "An event the source pushed, or the engine collected as it happened." }, "sourceTime": { "type": "null", "description": "Not applicable to a received event; see `occurredAt` and `providerPublishedAt` instead." }, "providerPublishedAt": { "anyOf": [ { "type": "string", "maxLength": 64, "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" }, { "type": "null" } ], "description": "When the provider says it published this event, when it reports one." }, "occurredAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the event actually happened, when the provider reports that separately from when it was published." }, "finalizedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider considers this event no longer subject to correction, when it reports one." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime", "providerPublishedAt", "occurredAt", "finalizedAt" ] } ] }, "description": "Each input this evaluation read, without its raw data." } }, "required": [ "verdict", "evaluatedAt", "reasons", "inputs" ] }, { "type": "null" } ], "description": "The rule's most recent evaluation, when it has run at least once." }, "webhook": { "anyOf": [ { "type": "object", "properties": { "configured": { "type": "boolean", "description": "Whether a webhook secret has been minted." }, "keyId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The current webhook secret's id, for rotation." }, "lastReceivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the webhook last received a request." } }, "required": [ "configured", "keyId", "lastReceivedAt" ] }, { "type": "null" } ], "description": "This automation's inbound webhook, when its rule listens for one." }, "reason": { "description": "Why status is not healthy, when it is not.", "type": [ "string", "null" ] } }, "required": [ "status", "lastCheckedAt", "sources", "lastEvaluation", "webhook", "reason" ], "description": "An automation's current health: its sources, its most recent evaluation, and its inbound webhook, if it has one." }, "AutomationOccurrence": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The occurrence's id." }, "deliverySequence": { "type": "string", "pattern": "^[1-9]\\d*$", "description": "This occurrence's place in its automation's delivery order, as a string so it sorts and compares exactly at any size." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The automation definition version this occurrence fired under." }, "activationEpoch": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The activation epoch this occurrence fired under." }, "name": { "type": "string", "description": "The automation's name at the time this occurrence fired." }, "prompt": { "type": "string", "description": "The automation's prompt at the time this occurrence fired." }, "evidence": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "decision", "manual", "external" ], "description": "What produced this occurrence: `decision` the rule's own condition, `manual` an owner's invoke or signal, `external` a source that decided on the engine's behalf." }, "identity": { "type": "string", "minLength": 1, "maxLength": 256, "description": "A stable string identifying this exact decision, used to deduplicate replays." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this decision was made." }, "data": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "The observations behind one decision, exactly as evaluated. Bounded to 256 KiB, 24 levels of nesting and 16384 entries." }, "sourceChecks": { "description": "Recipe checks recorded for each source this decision read, when evidence review is configured.", "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding this check was collected for." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The specific event or observation this check backs." }, "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this check ran." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "check": { "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ], "description": "A recorded run of a recipe's steps against the real source, kept as evidence." } }, "required": [ "binding", "sourceId", "eventId", "operationId", "operationVersion", "check" ], "description": "Frozen recipe evidence tied to the actual observation used by one decision." } } }, "required": [ "kind", "identity", "evaluatedAt", "data" ], "description": "What triggered this occurrence: the decision, its evaluated data, and any recipe checks behind it." }, "state": { "type": "string", "enum": [ "pending", "deferred", "accepted", "rejected", "canceled", "skipped", "coalesced" ], "description": "This occurrence's delivery state: `pending` waiting to run, `deferred` an admission attempt failed and is waiting to retry, `accepted` handed to a run, `rejected` the delivery policy refused it outright, or a non-retryable admission failure (or an exhausted retry deadline) stopped it, `canceled` stopped before running, `skipped` a previous occurrence was still active, `coalesced` merged into a newer match." }, "reason": { "description": "Why the occurrence is in this state, when there is one to give.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this occurrence was recorded." }, "deliveryDeadline": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest this occurrence could still be delivered." }, "nextAttemptAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine will next try to deliver this occurrence." }, "lastAttemptAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine last tried to deliver this occurrence, when it has tried." }, "attempts": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many delivery attempts this occurrence has had." }, "conversationId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, { "type": "null" } ], "description": "The conversation this occurrence ran in, once it has one." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The run this occurrence produced, once it has one." }, "runStatus": { "anyOf": [ { "type": "string", "enum": [ "running", "paused", "completed", "failed", "aborted" ] }, { "type": "null" } ], "description": "That run's status, once it has one: `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "runError": { "description": "Why the run failed, when it did.", "type": [ "string", "null" ] }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals this occurrence's run is waiting on." } }, "required": [ "id", "deliverySequence", "automationId", "definitionVersion", "activationEpoch", "name", "prompt", "evidence", "state", "reason", "createdAt", "deliveryDeadline", "nextAttemptAt", "lastAttemptAt", "attempts", "conversationId", "runId", "runStatus", "runError", "pendingApprovals" ], "description": "One firing of an automation: what evidence triggered it, its delivery state, and the run it produced, if any." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Pause firing Pauses the automation: its clock and readers stop, its pending occurrences are canceled, and any contract's standing authority is withdrawn. `automations.enable` resumes it later — except a contract automation, which cannot be resumed once paused. `POST /v1/users/{userId}/automations/{automationId}/disable` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID/disable' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The automation, updated. ```json { "description": "The automation, updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Automation" } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `automation_changed` — the `revision` sent is stale; reload the automation ```json { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.disable", "summary": "Pause firing", "tags": [ "automations" ], "description": "Pauses the automation: its clock and readers stop, its pending occurrences are canceled, and any contract's standing authority is withdrawn. `automations.enable` resumes it later — except a contract automation, which cannot be resumed once paused.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The automation, updated.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Automation" } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "Automation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "name": { "type": "string", "description": "The automation's name." }, "prompt": { "type": "string", "description": "The instructions given to the model each time this automation fires." }, "rule": { "$ref": "#/components/schemas/AutomationRule" }, "sourcePlans": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "result": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "const": "ready", "description": "The binding is fully planned and ready to collect." }, "plan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "How one binding will actually be collected: the operation, its guarantees and its configuration." } }, "required": [ "status", "plan" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "needs_connection", "description": "The binding is plannable but needs a connection the owner has not granted yet." }, "candidatePlan": { "type": "object", "properties": { "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this plan uses." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "descriptorFingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash of the source descriptor this plan was built from." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." }, "guarantees": { "type": "object", "properties": { "minCadenceSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "The shortest interval between requests the provider permits, in seconds." }, "expectedLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 2147483 }, { "type": "null" } ], "description": "How stale the provider's own value may be when it answers, in seconds; null when the provider establishes no bound. A reader with a delivery deadline cannot use a source that promises nothing here." }, "maxAgeSeconds": { "type": "integer", "minimum": 0, "maximum": 2147483, "description": "Maximum snapshot observation age accepted at collection. This acquisition guarantee does not shorten a reader's separately declared evaluation-age window." }, "requestsPerMinute": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The provider's own rate limit for this source, when it publishes one." }, "observationReuseSeconds": { "description": "How long one provider observation may serve every reader watching the same subject under the same connection, in seconds. Absent or 0 means each reader causes its own request. A reused observation keeps the provider's own `sourceTime`, so declared freshness still governs; what reuse changes is how often the provider is asked, not how old an accepted observation may be. Keep it at or below the cadence readers are expected to poll at.", "type": "integer", "minimum": 0, "maximum": 2147483 }, "batchLimit": { "description": "How many distinct subjects the provider can serve in one request. Absent or 1 means no batching. Only providers implementing `readBatch` may declare more: the framework cannot infer that an API accepts several subjects.", "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 } }, "required": [ "minCadenceSeconds", "expectedLatencySeconds", "maxAgeSeconds", "requestsPerMinute" ], "description": "What an operation promises about the snapshots it serves: cadence, freshness and how many subjects it can batch. Describes sampled state; nothing here promises that a change between two polls was seen." }, "scopeKind": { "type": "string", "enum": [ "public", "user" ], "description": "Who this binding is scoped to: `public` data anyone can read, `user` data read under the owner's own connection." }, "explanation": { "type": "string", "maxLength": 2048, "description": "Why this plan was chosen, in the reviewer's own words." }, "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "degraded": { "type": "boolean", "description": "Whether this plan settled for weaker guarantees than the rule asked for." } }, "required": [ "operationId", "operationVersion", "descriptorFingerprint", "config", "requirement", "guarantees", "scopeKind", "explanation", "degraded" ], "description": "The plan that would apply once the missing connection is granted." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "candidatePlan", "reasons" ] }, { "type": "object", "properties": { "status": { "type": "string", "const": "unsupported", "description": "The binding cannot be planned at all, as asked." }, "reasons": { "minItems": 1, "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A machine-readable reason code." }, "path": { "description": "The field this reason is about, when it is about one.", "type": "string", "maxLength": 256 }, "message": { "type": "string", "maxLength": 2048, "description": "The reason, in the reviewer's own words." } }, "required": [ "code", "message" ] }, "description": "Why this binding could not be planned as asked." } }, "required": [ "status", "reasons" ] } ], "description": "Whether this binding is ready, needs a connection, or is unsupported, and why." } }, "required": [ "binding", "result" ] }, "description": "How each of the rule's bindings will actually be collected." }, "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." }, "enabled": { "type": "boolean", "description": "Whether this automation is currently firing." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this automation was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this automation was last changed." }, "archivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this automation was archived, when it has been." }, "hold": { "anyOf": [ { "type": "object", "properties": { "at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the hold began." }, "reason": { "description": "Why an operator placed the hold, when they gave one.", "type": [ "string", "null" ] } }, "required": [ "at", "reason" ] }, { "type": "null" } ], "description": "An operator's hold: why future work is stopped, so the owner does not read it as their own doing." }, "nextFireAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this automation's clock will next wake it, when it has a schedule and is enabled." }, "monitoring": { "$ref": "#/components/schemas/AutomationMonitoring" }, "activeOccurrence": { "anyOf": [ { "$ref": "#/components/schemas/AutomationOccurrence" }, { "type": "null" } ], "description": "The occurrence currently running, when one is." }, "latestOccurrence": { "anyOf": [ { "$ref": "#/components/schemas/AutomationOccurrence" }, { "type": "null" } ], "description": "The most recent occurrence, running or not, when there has been one." }, "contract": { "anyOf": [ { "type": "object", "properties": { "terms": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "near_intents_transfer", "description": "Which contract template this is." }, "actions": { "minItems": 1, "maxItems": 16, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "swap", "description": "Exchange one asset for another; custody never leaves the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "withdraw_to_owner", "description": "Return an asset to the account that owns the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." } }, "required": [ "kind", "input", "quantity", "output" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send", "description": "Pay a pinned destination outside the agent wallet." }, "input": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action spends: pinned to one token, or any token the agent wallet holds." }, "quantity": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_tokens", "description": "Spend an exact amount of the input token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact input amount, in the input token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Spend an exact quantity of the input token, not its USD value. Exactly 5 USDC with verified input decimals 6 means amountRaw \"5000000\". Scale the requested decimal digits using the verified input decimals; reject excess fractional digits. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_input_value_usd", "description": "Spend a USD-denominated value of the input token." }, "value": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})(?:\\.\\d{1,18})?$", "description": "The USD value to spend, as a decimal string." } }, "required": [ "kind", "value" ], "description": "Spend a USD-denominated value of the input token: \"$5 worth of USDC\" means value \"5\". The host calculates token units from live prices. This does not mean exactly 5 USDC; never substitute it for a token-denominated quantity." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "exact_output_tokens", "description": "Receive an exact amount of the output token." }, "amountRaw": { "type": "string", "pattern": "^(0|[1-9]\\d{0,38})$", "description": "The exact output amount, in the output token's smallest unit." } }, "required": [ "kind", "amountRaw" ], "description": "Receive an exact quantity of the output token. Scale the requested decimal digits using the verified output decimals to obtain amountRaw; reject excess fractional digits. The host calculates the required input. No floating-point arithmetic or bash." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "all_of_input", "description": "Spend everything the agent wallet holds of the input asset." } }, "required": [ "kind" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "fraction_of_input", "description": "Spend a fraction of the input asset." }, "bps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The fraction to spend, in basis points of the input asset." } }, "required": [ "kind", "bps" ] } ], "description": "How much moves: an exact token amount, an exact USD value, an exact output amount, all of the input, or a fraction of it." }, "output": { "anyOf": [ { "type": "object", "properties": { "pinned": { "type": "object", "properties": { "tokenId": { "type": "string", "pattern": "^nep141:[a-z0-9]+(?:[._-][a-z0-9]+)*$", "description": "The token's NEP-141 identifier." }, "decimals": { "type": "integer", "minimum": 0, "maximum": 38, "description": "How many decimal places the token's smallest unit represents." } }, "required": [ "tokenId", "decimals" ], "description": "The exact token this asset is pinned to." } }, "required": [ "pinned" ] }, { "type": "object", "properties": { "any": { "type": "boolean", "const": true, "description": "Any token the agent wallet holds; the executor picks one at execution." } }, "required": [ "any" ] } ], "description": "The asset this action produces: pinned to one token, or left open." }, "recipient": { "type": "object", "properties": { "chain": { "type": "string", "minLength": 1, "maxLength": 32, "description": "Which chain the destination address is on." }, "address": { "type": "string", "pattern": "^[\\x21-\\x7e]{1,128}$", "description": "The destination address on that chain." } }, "required": [ "chain", "address" ], "description": "The pinned destination this action pays." } }, "required": [ "kind", "input", "quantity", "output", "recipient" ] } ] }, "description": "The actions this contract authorizes, executed in order." }, "validUntil": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this contract's authority expires." }, "maxExecutions": { "type": "integer", "minimum": 1, "maximum": 10000, "description": "How many times this contract may be executed before it is exhausted." }, "bounds": { "type": "object", "properties": { "maxValueLossBps": { "type": "string", "pattern": "^(0|[1-9]\\d{0,4})$", "description": "The most value an execution may give up to price movement and fees together, in basis points." }, "maxSignatureLifetimeSeconds": { "type": "integer", "minimum": 1, "maximum": 259500, "description": "Explicit maximum lifetime of each released transfer signature, in seconds. 1Click confidential swaps require up to 259500 seconds (72 hours 5 minutes). This does not extend the short execution window or approval validity." } }, "required": [ "maxValueLossBps", "maxSignatureLifetimeSeconds" ], "description": "The value-loss and signature-lifetime limits every execution must respect." } }, "required": [ "type", "actions", "validUntil", "maxExecutions", "bounds" ] } ], "description": "The approved contract's exact terms." }, "accountId": { "type": "string", "minLength": 1, "description": "The intents account this contract authorizes." }, "approvedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the owner approved this contract." }, "revokedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When this contract was withdrawn, when it has been." }, "executionsUsed": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Plans that consumed allowance, from the plan and leg ledger." } }, "required": [ "terms", "accountId", "approvedAt", "revokedAt", "executionsUsed" ] }, { "type": "null" } ], "description": "The standing financial authority this automation's engine-fired runs execute under; null for an automation without one." } }, "required": [ "id", "name", "prompt", "rule", "sourcePlans", "revision", "enabled", "createdAt", "updatedAt", "archivedAt", "hold", "nextFireAt", "monitoring", "activeOccurrence", "latestOccurrence", "contract" ], "description": "One automation: its rule, its current sources, its monitoring health, and the occurrences it has fired." }, "AutomationRule": { "type": "object", "properties": { "schemaVersion": { "type": "number", "const": 1, "description": "The rule schema's version; always `1`." }, "delivery": { "default": { "overlap": "queue", "maxPendingOccurrences": 100 }, "oneOf": [ { "type": "object", "properties": { "overlap": { "type": "string", "const": "queue", "description": "Queue a new occurrence and run it once the active one finishes." }, "maxPendingOccurrences": { "type": "integer", "minimum": 1, "maximum": 100, "description": "How many occurrences may wait in the queue, not counting the one currently active, including one whose run is itself waiting on an approval." } }, "required": [ "overlap", "maxPendingOccurrences" ] }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "coalesce", "description": "Close the occurrence already pending as `coalesced` and record the new match as a fresh occurrence, rather than queuing a second." } }, "required": [ "overlap" ] }, { "type": "object", "properties": { "overlap": { "type": "string", "const": "skip", "description": "Drop a new match while an occurrence is already active." } }, "required": [ "overlap" ] } ], "description": "What happens when a new occurrence is ready before the previous one has finished." }, "maxDeliveryLatenessSeconds": { "default": 86400, "description": "How long a new occurrence may wait to be delivered before its deadline passes and it is refused, in seconds.", "type": "integer", "minimum": 1, "maximum": 86400 }, "maxEvaluationGapSeconds": { "default": 600, "description": "The longest gap allowed between evaluations before `firing.mode: rising_edge` treats its history as broken and waits for a fresh baseline, in seconds.", "type": "integer", "minimum": 1, "maximum": 2678400 }, "wakes": { "minItems": 1, "maxItems": 7, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "at", "description": "A one-time wake at an exact moment; exhausted after that check, even if its condition is false." }, "runAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$", "description": "The exact moment this wake fires, as an ISO 8601 timestamp with an offset." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "runAt", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "interval", "description": "A wake that repeats on a fixed elapsed interval." }, "intervalMinutes": { "type": "integer", "minimum": 1, "maximum": 44640, "description": "How often this wake repeats, in minutes." }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "intervalMinutes", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "calendar", "description": "A wake on a recurring calendar schedule: local times, weekdays, months and days of the month." }, "timeZone": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The IANA time zone a calendar wake's local times are interpreted in." }, "localTimes": { "minItems": 1, "maxItems": 24, "type": "array", "items": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$" }, "description": "The times of day this wake fires, each in 24-hour `HH:MM` form, in `timeZone`." }, "weekdays": { "default": [ 1, 2, 3, 4, 5, 6, 7 ], "description": "Which ISO weekdays this wake fires on, 1 (Monday) through 7 (Sunday). Defaults to every day.", "minItems": 1, "maxItems": 7, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "months": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ], "description": "Which months this wake fires in, 1 (January) through 12 (December). Defaults to every month.", "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 12 } }, "monthDays": { "default": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ], "description": "Which days of the month this wake fires on, 1 through 31. Defaults to every day.", "minItems": 1, "maxItems": 31, "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 31 } }, "misfire": { "default": { "mode": "latest", "maxLatenessSeconds": null }, "oneOf": [ { "type": "object", "properties": { "mode": { "type": "string", "const": "skip", "description": "Drop a wake the engine could not evaluate in time; wait for the next one." }, "graceSeconds": { "default": 5, "description": "How late this wake may still run before it counts as missed, in seconds.", "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "mode", "graceSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "latest", "description": "Run once for the most recently missed wake, dropping any earlier ones." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] }, { "type": "object", "properties": { "mode": { "type": "string", "const": "all", "description": "Run once for every missed wake, oldest first." }, "maxLatenessSeconds": { "default": null, "description": "How late a missed wake may still run, in seconds; null for no limit.", "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2678400 }, { "type": "null" } ] } }, "required": [ "mode", "maxLatenessSeconds" ] } ], "description": "What happens when the engine could not evaluate this wake on time." }, "evaluationTime": { "default": "detection_time", "description": "Which moment this wake is evaluated as of: `scheduled_time` the time it was due, `detection_time` when the engine actually ran it.", "type": "string", "enum": [ "scheduled_time", "detection_time" ] } }, "required": [ "kind", "timeZone", "localTimes", "weekdays", "months", "monthDays", "misfire", "evaluationTime" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event", "description": "A wake evaluated each time a matching custom webhook event arrives." }, "eventType": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_.:-]{0,79}$", "description": "The event `type` this wake matches; a live webhook delivery of a different type is ignored before it reaches the condition." }, "fields": { "maxItems": 32, "type": "array", "items": { "type": "object", "properties": { "path": { "minItems": 1, "maxItems": 8, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$" }, "description": "The keys to walk, in order, from an observation's top level down to this field." }, "valueType": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "boolean", "description": "A true/false value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "string", "description": "A text value." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "integer", "description": "A whole-number value, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "decimal", "description": "An exact decimal value, as text, compared exactly." }, "unit": { "type": "string", "minLength": 1, "maxLength": 64, "description": "The unit an integer or decimal value is measured in, as the source or literal declares it." } }, "required": [ "type", "unit" ] } ], "description": "What type this field's value has, and the unit it carries when it has one." }, "optional": { "description": "Whether the provider may genuinely not observe this field, rather than fail to read it. When true, a missing value resolves a condition over it to `missing_field` and the rule's verdict to `unknown`, rather than zero, null or false.", "type": "boolean" } }, "required": [ "path", "valueType" ], "description": "One data field an event or a source's observation carries: where it lives, and its type." }, "description": "The data fields an event of this type is declared to carry." } }, "required": [ "kind", "eventType", "fields" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "reader_update", "description": "A wake evaluated each time the named reader delivers a fresh observation." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "kind", "binding" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "manual", "description": "A wake fired only by `automations.invoke` or `automations.signal`, never on its own." } }, "required": [ "kind" ] } ] }, "description": "Occasions to evaluate the rule's condition: alternatives, not an AND of conditions. At most one clock, one event stream and one manual wake." }, "readers": { "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "readerId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The installed source operation's id, as returned by `automationSources.list`." }, "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." }, "pollIntervalSeconds": { "type": "integer", "minimum": 1, "maximum": 2147483, "description": "How often this reader polls its source, in seconds." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum retained input age at evaluation, matching requirement.maxAgeSeconds when present. Snapshots use observation time; events use trusted receipt time. Collection separately enforces the provider's acquisition-age guarantee." }, "requirement": { "type": "object", "properties": { "maxLatencySeconds": { "anyOf": [ { "type": "integer", "minimum": 1, "maximum": 2147483 }, { "type": "null" } ], "description": "The target delay between an observation and its delivery, in seconds; null when delivery has no target deadline." }, "maxAgeSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Maximum acceptable input age at evaluation, matching the reader's maxAgeSeconds, measured from the provider's own observation time. The selected provider's acquisition guarantee must fit within this limit and does not reduce this evaluation window." }, "allowDegradedLatency": { "type": "boolean", "description": "Whether delivery slower than the target delay is still accepted." }, "maxAcceptedLatencySeconds": { "description": "The slowest delivery still accepted, in seconds, when `allowDegradedLatency` is set.", "type": "integer", "minimum": 1, "maximum": 2147483 } }, "required": [ "maxLatencySeconds", "maxAgeSeconds", "allowDegradedLatency" ], "description": "What a reader needs from its source: how fresh an answer must be, and whether a slower one is still acceptable." } }, "required": [ "name", "readerId", "config", "pollIntervalSeconds", "maxAgeSeconds" ] }, "description": "The named source bindings this rule reads from, referenced by `condition` and by each `reader_update` wake's `binding`." }, "condition": { "description": "The rule's condition tree, up to 8 levels deep and 128 nodes total, built from five node kinds: `{op:\"bool\", value}` a fixed true/false leaf; `{op:\"compare\", comparator, left, right}` one of `eq`/`ne`/`lt`/`lte`/`gt`/`gte` between two operands — `lt`/`lte`/`gt`/`gte` require both operands to be `integer` or `decimal`, and both sides must share the same type and, for `integer`/`decimal`, the same unit; `{op:\"all\", args}` / `{op:\"any\", args}` AND/OR over one or more child nodes; `{op:\"not\", arg}` negates one child node. An operand is either `{kind:\"field\", binding, path}` — a bound reader's name and the key path into its data — or `{kind:\"literal\", type, value, unit?}` with `type` one of `boolean`/`string`/`integer`/`decimal` (`integer`/`decimal` values are exact decimal strings and carry `unit`). `automations.testCondition` evaluates the tree against a given event without firing." }, "firing": { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "each_match", "rising_edge" ], "description": "When a qualifying evaluation fires: `each_match` fires on every qualifying evaluation, including the first; `rising_edge` fires only on a known false-to-true transition." }, "repeat": { "type": "string", "enum": [ "once", "repeating" ], "description": "Whether this rule fires at most once, or keeps watching after it fires." }, "maxRuns": { "description": "Maximum deliverable runs recorded for this automation across pauses and resumes. Missed or refused deliveries do not count; recorded runs count even if later canceled, coalesced or failed. Omit for no finite limit beyond repeat=once.", "type": "integer", "minimum": 1, "maximum": 1000000 }, "initial": { "type": "string", "enum": [ "baseline", "fire_if_true" ], "description": "How `rising_edge` treats the first known state: `baseline` records it without firing, `fire_if_true` fires immediately if it is already true." }, "cooldownSeconds": { "type": "integer", "minimum": 0, "maximum": 2678400, "description": "The minimum time between firings, in seconds; it does not require the condition to stay true that whole time. For `rising_edge`, a false-to-true edge that lands inside cooldown is discarded, not queued: it is not replayed once cooldown ends, so the rule needs an entirely fresh edge after cooldown lapses before it fires again — simply remaining true past the cooldown boundary does not trigger a firing." } }, "required": [ "mode", "repeat", "initial", "cooldownSeconds" ], "description": "How this rule turns a qualifying evaluation into a firing: which ones count, how often, and how many." }, "maxSnapshotSkewSeconds": { "type": "integer", "minimum": 0, "maximum": 86400, "description": "The most that bound readers' observation times may disagree before evaluation reports `snapshot_skew`, in seconds." } }, "required": [ "schemaVersion", "delivery", "maxDeliveryLatenessSeconds", "maxEvaluationGapSeconds", "wakes", "readers", "condition", "firing", "maxSnapshotSkewSeconds" ], "description": "One automation's rule: when it wakes, what condition it evaluates, and how it fires." }, "AutomationJsonValue": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValue" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" } } ] }, "AutomationMonitoring": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable", "paused", "completed" ], "description": "The automation's overall monitoring status: `waiting` no evaluation yet, `healthy` sources and evaluation are current, `stale` an input is older than expected, `unavailable` a source could not be reached, `paused` firing is paused, `completed` its run policy is spent." }, "lastCheckedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When monitoring last checked this automation's sources." }, "sources": { "maxItems": 5, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "description": "The source's id within its provider." }, "check": { "description": "The most recent recipe check against this source, when evidence review is configured.", "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ] }, "status": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable" ], "description": "This source's health: `waiting` no observation yet, `healthy` fresh, `stale` older than expected, `unavailable` the provider could not be reached." }, "sourceTime": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider says the most recent observation was true." }, "receivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine received the most recent observation." }, "reason": { "description": "Why the source is not healthy, when it is not.", "type": [ "string", "null" ] } }, "required": [ "binding", "sourceId", "status", "sourceTime", "receivedAt", "reason" ] }, "description": "Each bound source's own health." }, "lastEvaluation": { "anyOf": [ { "type": "object", "properties": { "verdict": { "type": "string", "enum": [ "true", "false", "unknown" ], "description": "Whether the rule's condition holds: `true` it fires, `false` it does not, `unknown` an input could not be read, so the rule neither fires nor is treated as false." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this evaluation ran." }, "reasons": { "maxItems": 256, "type": "array", "items": { "type": "object", "properties": { "nodePath": { "maxItems": 8, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "description": "The path to the condition node this reason explains, as indices into the rule tree." }, "code": { "type": "string", "enum": [ "missing_source", "unavailable", "gap", "stale", "future", "missing_field", "invalid_value", "snapshot_skew" ], "description": "Why this node could not cleanly resolve: `missing_source` no binding was configured, `unavailable` the provider did not answer, `gap` a break in coverage was recorded, `stale` or `future` a timestamp was out of range, `missing_field` the observation lacked this field, `invalid_value` the value did not match its declared type, `snapshot_skew` the inputs disagreed on when they were true." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "nodePath", "code" ] }, "description": "Why the verdict is what it is, one entry per condition node that did not cleanly resolve." }, "inputs": { "maxItems": 5, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "const": "snapshot", "description": "A point-in-time read of current state." }, "sourceTime": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the provider says this snapshot was true." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime" ] }, { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "const": "received_event", "description": "An event the source pushed, or the engine collected as it happened." }, "sourceTime": { "type": "null", "description": "Not applicable to a received event; see `occurredAt` and `providerPublishedAt` instead." }, "providerPublishedAt": { "anyOf": [ { "type": "string", "maxLength": 64, "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" }, { "type": "null" } ], "description": "When the provider says it published this event, when it reports one." }, "occurredAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the event actually happened, when the provider reports that separately from when it was published." }, "finalizedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider considers this event no longer subject to correction, when it reports one." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime", "providerPublishedAt", "occurredAt", "finalizedAt" ] } ] }, "description": "Each input this evaluation read, without its raw data." } }, "required": [ "verdict", "evaluatedAt", "reasons", "inputs" ] }, { "type": "null" } ], "description": "The rule's most recent evaluation, when it has run at least once." }, "webhook": { "anyOf": [ { "type": "object", "properties": { "configured": { "type": "boolean", "description": "Whether a webhook secret has been minted." }, "keyId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The current webhook secret's id, for rotation." }, "lastReceivedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the webhook last received a request." } }, "required": [ "configured", "keyId", "lastReceivedAt" ] }, { "type": "null" } ], "description": "This automation's inbound webhook, when its rule listens for one." }, "reason": { "description": "Why status is not healthy, when it is not.", "type": [ "string", "null" ] } }, "required": [ "status", "lastCheckedAt", "sources", "lastEvaluation", "webhook", "reason" ], "description": "An automation's current health: its sources, its most recent evaluation, and its inbound webhook, if it has one." }, "AutomationOccurrence": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The occurrence's id." }, "deliverySequence": { "type": "string", "pattern": "^[1-9]\\d*$", "description": "This occurrence's place in its automation's delivery order, as a string so it sorts and compares exactly at any size." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The automation definition version this occurrence fired under." }, "activationEpoch": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The activation epoch this occurrence fired under." }, "name": { "type": "string", "description": "The automation's name at the time this occurrence fired." }, "prompt": { "type": "string", "description": "The automation's prompt at the time this occurrence fired." }, "evidence": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "decision", "manual", "external" ], "description": "What produced this occurrence: `decision` the rule's own condition, `manual` an owner's invoke or signal, `external` a source that decided on the engine's behalf." }, "identity": { "type": "string", "minLength": 1, "maxLength": 256, "description": "A stable string identifying this exact decision, used to deduplicate replays." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this decision was made." }, "data": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValue" }, "description": "The observations behind one decision, exactly as evaluated. Bounded to 256 KiB, 24 levels of nesting and 16384 entries." }, "sourceChecks": { "description": "Recipe checks recorded for each source this decision read, when evidence review is configured.", "maxItems": 4, "type": "array", "items": { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding this check was collected for." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The specific event or observation this check backs." }, "operationId": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,79}$", "description": "The collection operation this check ran." }, "operationVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The collection operation's version." }, "check": { "type": "object", "properties": { "recipe": { "type": "object", "properties": { "version": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The recipe description's own version, bumped when its steps change." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The recipe's short label, for the reviewed catalog." }, "summary": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What the recipe does, for the reviewed catalog." }, "steps": { "minItems": 1, "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The step's identifier, unique within its recipe." }, "kind": { "type": "string", "enum": [ "request", "validate", "calculate" ], "description": "What this step does: `request` calls the provider, `validate` checks what it returned, `calculate` derives a value from earlier steps." }, "title": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The step's short label, for the reviewed catalog." }, "description": { "type": "string", "minLength": 1, "maxLength": 600, "description": "What this step does, for the reviewed catalog." }, "api": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "GRAPHQL" ], "description": "The request's method or protocol." }, "resource": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^\\/?[A-Za-z0-9_{}][A-Za-z0-9_./{} -]*$", "description": "The request's path or resource name." } }, "required": [ "method", "resource" ], "description": "The request this step makes, when it calls the provider." } }, "required": [ "id", "kind", "title", "description" ] }, "description": "The recipe's steps, in order." }, "limitations": { "maxItems": 6, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 600 }, "description": "What the recipe does not cover, in the reviewer's own words." }, "fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$", "description": "A content hash identifying this exact recipe, independent of execution or connection identity." } }, "required": [ "version", "title", "summary", "steps", "limitations", "fingerprint" ], "description": "A reviewed, public description of how a source is collected: the steps a reviewer confirmed, never an executable request or a resolved private endpoint." }, "startedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check began." }, "completedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check finished." }, "status": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether every step completed." }, "steps": { "maxItems": 12, "type": "array", "items": { "type": "object", "properties": { "stepId": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,47}$", "description": "The declared recipe step this check reports on." }, "outcome": { "type": "string", "enum": [ "completed", "failed" ], "description": "Whether the step completed or failed." }, "requestCount": { "description": "How many requests this step made, when it made any.", "type": "integer", "minimum": 0, "maximum": 100000 }, "itemCount": { "description": "How many items this step processed, when counting applies.", "type": "integer", "minimum": 0, "maximum": 1000000 }, "durationMs": { "description": "How long this step took, in milliseconds.", "type": "integer", "minimum": 0, "maximum": 600000 }, "reason": { "description": "Why the step failed, when it did: `not_configured` the source lacks a needed setting, `unavailable` the provider did not answer, `malformed` its answer could not be read, `oversized` the answer exceeded a bound, `stale` or `future` a timestamp was out of range, `incomplete` part of the answer was missing, `invalid` the answer failed validation, `canceled` the check was stopped before finishing.", "type": "string", "enum": [ "not_configured", "unavailable", "malformed", "oversized", "stale", "future", "incomplete", "invalid", "canceled" ] } }, "required": [ "stepId", "outcome" ], "description": "One recipe step's recorded outcome: counts and a closed reason only, never a URL, body, cursor, address or error message." }, "description": "Each step's own recorded outcome, in order." } }, "required": [ "recipe", "startedAt", "completedAt", "status", "steps" ], "description": "A recorded run of a recipe's steps against the real source, kept as evidence." } }, "required": [ "binding", "sourceId", "eventId", "operationId", "operationVersion", "check" ], "description": "Frozen recipe evidence tied to the actual observation used by one decision." } } }, "required": [ "kind", "identity", "evaluatedAt", "data" ], "description": "What triggered this occurrence: the decision, its evaluated data, and any recipe checks behind it." }, "state": { "type": "string", "enum": [ "pending", "deferred", "accepted", "rejected", "canceled", "skipped", "coalesced" ], "description": "This occurrence's delivery state: `pending` waiting to run, `deferred` an admission attempt failed and is waiting to retry, `accepted` handed to a run, `rejected` the delivery policy refused it outright, or a non-retryable admission failure (or an exhausted retry deadline) stopped it, `canceled` stopped before running, `skipped` a previous occurrence was still active, `coalesced` merged into a newer match." }, "reason": { "description": "Why the occurrence is in this state, when there is one to give.", "type": [ "string", "null" ] }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this occurrence was recorded." }, "deliveryDeadline": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The latest this occurrence could still be delivered." }, "nextAttemptAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine will next try to deliver this occurrence." }, "lastAttemptAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the engine last tried to deliver this occurrence, when it has tried." }, "attempts": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many delivery attempts this occurrence has had." }, "conversationId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The conversation's id." }, { "type": "null" } ], "description": "The conversation this occurrence ran in, once it has one." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, { "type": "null" } ], "description": "The run this occurrence produced, once it has one." }, "runStatus": { "anyOf": [ { "type": "string", "enum": [ "running", "paused", "completed", "failed", "aborted" ] }, { "type": "null" } ], "description": "That run's status, once it has one: `running`, `paused` while an approval waits, then `completed`, `failed` or `aborted`." }, "runError": { "description": "Why the run failed, when it did.", "type": [ "string", "null" ] }, "pendingApprovals": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many approvals this occurrence's run is waiting on." } }, "required": [ "id", "deliverySequence", "automationId", "definitionVersion", "activationEpoch", "name", "prompt", "evidence", "state", "reason", "createdAt", "deliveryDeadline", "nextAttemptAt", "lastAttemptAt", "attempts", "conversationId", "runId", "runStatus", "runError", "pendingApprovals" ], "description": "One firing of an automation: what evidence triggered it, its delivery state, and the run it produced, if any." }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Fire now Fires the automation immediately, bypassing its rule's condition. `revision` must match the automation's current one, and `idempotencyKey` makes the call safe to repeat: calling again with the same key before it finishes answers the same outcome rather than firing twice. The occurrence this creates, and the run it produces, follow through `automations.history`. `POST /v1/users/{userId}/automations/{automationId}/invoke` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." }, "idempotencyKey": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "A client-chosen id that makes this call repeatable: calling again with the same key before it finishes answers the same outcome rather than acting twice. Shared by `automations.invoke` and `automations.signal`." }, "input": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." } }, "required": [ "revision", "idempotencyKey" ], "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID/invoke' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data-binary '@request.json' ``` ## Responses ### 200 What happened to the invocation. ```json { "description": "What happened to the invocation.", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "recorded", "duplicate", "skipped", "rejected" ], "description": "What happened to this invocation: `recorded` a new occurrence was created and is pending, `duplicate` this idempotency key was already recorded, `skipped` a previous occurrence for this automation is still active, `rejected` the delivery policy refused it (its queue is full, or its deadline had already passed)." }, "occurrenceId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The occurrence this invocation created or matched." } }, "required": [ "status", "occurrenceId" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `automation_changed` — the `revision` sent is stale; reload the automation - `automation_held` — an operator holds the automation; it fires again when released - `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired - `automation_completed` — the automation has finished for good and cannot fire again ```json { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation\n- `automation_held` — an operator holds the automation; it fires again when released\n- `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired\n- `automation_completed` — the automation has finished for good and cannot fire again", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.invoke", "summary": "Fire now", "tags": [ "automations" ], "description": "Fires the automation immediately, bypassing its rule's condition. `revision` must match the automation's current one, and `idempotencyKey` makes the call safe to repeat: calling again with the same key before it finishes answers the same outcome rather than firing twice. The occurrence this creates, and the run it produces, follow through `automations.history`.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." }, "idempotencyKey": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "A client-chosen id that makes this call repeatable: calling again with the same key before it finishes answers the same outcome rather than acting twice. Shared by `automations.invoke` and `automations.signal`." }, "input": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." } }, "required": [ "revision", "idempotencyKey" ], "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "What happened to the invocation.", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "recorded", "duplicate", "skipped", "rejected" ], "description": "What happened to this invocation: `recorded` a new occurrence was created and is pending, `duplicate` this idempotency key was already recorded, `skipped` a previous occurrence for this automation is still active, `rejected` the delivery policy refused it (its queue is full, or its deadline had already passed)." }, "occurrenceId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The occurrence this invocation created or matched." } }, "required": [ "status", "occurrenceId" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation\n- `automation_held` — an operator holds the automation; it fires again when released\n- `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired\n- `automation_completed` — the automation has finished for good and cannot fire again", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "AutomationJsonValueInput": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValueInput" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Send signal Hands the rule's condition an event to evaluate, as if a source had delivered it; `automations.invoke` bypasses that decision instead. `revision` must match the automation's current one, and `idempotencyKey` makes the call safe to repeat: calling again with the same key answers the same outcome rather than recording it twice. `POST /v1/users/{userId}/automations/{automationId}/signal` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." }, "idempotencyKey": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "A client-chosen id that makes this call repeatable: calling again with the same key before it finishes answers the same outcome rather than acting twice. Shared by `automations.invoke` and `automations.signal`." }, "input": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." } }, "required": [ "revision", "idempotencyKey" ], "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID/signal' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data-binary '@request.json' ``` ## Responses ### 200 Whether the signal was recorded. ```json { "description": "Whether the signal was recorded.", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "recorded", "duplicate" ], "description": "Whether this signal was newly recorded, or was already recorded under the same idempotency key." }, "inputId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The recorded signal's id." } }, "required": [ "status", "inputId" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `automation_changed` — the `revision` sent is stale; reload the automation - `automation_held` — an operator holds the automation; it fires again when released - `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired - `automation_completed` — the automation has finished for good and cannot fire again ```json { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation\n- `automation_held` — an operator holds the automation; it fires again when released\n- `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired\n- `automation_completed` — the automation has finished for good and cannot fire again", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.signal", "summary": "Send signal", "tags": [ "automations" ], "description": "Hands the rule's condition an event to evaluate, as if a source had delivered it; `automations.invoke` bypasses that decision instead. `revision` must match the automation's current one, and `idempotencyKey` makes the call safe to repeat: calling again with the same key answers the same outcome rather than recording it twice.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." }, "idempotencyKey": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "A client-chosen id that makes this call repeatable: calling again with the same key before it finishes answers the same outcome rather than acting twice. Shared by `automations.invoke` and `automations.signal`." }, "input": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." } }, "required": [ "revision", "idempotencyKey" ], "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "Whether the signal was recorded.", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "recorded", "duplicate" ], "description": "Whether this signal was newly recorded, or was already recorded under the same idempotency key." }, "inputId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The recorded signal's id." } }, "required": [ "status", "inputId" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation\n- `automation_held` — an operator holds the automation; it fires again when released\n- `deployment_paused` — an operator paused a deployment control; nothing was admitted or fired\n- `automation_completed` — the automation has finished for good and cannot fire again", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "AutomationJsonValueInput": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValueInput" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Rotate webhook secret Mints a new inbound webhook secret for the automation; the previous one stops working at once. Only works on an enabled automation whose rule has an event wake: anything else is refused as `automation_changed`, the same reason a stale `revision` gets, even when the revision sent is perfectly current. `revision` must match the automation's current one. `POST /v1/users/{userId}/automations/{automationId}/rotate-webhook-secret` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." } }, "required": [ "revision" ], "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID/rotate-webhook-secret' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data-binary '@request.json' ``` ## Responses ### 200 The new webhook secret and where it is received. ```json { "description": "The new webhook secret and where it is received.", "content": { "application/json": { "schema": { "type": "object", "properties": { "secret": { "type": "string", "pattern": "^[A-Za-z0-9_-]{43}$", "description": "The new webhook secret. Shown once; it cannot be read back later." }, "keyId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The new secret's id." }, "path": { "type": "string", "description": "The path this automation's webhook receives requests on." }, "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The definition version this secret was minted for." } }, "required": [ "secret", "keyId", "path", "definitionVersion" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `automation_changed` — the `revision` sent is stale; reload the automation ```json { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.rotateWebhookSecret", "summary": "Rotate webhook secret", "tags": [ "automations" ], "description": "Mints a new inbound webhook secret for the automation; the previous one stops working at once. Only works on an enabled automation whose rule has an event wake: anything else is refused as `automation_changed`, the same reason a stale `revision` gets, even when the revision sent is perfectly current. `revision` must match the automation's current one.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "revision": { "type": "string", "pattern": "^[1-9]\\d*\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "description": "The automation's concurrency token, `.`, unique to one exact version. Writes must echo the value just read back unchanged; a stale one is refused as `automation_changed`." } }, "required": [ "revision" ], "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The new webhook secret and where it is received.", "content": { "application/json": { "schema": { "type": "object", "properties": { "secret": { "type": "string", "pattern": "^[A-Za-z0-9_-]{43}$", "description": "The new webhook secret. Shown once; it cannot be read back later." }, "keyId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The new secret's id." }, "path": { "type": "string", "description": "The path this automation's webhook receives requests on." }, "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The definition version this secret was minted for." } }, "required": [ "secret", "keyId", "path", "definitionVersion" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `automation_changed` — the `revision` sent is stale; reload the automation", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Test condition Evaluates the automation's condition once, against the given event when one is supplied or against its retained source data otherwise. Nothing is recorded and the automation does not fire. `POST /v1/users/{userId}/automations/{automationId}/test-condition` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request body ```json { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "event": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$", "description": "A caller-chosen id for this event, used to deduplicate replays." }, "type": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_.:-]{0,79}$", "description": "This event's own `type`, as the sender reports it." }, "occurredAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event happened, as the sender reports it." }, "data": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." } }, "required": [ "id", "type", "occurredAt", "data" ], "additionalProperties": false, "description": "One event, shaped as an automation's inbound webhook receives it: an id, a type, when it happened, and its data. `automations.testCondition` accepts the same shape to evaluate a rule's condition against exactly the event given, without the type check a live delivery applies." } }, "additionalProperties": false } } } } ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request POST 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID/test-condition' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' \ --header 'Content-Type: application/json' \ --data '{}' ``` ## Responses ### 200 The condition's evaluation against the given event. ```json { "description": "The condition's evaluation against the given event.", "content": { "application/json": { "schema": { "type": "object", "properties": { "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The automation definition version this test evaluated against." }, "evaluation": { "type": "object", "properties": { "verdict": { "type": "string", "enum": [ "true", "false", "unknown" ], "description": "Whether the rule's condition holds: `true` it fires, `false` it does not, `unknown` an input could not be read, so the rule neither fires nor is treated as false." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this evaluation ran." }, "reasons": { "maxItems": 256, "type": "array", "items": { "type": "object", "properties": { "nodePath": { "maxItems": 8, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "description": "The path to the condition node this reason explains, as indices into the rule tree." }, "code": { "type": "string", "enum": [ "missing_source", "unavailable", "gap", "stale", "future", "missing_field", "invalid_value", "snapshot_skew" ], "description": "Why this node could not cleanly resolve: `missing_source` no binding was configured, `unavailable` the provider did not answer, `gap` a break in coverage was recorded, `stale` or `future` a timestamp was out of range, `missing_field` the observation lacked this field, `invalid_value` the value did not match its declared type, `snapshot_skew` the inputs disagreed on when they were true." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "nodePath", "code" ] }, "description": "Why the verdict is what it is, one entry per condition node that did not cleanly resolve." }, "inputs": { "maxItems": 5, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "description": "A point-in-time read of current state.", "enum": [ "snapshot" ] }, "sourceTime": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the provider says this snapshot was true." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime" ] }, { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "description": "An event the source pushed, or the engine collected as it happened.", "enum": [ "received_event" ] }, "sourceTime": { "type": "null", "description": "Not applicable to a received event; see `occurredAt` and `providerPublishedAt` instead." }, "providerPublishedAt": { "anyOf": [ { "type": "string", "maxLength": 64, "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" }, { "type": "null" } ], "description": "When the provider says it published this event, when it reports one." }, "occurredAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the event actually happened, when the provider reports that separately from when it was published." }, "finalizedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider considers this event no longer subject to correction, when it reports one." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime", "providerPublishedAt", "occurredAt", "finalizedAt" ] } ] }, "description": "Each input this evaluation read, without its raw data." } }, "required": [ "verdict", "evaluatedAt", "reasons", "inputs" ], "description": "The condition's evaluation result: its verdict, the data it read, and why, when it did not cleanly resolve." } }, "required": [ "definitionVersion", "evaluation" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 413 The body exceeds the size this deployment accepts. ```json { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.testCondition", "summary": "Test condition", "tags": [ "automations" ], "description": "Evaluates the automation's condition once, against the given event when one is supplied or against its retained source data otherwise. Nothing is recorded and the automation does not fire.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "event": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$", "description": "A caller-chosen id for this event, used to deduplicate replays." }, "type": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_.:-]{0,79}$", "description": "This event's own `type`, as the sender reports it." }, "occurredAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this event happened, as the sender reports it." }, "data": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" }, "description": "Arbitrary JSON data for this event: a manual invocation's or signal's payload, a reader's configuration, or a source plan's configuration. Bounded to 16 KiB, 8 levels of nesting and 256 entries." } }, "required": [ "id", "type", "occurredAt", "data" ], "additionalProperties": false, "description": "One event, shaped as an automation's inbound webhook receives it: an id, a type, when it happened, and its data. `automations.testCondition` accepts the same shape to evaluate a rule's condition against exactly the event given, without the type check a live delivery applies." } }, "additionalProperties": false } } } }, "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The condition's evaluation against the given event.", "content": { "application/json": { "schema": { "type": "object", "properties": { "definitionVersion": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "The automation definition version this test evaluated against." }, "evaluation": { "type": "object", "properties": { "verdict": { "type": "string", "enum": [ "true", "false", "unknown" ], "description": "Whether the rule's condition holds: `true` it fires, `false` it does not, `unknown` an input could not be read, so the rule neither fires nor is treated as false." }, "evaluatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this evaluation ran." }, "reasons": { "maxItems": 256, "type": "array", "items": { "type": "object", "properties": { "nodePath": { "maxItems": 8, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "description": "The path to the condition node this reason explains, as indices into the rule tree." }, "code": { "type": "string", "enum": [ "missing_source", "unavailable", "gap", "stale", "future", "missing_field", "invalid_value", "snapshot_skew" ], "description": "Why this node could not cleanly resolve: `missing_source` no binding was configured, `unavailable` the provider did not answer, `gap` a break in coverage was recorded, `stale` or `future` a timestamp was out of range, `missing_field` the observation lacked this field, `invalid_value` the value did not match its declared type, `snapshot_skew` the inputs disagreed on when they were true." }, "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." } }, "required": [ "nodePath", "code" ] }, "description": "Why the verdict is what it is, one entry per condition node that did not cleanly resolve." }, "inputs": { "maxItems": 5, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "description": "A point-in-time read of current state.", "enum": [ "snapshot" ] }, "sourceTime": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the provider says this snapshot was true." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime" ] }, { "type": "object", "properties": { "binding": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,31}$", "description": "The binding name a rule or a plan gives one configured source." }, "sourceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The source's id within its provider." }, "eventId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The observation or event's id." }, "receivedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When the engine received this observation." }, "maxAgeSeconds": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "How old this observation was allowed to be at evaluation, in seconds." }, "status": { "type": "string", "enum": [ "ready", "unavailable", "gap" ], "description": "Whether this input was ready to evaluate, the provider was unavailable, or a gap was recorded instead." }, "reason": { "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ], "description": "Why the input is not ready, when it is not." }, "kind": { "type": "string", "description": "An event the source pushed, or the engine collected as it happened.", "enum": [ "received_event" ] }, "sourceTime": { "type": "null", "description": "Not applicable to a received event; see `occurredAt` and `providerPublishedAt` instead." }, "providerPublishedAt": { "anyOf": [ { "type": "string", "maxLength": 64, "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" }, { "type": "null" } ], "description": "When the provider says it published this event, when it reports one." }, "occurredAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the event actually happened, when the provider reports that separately from when it was published." }, "finalizedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the provider considers this event no longer subject to correction, when it reports one." } }, "required": [ "binding", "sourceId", "eventId", "receivedAt", "maxAgeSeconds", "status", "reason", "kind", "sourceTime", "providerPublishedAt", "occurredAt", "finalizedAt" ] } ] }, "description": "Each input this evaluation read, without its raw data." } }, "required": [ "verdict", "evaluatedAt", "reasons", "inputs" ], "description": "The condition's evaluation result: its verdict, the data it read, and why, when it did not cleanly resolve." } }, "required": [ "definitionVersion", "evaluation" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "schemas": { "AutomationJsonValueInput": { "description": "Any JSON value: a string, number, boolean, null, array or object, nested to any depth.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" }, { "type": "array", "items": { "$ref": "#/components/schemas/AutomationJsonValueInput" } }, { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/AutomationJsonValueInput" } } ] }, "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "PayloadTooLarge": { "description": "The body exceeds the size this deployment accepts.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Search automations Searches the user's automations, oldest first, matching every given word as a whole token against the name, prompt and reviewed rule description (the same text `automations.status` reports as `behavior`). `state` narrows by lifecycle. The page is small and bounded to a byte cap, meant for a model to read back mid-conversation rather than to browse — see `automations.list` for that. `GET /v1/users/{userId}/automations/search` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ] ``` ## Query parameters ```json [ { "schema": { "type": "string", "maxLength": 120 }, "in": "query", "name": "query", "required": false, "description": "Distinctive search words, not the whole user request. Every word must match a whole token in the name, instructions or reviewed rule description; matching is case-insensitive. Omit to browse." }, { "schema": { "default": "current", "type": "string", "enum": [ "current", "enabled", "paused", "archived", "all" ] }, "in": "query", "name": "state", "required": false, "description": "Which automations match by lifecycle: `current` (the default) every one not archived, `enabled` currently firing, `paused` disabled but not archived, `archived` removed, or `all` regardless of archived." }, { "schema": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "in": "query", "name": "offset", "required": false, "description": "How many matches to skip, to page past a previous result." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/automations/search' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The matching automations. ```json { "description": "The matching automations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "asOf": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The database snapshot time this search ran against." }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many automations match every filter, across every page." }, "items": { "maxItems": 5, "type": "array", "items": { "type": "object", "properties": { "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "name": { "type": "string", "maxLength": 120, "description": "The automation's name." }, "state": { "type": "string", "enum": [ "enabled", "paused", "archived" ], "description": "The automation's lifecycle: `enabled` and firing, `paused` and not firing, or `archived` for good." }, "task": { "type": "object", "properties": { "text": { "type": "string", "maxLength": 160, "description": "The excerpt's text, cut to fit if the source was longer." }, "truncated": { "type": "boolean", "description": "Whether the source text was longer than `text` and had to be cut." } }, "required": [ "text", "truncated" ], "description": "A preview of the automation's current prompt." } }, "required": [ "automationId", "name", "state", "task" ] }, "description": "This page's matches, oldest first." }, "nextOffset": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The offset for the next page, or null once there are no more matches." } }, "required": [ "asOf", "total", "items", "nextOffset" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 409 The operation lost to the current state. - `automation_invalid` — the automation's definition cannot run as written ```json { "description": "The operation lost to the current state.\n\n- `automation_invalid` — the automation's definition cannot run as written", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.search", "summary": "Search automations", "tags": [ "automations" ], "description": "Searches the user's automations, oldest first, matching every given word as a whole token against the name, prompt and reviewed rule description (the same text `automations.status` reports as `behavior`). `state` narrows by lifecycle. The page is small and bounded to a byte cap, meant for a model to read back mid-conversation rather than to browse — see `automations.list` for that.", "parameters": [ { "schema": { "type": "string", "maxLength": 120 }, "in": "query", "name": "query", "required": false, "description": "Distinctive search words, not the whole user request. Every word must match a whole token in the name, instructions or reviewed rule description; matching is case-insensitive. Omit to browse." }, { "schema": { "default": "current", "type": "string", "enum": [ "current", "enabled", "paused", "archived", "all" ] }, "in": "query", "name": "state", "required": false, "description": "Which automations match by lifecycle: `current` (the default) every one not archived, `enabled` currently firing, `paused` disabled but not archived, `archived` removed, or `all` regardless of archived." }, { "schema": { "default": 0, "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "in": "query", "name": "offset", "required": false, "description": "How many matches to skip, to page past a previous result." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The matching automations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "asOf": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The database snapshot time this search ran against." }, "total": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many automations match every filter, across every page." }, "items": { "maxItems": 5, "type": "array", "items": { "type": "object", "properties": { "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "name": { "type": "string", "maxLength": 120, "description": "The automation's name." }, "state": { "type": "string", "enum": [ "enabled", "paused", "archived" ], "description": "The automation's lifecycle: `enabled` and firing, `paused` and not firing, or `archived` for good." }, "task": { "type": "object", "properties": { "text": { "type": "string", "maxLength": 160, "description": "The excerpt's text, cut to fit if the source was longer." }, "truncated": { "type": "boolean", "description": "Whether the source text was longer than `text` and had to be cut." } }, "required": [ "text", "truncated" ], "description": "A preview of the automation's current prompt." } }, "required": [ "automationId", "name", "state", "task" ] }, "description": "This page's matches, oldest first." }, "nextOffset": { "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The offset for the next page, or null once there are no more matches." } }, "required": [ "asOf", "total", "items", "nextOffset" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "description": "The operation lost to the current state.\n\n- `automation_invalid` — the automation's definition cannot run as written", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ``` --- # Get automation status The bounded, model-readable state of one automation: its lifecycle, its overall monitoring status, its most recent evaluation and occurrence. Unlike `automations.get`, evidence here is fixed-size and reviewed for a conversation, never the raw stored value. `GET /v1/users/{userId}/automations/{automationId}/status` ## Authentication Both headers are required. - Header: `X-Api-Key: YOUR_API_KEY` - Header: `Authorization: Bearer YOUR_USER_TOKEN` ## Path parameters ```json [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ] ``` ## Request example Illustrative request. Replace the host, credentials and resource IDs with your own. If a request file is shown, create it from the schema above. Review the requested action before sending it. ```sh curl --request GET 'https://api.example.test/v1/users/YOUR_USER_ID/automations/YOUR_AUTOMATION_ID/status' \ --header 'X-Api-Key: YOUR_API_KEY' \ --header 'Authorization: Bearer YOUR_USER_TOKEN' ``` ## Responses ### 200 The automation's current state and observations. ```json { "description": "The automation's current state and observations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "asOf": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The database snapshot time this status was read as of." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "name": { "type": "string", "maxLength": 120, "description": "The automation's name." }, "state": { "type": "string", "enum": [ "enabled", "paused", "archived" ], "description": "The automation's lifecycle: `enabled` and firing, `paused` and not firing, or `archived` for good." }, "monitoring": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable", "paused", "completed" ], "description": "The automation's overall monitoring status: `waiting` no evaluation yet, `healthy` sources and evaluation are current, `stale` an input is older than expected, `unavailable` a source could not be reached, `paused` firing is paused, `completed` its run policy is spent." }, "behavior": { "type": "object", "properties": { "text": { "type": "string", "maxLength": 320, "description": "The excerpt's text, cut to fit if the source was longer." }, "truncated": { "type": "boolean", "description": "Whether the source text was longer than `text` and had to be cut." } }, "required": [ "text", "truncated" ], "description": "A plain-language rendering of the rule's schedule, condition and firing policy — the same text `automations.search` matches words against." }, "lastCheck": { "anyOf": [ { "type": "object", "properties": { "at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check last ran." }, "condition": { "type": "string", "enum": [ "matched", "not_matched", "unknown" ], "description": "Whether the rule's condition held at this check: `matched`, `not_matched`, or `unknown` when a needed source was unavailable." }, "facts": { "maxItems": 3, "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string", "maxLength": 80, "description": "What this recorded fact measures." }, "value": { "type": "string", "maxLength": 160, "description": "The fact's value, as text." }, "unit": { "description": "The value's unit, when it has one.", "type": "string", "maxLength": 40 }, "observedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the underlying observation was made, or null when unknown." } }, "required": [ "label", "value", "observedAt" ] }, "description": "Up to three facts behind this check's verdict." }, "omittedFacts": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many additional facts this check recorded but the response left out." } }, "required": [ "at", "condition", "facts", "omittedFacts" ] }, { "type": "null" } ], "description": "The automation's most recent evaluation, or null before the first." }, "issue": { "anyOf": [ { "type": "object", "properties": { "text": { "type": "string", "maxLength": 240, "description": "The excerpt's text, cut to fit if the source was longer." }, "truncated": { "type": "boolean", "description": "Whether the source text was longer than `text` and had to be cut." } }, "required": [ "text", "truncated" ] }, { "type": "null" } ], "description": "A plain-language reason monitoring is not healthy right now — an operator hold, a paused or archived automation, an unavailable or stale source, or nothing evaluated yet — or null when nothing is wrong." }, "latestOccurrence": { "anyOf": [ { "type": "object", "properties": { "at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this occurrence was recorded." }, "delivery": { "type": "string", "enum": [ "pending", "deferred", "accepted", "rejected", "canceled", "skipped", "coalesced" ], "description": "This occurrence's delivery state: `pending` waiting to run, `deferred` an admission attempt failed and is waiting to retry, `accepted` handed to a run, `rejected` the delivery policy refused it outright, or a non-retryable admission failure (or an exhausted retry deadline) stopped it, `canceled` stopped before running, `skipped` a previous occurrence was still active, `coalesced` merged into a newer match." }, "reason": { "anyOf": [ { "type": "object", "properties": { "text": { "type": "string", "maxLength": 240, "description": "The excerpt's text, cut to fit if the source was longer." }, "truncated": { "type": "boolean", "description": "Whether the source text was longer than `text` and had to be cut." } }, "required": [ "text", "truncated" ] }, { "type": "null" } ], "description": "Why the occurrence is in this state, or null when there is none to give." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The stable public agent run id, retained across approval continuations." }, { "type": "null" } ], "description": "The occurrence's stable agent run, when one has started; else null." } }, "required": [ "at", "delivery", "reason", "runId" ] }, { "type": "null" } ], "description": "The automation's most recently recorded occurrence, or null before its first." } }, "required": [ "asOf", "automationId", "name", "state", "monitoring", "behavior", "lastCheck", "issue", "latestOccurrence" ] } } } } ``` ### 400 The request could not be read as this operation expects. - `invalid_input` — the body or query failed validation; `issues` names each field - `invalid_cursor` — the `cursor` is not one this list minted ```json { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 401 A credential is missing, invalid or expired. - `partner_key_required` — no `X-Api-Key` header was sent - `partner_key_invalid` — the `X-Api-Key` is unknown or revoked - `credential_expired` — the user token has expired; obtain a fresh one ```json { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 403 The credentials are valid but may not do this. - `subject_mismatch` — the `{userId}` in the path is not the token's user - `account_disabled` — an operator disabled the account - `origin_rejected` — a browser `Origin` other than the configured web origin ```json { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 404 The resource is missing, belongs to someone else, or its id is malformed: all three answer alike. ```json { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 412 The identity is verified but has no account yet. - `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first ```json { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 429 A limiter refused the request; honour `Retry-After`. - `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After` ```json { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 500 A fault on our side; quote `requestId` when reporting it. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ### 503 The replica is draining or a dependency did not answer; `retryable` says whether to try again. - `internal` — a fault on our side; quote `requestId` when reporting it ```json { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } ``` ## Complete OpenAPI definition The exact operation and all referenced components, including recursive schemas. ```json { "operation": { "operationId": "automations.status", "summary": "Get automation status", "tags": [ "automations" ], "description": "The bounded, model-readable state of one automation: its lifecycle, its overall monitoring status, its most recent evaluation and occurrence. Unlike `automations.get`, evidence here is fixed-size and reviewed for a conversation, never the raw stored value.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "userId", "required": true, "description": "The user in the path; must equal the token's own account." }, { "schema": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "in": "path", "name": "automationId", "required": true, "description": "The automation's id." } ], "security": [ { "apiKey": [], "userToken": [] } ], "responses": { "200": { "description": "The automation's current state and observations.", "content": { "application/json": { "schema": { "type": "object", "properties": { "asOf": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "The database snapshot time this status was read as of." }, "automationId": { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The automation's id." }, "name": { "type": "string", "maxLength": 120, "description": "The automation's name." }, "state": { "type": "string", "enum": [ "enabled", "paused", "archived" ], "description": "The automation's lifecycle: `enabled` and firing, `paused` and not firing, or `archived` for good." }, "monitoring": { "type": "string", "enum": [ "waiting", "healthy", "stale", "unavailable", "paused", "completed" ], "description": "The automation's overall monitoring status: `waiting` no evaluation yet, `healthy` sources and evaluation are current, `stale` an input is older than expected, `unavailable` a source could not be reached, `paused` firing is paused, `completed` its run policy is spent." }, "behavior": { "type": "object", "properties": { "text": { "type": "string", "maxLength": 320, "description": "The excerpt's text, cut to fit if the source was longer." }, "truncated": { "type": "boolean", "description": "Whether the source text was longer than `text` and had to be cut." } }, "required": [ "text", "truncated" ], "description": "A plain-language rendering of the rule's schedule, condition and firing policy — the same text `automations.search` matches words against." }, "lastCheck": { "anyOf": [ { "type": "object", "properties": { "at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this check last ran." }, "condition": { "type": "string", "enum": [ "matched", "not_matched", "unknown" ], "description": "Whether the rule's condition held at this check: `matched`, `not_matched`, or `unknown` when a needed source was unavailable." }, "facts": { "maxItems": 3, "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string", "maxLength": 80, "description": "What this recorded fact measures." }, "value": { "type": "string", "maxLength": 160, "description": "The fact's value, as text." }, "unit": { "description": "The value's unit, when it has one.", "type": "string", "maxLength": 40 }, "observedAt": { "anyOf": [ { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$" }, { "type": "null" } ], "description": "When the underlying observation was made, or null when unknown." } }, "required": [ "label", "value", "observedAt" ] }, "description": "Up to three facts behind this check's verdict." }, "omittedFacts": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "How many additional facts this check recorded but the response left out." } }, "required": [ "at", "condition", "facts", "omittedFacts" ] }, { "type": "null" } ], "description": "The automation's most recent evaluation, or null before the first." }, "issue": { "anyOf": [ { "type": "object", "properties": { "text": { "type": "string", "maxLength": 240, "description": "The excerpt's text, cut to fit if the source was longer." }, "truncated": { "type": "boolean", "description": "Whether the source text was longer than `text` and had to be cut." } }, "required": [ "text", "truncated" ] }, { "type": "null" } ], "description": "A plain-language reason monitoring is not healthy right now — an operator hold, a paused or archived automation, an unavailable or stale source, or nothing evaluated yet — or null when nothing is wrong." }, "latestOccurrence": { "anyOf": [ { "type": "object", "properties": { "at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$", "description": "When this occurrence was recorded." }, "delivery": { "type": "string", "enum": [ "pending", "deferred", "accepted", "rejected", "canceled", "skipped", "coalesced" ], "description": "This occurrence's delivery state: `pending` waiting to run, `deferred` an admission attempt failed and is waiting to retry, `accepted` handed to a run, `rejected` the delivery policy refused it outright, or a non-retryable admission failure (or an exhausted retry deadline) stopped it, `canceled` stopped before running, `skipped` a previous occurrence was still active, `coalesced` merged into a newer match." }, "reason": { "anyOf": [ { "type": "object", "properties": { "text": { "type": "string", "maxLength": 240, "description": "The excerpt's text, cut to fit if the source was longer." }, "truncated": { "type": "boolean", "description": "Whether the source text was longer than `text` and had to be cut." } }, "required": [ "text", "truncated" ] }, { "type": "null" } ], "description": "Why the occurrence is in this state, or null when there is none to give." }, "runId": { "anyOf": [ { "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", "description": "The stable public agent run id, retained across approval continuations." }, { "type": "null" } ], "description": "The occurrence's stable agent run, when one has started; else null." } }, "required": [ "at", "delivery", "reason", "runId" ] }, { "type": "null" } ], "description": "The automation's most recently recorded occurrence, or null before its first." } }, "required": [ "asOf", "automationId", "name", "state", "monitoring", "behavior", "lastCheck", "issue", "latestOccurrence" ] } } } }, "400": { "$ref": "#/components/responses/InvalidInput" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "412": { "$ref": "#/components/responses/AccountNotProvisioned" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/Internal" }, "503": { "$ref": "#/components/responses/Unavailable" } } }, "components": { "responses": { "InvalidInput": { "description": "The request could not be read as this operation expects.\n\n- `invalid_input` — the body or query failed validation; `issues` names each field\n- `invalid_cursor` — the `cursor` is not one this list minted", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unauthorized": { "description": "A credential is missing, invalid or expired.\n\n- `partner_key_required` — no `X-Api-Key` header was sent\n- `partner_key_invalid` — the `X-Api-Key` is unknown or revoked\n- `credential_expired` — the user token has expired; obtain a fresh one", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Forbidden": { "description": "The credentials are valid but may not do this.\n\n- `subject_mismatch` — the `{userId}` in the path is not the token's user\n- `account_disabled` — an operator disabled the account\n- `origin_rejected` — a browser `Origin` other than the configured web origin", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "NotFound": { "description": "The resource is missing, belongs to someone else, or its id is malformed: all three answer alike.", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "AccountNotProvisioned": { "description": "The identity is verified but has no account yet.\n\n- `account_not_provisioned` — the identity is verified but has no account yet; call `users.ensure` first", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "TooManyRequests": { "description": "A limiter refused the request; honour `Retry-After`.\n\n- `rate_limited` — the per-key or per-user limit is spent; honour `Retry-After`", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Internal": { "description": "A fault on our side; quote `requestId` when reporting it.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } }, "Unavailable": { "description": "The replica is draining or a dependency did not answer; `retryable` says whether to try again.\n\n- `internal` — a fault on our side; quote `requestId` when reporting it", "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/ProblemDetails" } } } } }, "schemas": { "ProblemDetails": { "type": "object", "properties": { "type": { "type": "string", "description": "The kind of problem as a URN, `urn:fin:error:`; stable, compare against it" }, "title": { "type": "string", "description": "The kind's human title, for logs; never parse it" }, "status": { "type": "integer", "minimum": 400, "maximum": 599, "description": "The HTTP status, repeated in the body" }, "reason": { "description": "The machine-readable why. One of:\n\n- `run_active` (409) — a run already holds this conversation\n- `budget_exhausted` (409) — the user's spend headroom is gone, or an operator froze it\n- `approval_not_pending` (409) — the approval was already decided or has expired, or its id does not exist or belongs to a different conversation\n- `execution_capacity` (409) — no execution capacity is free right now; `retryable` says whether to try again\n- `execution_unavailable` (409) — the execution engine could not take the work\n- `stop_pending` (409) — a stop is already in progress and its cleanup is not yet confirmed\n- `automation_changed` (409) — the `revision` sent is stale; reload the automation\n- `automation_held` (409) — an operator holds the automation; it fires again when released\n- `automation_invalid` (409) — the automation's definition cannot run as written\n- `automation_completed` (409) — the automation has finished for good and cannot fire again\n- `automation_limit` (409) — the user already has as many automations as the deployment allows\n- `profile_unknown_tool` (409) — the run profile names a tool this deployment does not have\n- `deployment_paused` (409) — an operator paused a deployment control; nothing was admitted or fired\n- `run_not_active` (409) — the run named in the path is not the conversation's live run\n- `withdrawal_changed` (409) — the withdrawal cannot be prepared or confirmed as asked: the balance no longer covers it, its terms changed or expired, or it is already in progress\n- `credential_expired` (401) — the user token has expired; obtain a fresh one\n- `account_disabled` (403) — an operator disabled the account\n- `account_not_provisioned` (412) — the identity is verified but has no account yet; call `users.ensure` first\n- `provider_unavailable` (503) — an external provider the call depends on did not answer\n- `engine_unavailable` (503) — the execution engine did not answer\n- `invalid_input` (400) — the body or query failed validation; `issues` names each field\n- `internal` (500) — a fault on our side; quote `requestId` when reporting it\n- `partner_key_required` (401) — no `X-Api-Key` header was sent\n- `partner_key_invalid` (401) — the `X-Api-Key` is unknown or revoked\n- `subject_mismatch` (403) — the `{userId}` in the path is not the token's user\n- `origin_rejected` (403) — a browser `Origin` other than the configured web origin\n- `permission_required` (403) — the operator credential lacks the scope this call needs\n- `rate_limited` (429) — the per-key or per-user limit is spent; honour `Retry-After`\n- `stream_capacity` (429) — no stream socket is free on this replica or for this user; honour `Retry-After`\n- `invalid_cursor` (400) — the `cursor` is not one this list minted", "type": "string", "enum": [ "run_active", "budget_exhausted", "approval_not_pending", "execution_capacity", "execution_unavailable", "stop_pending", "automation_changed", "automation_held", "automation_invalid", "automation_completed", "automation_limit", "profile_unknown_tool", "deployment_paused", "run_not_active", "withdrawal_changed", "credential_expired", "account_disabled", "account_not_provisioned", "provider_unavailable", "engine_unavailable", "invalid_input", "internal", "partner_key_required", "partner_key_invalid", "subject_mismatch", "origin_rejected", "permission_required", "rate_limited", "stream_capacity", "invalid_cursor" ] }, "requestId": { "type": "string", "description": "The id Fin used for this request; quote it when reporting a problem" }, "retryable": { "type": "boolean", "description": "Whether repeating the same request later can succeed without changing it" }, "detail": { "description": "Only on `invalid_input`: which part of the request failed validation", "type": "string" }, "issues": { "description": "Only on `invalid_input`: one entry per failing field", "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string", "description": "The JSON pointer of the failing field; empty for the root object" }, "message": { "type": "string", "description": "Why the field failed" } }, "required": [ "path", "message" ] } } }, "required": [ "type", "title", "status", "requestId", "retryable" ], "description": "RFC 9457 problem details: what every error response carries. Never a provider's message, a query or a stack." } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-Api-Key" }, "userToken": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } } } ```