Start an Amy run and return one JSON result when it completes.
Optional endUserRef must be a stable PSEUDONYMOUS handle for the caller's end user (their own user id / opaque token) — never PII (no email, name, phone, government id). It is retained in the append-only audit log and webhook delivery records, and it is the handle an erasure of that end user's data is made against. Erasure is an organisation-admin operation: an API key cannot call it. Validated for shape only (≤200 chars, printable ASCII), and erasure takes every ref this rule admits, so a ref that can be stored can always be erased. Omitting it leaves the run UNATTRIBUTED, which disables the run-history tools for it (search_runs / get_run_messages / get_run_iterations refuse rather than read a bucket shared with every other unattributed run in the tenant). Pass a stable ref per end user, or one constant ref if a single shared history is genuinely wanted.
A conversationId belongs to the client and endUserRef that first use it: starting a run under one that already holds a run of another client, another endUserRef, a Console member, or a run started before clients were recorded is a 404 — before any run is created or spend recorded. Mint a fresh id per chat.
Runs are stateless by default: the agent sees only the new message. Set threadConversationHistory: true to have it replayed the earlier turns of this conversation — the user and assistant text of this client's earlier runs with the same conversationId and endUserRef, oldest first. Another client's runs, another endUserRef's and a Console member's are never replayed. At most the newest 20 runs and 48,000 characters are replayed; older runs are dropped whole, never cut mid-turn. A retry of such a run, and its resume after an approval, a question or its background tasks, replay the same way. threadConversationHistory: true requires both conversationId and endUserRef, and only a JSON boolean is accepted — anything else is a 400 before any run is created.
Optional Idempotency-Key header (a UUID is recommended; any string works; a blank header is no key): send a start again with the same key and no second run starts and nothing is billed twice. Keys belong to the calling API client — any of its keys, rotations included — and the three start routes share them; another client's identical key is unrelated. A repeat of the same request (same route, agent and body; mcpAuth is left out, so a freshly minted MCP token is still a repeat) answers 202 with the first run's runId, current status and toolWarnings on /runs/submit, and 409code: run_already_started with runId, runStatus and a Location on the stream and /runs/await — no stream opens; read the run with GET /v1/runs/{runId}. The same key with another request is 409code: idempotency_key_reused; a first request still starting is 409code: idempotency_in_progress with Retry-After: 1. A start refused before its run exists (400, 403, 404, 422, 503) frees its key for the corrected request. With a key, /runs/await lets its run finish when the caller hangs up instead of cancelling it. A key lasts 24 hours from first use; nothing is stored but the request's hash and the run id.