POSTs a message, the bridge runs an agent turn as the route’s
execution key, and the answer comes back by a signed HTTPS callback (or inline on a
bounded wait).
See client conversations for the model.
Two identities: who-may-send vs what-the-agent-may-do
An API route separates two authorities, and you provision both:- The invoking key — the API key your system authenticates with when it
POSTs a message. The access-control gate authorizes it for the route’s send door; it answers who may send. - The execution key — the identity the turn runs as. Its live grants are the turn’s entire authority; it answers what the agent may do.
1
Mint the invoking key
A scoped key your system will send with. Scope it to reach the route and no
more.
2
Mint the execution key
A least-privilege key the agent runs as (see owned keys).
Create the API route
Anapi route carries an HTTPS callback_url — the sink the answer is POSTed to.
The URL must be absolute HTTPS; an http:// or relative URL is rejected at
create.
callback_secret — shown once, here, and never
readable again. It signs every callback for this route. Capture it now and store it
where your callback receiver can read it.
Send a message
POST to the send door with your invoking key. external_user_id is your handle
for the end user — it becomes the conversation’s thread key, so the agent remembers
that user’s earlier turns.
202 with the id to correlate the callback against:
404 unknown route, 429 the
address rate cap, 503 the thread queue is full, 501 no conversations backend
configured, 400 a malformed body, 401 an unauthorized caller.
Sync variant: wait_seconds
Add wait_seconds to wait inline for a fast turn. A turn that finishes within the
window answers 200 with the answer embedded and its callback suppressed (so it
never double-fires); a turn still running when the wait elapses falls back to 202
and the answer arrives by callback as usual. The window is clamped to the
deployment’s sync_wait_max_seconds cap.
Receive the callback
The bridgePOSTs the answer to your callback_url as JSON. The body is the
answer payload; correlate it by message_id:
status is error and answer
is generic client-safe text — never an internal detail:
Verify the X-Tai-Signature
Every callback carries an X-Tai-Signature header:
sha256=<hex HMAC-SHA256(callback_secret, raw_request_body)>. Recompute it over
the raw bytes and compare in constant time — reject any mismatch. This is what
proves the callback came from your deployment and was not tampered with.
failed (listed on tai conversations failed) rather than
being lost.
See also
- Client conversations — the delivery lifecycle.
- Conversation bridge reference — payload models, the read doors, and every setting.
- Set up access control — scoping the invoking key.

