Polling Webhooks
A polling webhook is a webhook you read instead of one we deliver. You subscribe to the same event types as a regular webhook and AgentMail queues the matching events for you. Your agent fetches them whenever it runs and commits the ones it has processed. Nothing in your setup needs to be reachable from the internet.
When to use it
Use a polling webhook when your agent cannot accept inbound HTTP or stay connected: it runs on a schedule, in a sandbox, on a laptop, or inside a serverless function. If it can stay connected, WebSockets deliver the same events with lower latency.
How it works
- Create a polling webhook with a
client_id, theevent_typesyou want, and optionally the inboxes or pods to cover. The response carries a one-timetoken. - Hand the token to the Svix SDK’s
AutoConfigConsumer.receivereturns queued events;commitmarks them processed so they are not returned again. - On restart, create again with the same
client_id. You get the same subscription with a new token, and the previous token stops working immediately. - Delete the polling webhook when the agent retires. Its token stops working and its slot is freed.
Step 1: Create a polling webhook
Install the AgentMail and Svix SDKs:
Create the subscription. client_id is required: it identifies this consumer, so running the same code again returns the existing subscription instead of creating a second one.
token comes back from create only. get and list never include it, and there is no endpoint to read it again. To get a new one, create again with the same client_id: the previous token is invalidated at once, so one client_id should back exactly one running worker. Store the token like an API key.
Omit inbox_ids and pod_ids to receive events for the whole organization. The event types you can subscribe to follow the same permission rules as webhooks: message.received.spam, message.received.blocked and message.received.unauthenticated require the matching label permission on the API key. See the webhooks overview.
Step 2: Read events
The AutoConfigConsumer takes the token and a sink configuration. Pass an empty configuration: AgentMail already created the subscription, and calling subscribe() on the consumer would replace its event types and inboxes. Only call receive and commit.
"worker-1"is a consumer id. Each consumer id keeps its own position in the queue, so two consumer ids on one token each see every event. Most agents use one.commitacknowledges that event and everything before it. Events you have not committed are returned again on the nextreceive, so a crash betweenreceiveandcommitloses nothing.page.doneis true when the queue is drained. Sleep before polling again; a few seconds is plenty.payloadmatches the webhook body for that event type, documented in Events. Formessage.receivedthe message is underpayload["message"].
Scoping to a pod or inbox
The same three routes as webhooks, with the same rules (see Scoping a webhook to a pod or inbox):
A pod- or inbox-scoped API key uses its own route. Listing is per route: client.webhooks.polling.list() returns what was created through the organization route, and the pod and inbox routes list their own.
Limits
- Each organization, pod and inbox holds at most 10 polling webhooks. Creating an eleventh answers
403with a message naming the narrower routes; a repeat create with an existingclient_iddoes not count against the limit. - A token can only ever read the event types the API key could read when it was created. If the key later loses one of those permissions, a repeat create with that
client_idis refused: delete the polling webhook and create it again with the current key. - Up to 10 pods and inboxes per polling webhook, as for webhooks. A pod already covers every inbox in it.
