Registering endpoints
secret (whsec_…) exactly once — store it in your secret manager. Up to 5 endpoints per project; GET /v3/s2s/webhooks lists them (secrets masked), DELETE /v3/s2s/webhooks/{id} removes one. URLs must be public https:// endpoints.
An empty events array means all events except typing — agent.typing.* is strictly opt-in and only delivered to endpoints that list it explicitly.
Event catalog
Data retention: bot-only conversations are permanently deleted ~33 days after creation; archived conversations follow the project’s retention window.
conversation.deleted (and a 404 on any fetch) means “remove from your mirror” — there are no tombstones.Envelope
sequenceis monotonic per conversation — order and deduplicate by(conversation id, sequence). Events can arrive out of order on the wire.sequenceisnullonagent.typing.*andcontact.updated(no conversation context).- Treat
dataas the authoritative current state of what it carries.
Verifying signatures
Every delivery carries:v1 = HMAC-SHA256(secret, t + "." + <raw request body>). Verify against the raw body bytes, allow a 5-minute tolerance on t, compare constant-time, and reject anything that fails.
Delivery semantics & recovery
- Respond
2xxwithin 5 seconds; anything else (or a timeout) is retried 3 times over ~20 seconds, then dropped. Endpoints that fail persistently are circuit-broken for a few minutes. - Delivery is therefore at-least-once within a short window — not guaranteed. Your durable safety net is per-conversation catch-up: whenever your app opens a contact’s support screen (or your consumer suspects a gap), re-pull
GET /v3/s2s/contacts/{userId}/conversationsandGET /v3/s2s/conversations/{id}/messages?after=<last id you have>. - Signed file URLs inside payloads expire (~30 days) and rotate — never dedupe or persist by URL.