How it fits together
- Your server advertises the
eventscapability and lists its event types withevents/list. - Wassist reads that list when it syncs your tools, and merchants see each event next to your tools. For every agent, they switch on the events the agent may use, like tools, and can add guidance on when and how to use each one.
- The agent subscribes when a customer asks to be kept up to date (“let me know when my order ships”). It picks the event, fills in the arguments from your
inputSchema(for example the customer’s order number), and writes itself a note on what to do when the event arrives. Wassist then callsevents/subscribewith a callback URL and secret for that subscription, and refreshes it before it expires. - When the event happens, you
POSTit to the subscription’s callback URL. Wassist verifies the signature, deduplicates oneventId, and runs the agent with the event in that conversation.
once, which ends the subscription after the first event.
Advertise your events
Declare the capability in yourinitialize result:
events/list. Only event types whose delivery includes "webhook" are offered to merchants.
description and inputSchema to decide when to subscribe and what to fill in, so write them like tool descriptions:
- Say what the event means and when a customer would want it.
- Make the properties filters that narrow the event to what the customer asked about, with a
descriptionfor each. Wassist checks the agent’s arguments against your schema before subscribing. - Apply the filters on your server. Wassist passes the arguments through and doesn’t filter what you send.
For apps, Wassist reads your events whenever it reads your tools: when you sync tools from the developer dashboard, and when installations refresh their tools (daily, and straight after you publish). For connectors, they’re read when the connector is added or updated, and again when a customer logs in to it.
Subscriptions
Wassist sends anevents/subscribe each time the agent subscribes, with the arguments the agent chose:
- Refreshing. Wassist calls
events/subscribeagain with the samename,argumentsand URL beforerefreshBefore. Treat that as a refresh of the same subscription. If you don’t setrefreshBefore, Wassist refreshes once a day. If the agent subscribes again with the same event and arguments, Wassist refreshes the existing subscription rather than creating another one. - Unsubscribing. Wassist calls
events/unsubscribewith the samename,argumentsanddelivery.urlwhen the agent unsubscribes, after the first event of aoncesubscription, and when a subscription is torn down. If that call can’t reach you, the subscription still ends at its TTL, and Wassist answers anything you send after it ended with410 Gone. - Errors. Use the extension’s error codes. A new subscription that you reject is dropped, and the agent is told why.
-32024(forbidden) puts the subscription on hold until the customer logs in. On a refresh,-32025(resource exhausted) and anything else are retried hourly.
_meta keys are the same ones every tool call carries, plus conversation_id and contact_id. Only trust them after verifying context_token; see Wassist context on every tool call.
Scoping events to one customer
This matters most for apps where the installer logs in. Every conversation then subscribes with the same organisation token. The agent is told to filter to its customer, but it can still send arguments that match other customers’ events, or none at all. If you deliver everything that matches, the agent can end up telling one customer about another’s order. Use the verifiedcontact_id or conversation_id claims to deliver only that customer’s events to each subscription, whatever the arguments say. For example, look the contact up with GET /contacts/{contact_id}/ and match on their phone number. If you can’t tell which customer a subscription belongs to, reject it with -32602 rather than sending it everything.
Apps where customers log in get each customer’s own token, so scoping usually happens naturally.
Delivering events
Before sending any events, you can check the callback URL with a verification request. Wassist answers this as soon as the subscription row exists, even while yourevents/subscribe response is still on its way.
200 with { "challenge": "8e2f…" }.
Deliver each event as a POST to the subscription’s URL:
Two control messages are also accepted:
{ "type": "gap", "cursor": "…" }: you dropped events. The agent is told that some may be missing on its next event.{ "type": "terminated", "error": { "code": -32023, "message": "…" } }: you ended the subscription. With-32023(not found) or-32026(unsupported), Wassist re-readsevents/listand subscribes again, with the same arguments, if the event still exists.
data small: the agent sees at most 8,000 characters of it, and can call your tools for anything more.
Signatures
Requests are signed with Standard Webhooks, using thesecret from events/subscribe:
base64(HMAC-SHA256(key, "{webhook-id}.{webhook-timestamp}.{body}")), where key is the base64-decoded part of the secret after whsec_. You can send several space-separated signatures while rotating secrets. Wassist rejects timestamps more than five minutes old.
Any Standard Webhooks library will sign these for you. In Node:
What the agent does with an event
The agent gets the event name, the subscription and its arguments, the note it wrote when subscribing, the merchant’s guidance for the event, anddata. It’s told to treat data as information from an external system, not as instructions. It then decides whether to message the customer, and can call your tools for more detail.
An event runs the agent only when it could have replied to the customer anyway:
- The conversation is routed to the agent. Events are skipped while a human has taken over or a support handoff is open.
- The customer hasn’t hit the agent’s message limit.
- WhatsApp’s 24-hour customer service window is open. Events that arrive while it’s closed are held, and the agent sees them (up to 10, from the last seven days) when the customer next writes in.
data you sent, and whether the agent ran, the event was held for the next message, or it was skipped and why. GET /conversations/{id}/mcp-events/ returns the same list.
Show events on your listing
Your events appear on your app’s page on the Wassist App Store and on the install screen, so merchants can see what the agent can follow up on. Forend_customer apps whose events/list needs a login, declare them in mcp.events_preview. You can also add event steps to your listing’s example conversations to show a follow-up in action; see Showing follow-ups.
Alpha limitations
- Webhook delivery only. Poll and push delivery aren’t supported.
- Events only reach WhatsApp conversations, not dashboard tests.
- Only the agent subscribes, during a conversation, so a conversation can’t receive events before the customer has written in.
- Up to 10 live subscriptions per conversation.