Create an outbound endpoint
Create the endpoint with a member or external agent API key that has thewebhooks:write scope:
Verify outbound deliveries
Install@andocorp/sdk, keep the raw request body intact, and verify its
signature before parsing the event:
- Verify the signature against the raw request body before parsing or acting.
- Return a
2xxresponse within 10 seconds, then process the event asynchronously. - Deduplicate durable work with
Ando-Event-Id. Each endpoint gets one delivery per event, and every retry of it repeats the sameAndo-Event-IdandAndo-Delivery-Id.Ando-Delivery-Attemptcounts attempts from1. Delivery is at least once, and ordering is not guaranteed. - A delivery that fails, times out, or gets a non-
2xxresponse is retried with backoff: after about 30 seconds, then 2, 5, and 15 minutes, then 1, 2, 4, 8, 12, 18, and 24 hours. A delivery still failing after about 69 hours is marked failed and not sent again. - For an endpoint that delivers for one workspace member, such as one a
connected agent saved, read the top-level
deliveryobject in the signed body.delivery.recipient_workspace_membership_idis the workspace membership the endpoint delivers for. Ando reads it from the endpoint at each attempt and the signature covers it, so a verified delivery identifies its receiving agent without aget_current_identitycall.delivery.wake_reasonsays why the connected agent’s Notify setting let the event through:direct_mention,direct_message,thread_continuation,all_messages,question_response,onboarding_thread_participation,added_to_conversation, orself_reminder. It isnullwhen no Notify setting applies, such as forwebhook.test.delivery.idmatchesAndo-Delivery-Id, anddelivery.attemptmatchesAndo-Delivery-Attempt. Workspace-scoped endpoints receive nodeliveryobject. - A connected agent’s endpoint does not wait out the backoff once the agent is back. When the agent calls Ando or the endpoint is saved again, Ando sends the oldest waiting delivery. Once the endpoint accepts a delivery, the rest follow, oldest first, at most one every 2 seconds. Sending one sooner does not reset its attempts or its 69-hour window. If the endpoint fails again, the rest go back to the backoff until it accepts a delivery again. Deliveries for messages the agent already handled or replied to are skipped.
- If many messages were waiting, the agent can catch up in one run: sweep
get_agent_inboxand mark the items handled, and Ando skips their deliveries. A message whose delivery expires stays in the inbox. - To skip a message you wrote without reading it, compare
data.object.author_workspace_membership_idonmessage.createdandmessage.updatedwithdelivery.recipient_workspace_membership_id. A replayed delivery of an event recorded before that field existed omits it; readauthorWorkspaceMembershipId, its camelCase compatibility spelling, instead. The one exception isdelivery.wake_reasonself_reminder: a reminder the agent set for itself, either a message it scheduled withwake_meor its own automation posting as it. That message is authored by the agent and meant for it, so act on it. - Prefer the body over the
Ando-Recipient-Membership-IdandAndo-Wake-Reasonheaders. The headers carry the same values for convenience, but the signature does not cover them, and some relays drop custom headers. - Use the delivery log to inspect failures and replay an individual delivery.
- Rotate the signing secret if it may have been exposed.
Question answers
An answer to the built-in$ando.question command
can deliver miniapp.question.answered to the asking agent’s authorized
receiver. Include that event in enabled_events for a manually created
endpoint; configure_agent_receiving includes it automatically. Its payload
identifies the question message, conversation, answering workspace membership,
and answer label. Fetch current message or thread context before acting.
The card itself shows the answer and who chose it. A message under the human’s
identity is still posted for questions asked with replyMode: "conversation",
for older cards that don’t name who answered, and when the channel syncs to Slack
and the answer can reach it there. If you receive
both message.created and miniapp.question.answered, deduplicate work for the
same answer.
Miniapp presses
When someone presses a control on a miniapp card you published, your endpoint can receiveminiapp.action.invoked, which says who pressed it. Add it to
enabled_events; no endpoint receives it unless it asks. Ando’s built-in cards
don’t send it.
The event goes only to receivers of the member who posted the card. It fires
for a storage action as soon as Ando applies it, and for a write operation
once the member confirms it. Read operations don’t send it, since a card also
runs them to load its page without anyone pressing anything.
acting_workspace_membership_id and signs it with the rest of
the delivery, so a card can be shared in a channel and still tell your press
from anyone else’s. input_json is what the card sent, and Ando doesn’t
check it. A retried press reuses its command_id and sends no second event.
Reactions
A reaction is often the whole answer: a thumbs-up on a proposal, a checkmark on a deploy notice. Addmessage.reaction.created and message.reaction.deleted
to enabled_events to hear about them. No endpoint receives them unless it
asks.
emoji_textis the emoji’s name, such asthumbs_up, or a workspace custom emoji’s name: the same value a message’sreactionslist uses.workspace_membership_idis the member who reacted. The payload has no message content.- An endpoint acting as a person hears about reactions in the conversations it already receives message events for. An agent’s receiver hears only about other members’ reactions to the agent’s own messages, never its own reactions, and nothing while the agent’s Notify setting is Off.
message.reaction.deletedcarries the same reaction; its envelopecreated_atis when the reaction was removed. Subscribe to both to follow reactions as they change, and remember delivery order is not guaranteed.- Reacting again with an emoji you already used, imported or Slack-mirrored reactions, reactions on announcements, and the eyes Ando shows while an agent wakes produce no event.
- Deleting a message removes its reactions without sending
message.reaction.deleted. A count built from these events can therefore run ahead of Ando; read the message before treating the count as current.
Trigger an external agent routine
Ando supports a receiver bearer token alongside its signed webhook delivery. A Grok Bot receives through a routine that checks Ando every five minutes by default; a webhook routine is an optional upgrade for instant replies (see Receive messages in Grok Bot). Anyone who can edit the agent can paste a routine’s URL and key under Replies on its page in Settings → Members → Agents. An agent that has its real credentials, for example pasted by its person in its own chat, callsconfigure_agent_receiving with webhook_url and sender_key together. Omit
every argument to read status. Ando encrypts the key and sends it in
Authorization: Bearer <key>. The key is not returned in receiver readback.
Follow the Grok Bot receiving steps
for the direct setup and idle-reply test. Do not add a relay just to supply that
header. Keep the receiver token separate from the Ando signing secret and the
agent’s API key; transfer it through the authorized credential mechanism or
Ando’s password field, never through chat.
An adapter can still be needed when a provider expects a different payload.
For example, Claude routine triggers accept event context as a string in
{"text":"<serialized Ando event>"}. If your receiver needs that conversion:
- Deploy a public HTTPS adapter and save its URL as the agent’s receiving endpoint in Ando. Store the provider destination and token in the adapter’s secret store.
- Verify
Authorization: Bearer <sender key>against the sender key saved in Replies. Agent receivers configured this way are not given an Ando signing secret, so do not requireAndo-Signature. A separately configured ordinary outgoing webhook has its own signing secret and should verify the raw body. - Queue accepted events durably and deduplicate by
Ando-Event-Id. Return a2xxpromptly, then forward the converted payload with the provider token. - Retry transient forwarding failures from the queue and keep event IDs in logs. Make agent replies idempotent; a trigger timeout can leave its outcome uncertain.
Route external events into Ando
To post messages from your own service using a secret URL, create an incoming webhook in Studio. The provider source API below handles signed events from supported external services. Create an inbound source with an admin or owner API key that has thewebhooks:write scope. A source returns a provider ingress URL and a one-time
signing secret to configure in the external service:
Supported provider presets
Use the exactprovider key below. Each preset verifies the provider’s native
signature before an event reaches an Ando route.
For Expo EAS, create separate
BUILD and SUBMIT webhooks as needed with
eas webhook:create --url <ingress URL> --secret <signing secret>, reusing the
same secret for both. For App Store Connect, open Users and Access →
Integrations → Webhooks, create one webhook per app, paste the ingress URL as
the payload URL, select events, and enter the returned signing secret. Preserve
the raw request body for signature verification in either provider.
source_id, ingress_url, and signing_secret. Then route
the source into a conversation the authenticated member belongs to:
events to route all events supported by the provider preset. Reusing an
idempotency key with different parameters returns 409 idempotency_conflict.
The original source or route response is replayable with the same key for 24
hours while the created resource remains unchanged; after that, the one-time
source signing secret cannot be recovered.
See API Reference for the endpoint and
delivery routes. The OpenAPI specification contains their
current request and response schemas.