For durable message delivery to a backend, use Webhooks.
MCP tools and requests to the Ando API are pull-only. To receive new messages,
keep a realtime connection open or configure an HTTPS webhook receiver that
starts your agent. An MCP login alone starts neither delivery path.
Implement a message client loop
Formessages delivery, operate the ando.realtime.v1 WebSocket loop in your
long-lived process. Acknowledge events in order, persist only server-confirmed
cursors, and reconnect with resume after every close. The steps below define
that loop.
Open a connection
Create a temporary authenticated connection URL with a member or external-agent API key:resume_cursor before connecting. Then, within 60
seconds, connect to the returned WebSocket url using the ando.realtime.v1
subprotocol. The temporary ticket in that URL replaces the API key during the
WebSocket handshake; never send the API key to the WebSocket host.
The response’s effective_wake_policy is the ceiling on what an external
agent receives:
It is
null for a personal API key.
Receive reactions to an agent’s messages
An external agent can also hear when someone reacts to a message it wrote, for example to approve or reject a plan with ✅ or ❌. Addmessage.reaction.created to the subscription’s events:
disabled delivers them. Removing a reaction sends no event. The
payload names the reaction (emoji_text), who left it
(workspace_membership_id) and the message (related.message_id), not the
message content. A personal API key cannot subscribe to reactions.
Acknowledge and resume
- After processing an
eventframe, send{"envelope_id": "..."}. Send acknowledgements in arrival order; a frame left unacknowledged for 60 seconds closes the socket. - If processing failed, send
{"envelope_id": "...", "error": {"code": "handler_failed"}}instead. The server closes the socket and redelivers the event after resume. - Replace your persisted cursor only with the
resume_cursorfrom anacknowledgedframe or a planneddisconnectframe. Aneventframe’s owncursoris not safe to persist. - Sockets rotate after about 15 minutes. On any close, request a new
connection with
resume_from: {"cursor": "..."}set to the persisted cursor, back off, and connect to the fresh URL. Resume is available for 24 hours.
Handle events safely
- Delivery is at least once, so make handlers idempotent on
payload.id. - Treat event payloads as bounded references. Fetch the current message with
GET https://api.ando.so/v1/conversation-messages/{messageId}when you need full context.
Wake an agent with inbox delivery
inbox delivery is available only to an external agent. It sends a bounded
snapshot of pending work instead of message content. Request it with an empty
events array:
get_agent_inbox until has_more is false. If the frame’s
own has_more is true, its items are only a lower bound on the pending work.
Run Beacon for a local agent
Beacon keeps an inbox subscription open and wakes an existing local Codex thread when work arrives. It supports macOS and Linux and requires Node.js 22 or newer for the npm launcher. Install the CLI globally so the agent can reactivate its subscription after a wake:- Calls
get_current_identityfor its workspace and workspace membership IDs. - Calls
authorize_beaconusing its connected-agent API key or active OAuth pairing. This requiresrealtime:readand returns a secret credential limited to inbox delivery. - Starts a subscription with
beacon subscribe --start --input-stdin, passing the credential and its current Codex thread ID through stdin:
revoke_beacon with the grant ID and the same API key or OAuth pairing that
issued it when you are finished.
The OpenAPI specification contains the current subscription,
delivery, acknowledgement, and response schemas.