Subscribe to webhook events
Webhook subscriptions let Atender notify your server when something happens — a new message arrived, a conversation was resolved, an SLA was breached. You manage subscriptions via the v1 API.
Before you start
- A tenant API key with
webhooks:writescope. Generate one in Settings → API Keys. - A public HTTPS endpoint on your server that can receive POST requests and respond quickly (under 10 seconds).
- A way to store the webhook secret Atender returns when you create the subscription — you’ll need it to verify signatures.
- Webhooks must be enabled for your tenant. If they’re not, the API returns 403. Talk to your account team if you need them turned on.
Create a subscription
POST https://YOUR-ATENDER-HOST/v1/webhooks
Headers:
Authorization: Bearer sa_live_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
Body:
{
"name": "production-listener",
"url": "https://your-server.example.com/atender-webhooks",
"events": [
"message.received",
"message.sent",
"conversation.resolved"
]
}
Response (201 Created):
{
"id": "...",
"name": "production-listener",
"url": "https://your-server.example.com/atender-webhooks",
"events": ["message.received", "message.sent", "conversation.resolved"],
"secret": "whsec_...",
"isActive": true,
...
}
The secret is returned only at creation time. Store it immediately — you cannot retrieve it later. If you lose it, rotate using POST /v1/webhooks/:id/rotate-secret.
What your server receives
When a subscribed event fires, Atender POSTs your URL with a payload like:
{
"event": "message.received",
"tenantId": "...",
"timestamp": "2026-05-11T09:00:00Z",
"data": { ... }
}
The exact data shape depends on the event — see Webhook events reference.
Verify signatures
Every webhook delivery is signed using the subscription secret. Verify the signature before trusting the payload — otherwise anyone who knows your endpoint can forge events.
The signature is sent as an HTTP header (typically X-Atender-Signature or similar — check the actual headers on your first delivery). Compute the HMAC-SHA256 of the raw request body using your subscription’s secret as the key. If it matches the header, the request is genuine.
Respond quickly
Your endpoint must respond within ~10 seconds. The expected response is 2xx. If your server is slow or returns an error, Atender retries with exponential backoff. After enough consecutive failures (configurable per subscription via maxRetries and retryDelaySeconds), the subscription is disabled — you can see why under disableReason when you GET the subscription.
Best practice: acknowledge the delivery immediately with a 200 OK, then process the event in a background job. Don’t do heavy work in the webhook handler itself.
List, update, delete
GET—/v1/webhooks— List your tenant’s subscriptions. Includes delivery status and consecutive-failure count.GET—/v1/webhooks/:id— Get full details for one subscription, including custom headers and retry config.PATCH—/v1/webhooks/:id— Update name, URL, event list, active/paused state, retry config.DELETE—/v1/webhooks/:id— Permanently remove a subscription.POST—/v1/webhooks/:id/rotate-secret— Generate a new signing secret. Returns the new secret in the response — old secret immediately stops working.
All require webhooks:write except GET which requires webhooks:read.
Pause vs disable
A paused subscription receives no deliveries but remains in your tenant — useful for temporary maintenance or debugging.
A disabled subscription was paused automatically by Atender after too many consecutive failures. Check disableReason to understand why, fix your endpoint, then PATCH isActive: true to re-enable.
Limits
- Each tenant has a
maxWebhookslimit (set per tenant). Trying to create more returns 429. - Webhooks must be enabled at the tenant level. If they’re not, every
/v1/webhookscall returns 403.
Troubleshooting
-
Symptom: POST /v1/webhooks returns 403. Fix: Either your API key lacks
webhooks:writescope, or your tenant doesn’t have webhooks enabled. Check the response body’s error message to tell which. -
Symptom: Subscription created but no events arrive. Fix: Confirm the subscription is
isActive: trueand notisPaused. ChecklastDeliveryAtandlastDeliveryStatusto see whether Atender tried and failed, or whether nothing triggered yet. -
Symptom: The subscription got disabled. Fix: GET it and read
disableReason. Usually it’s “too many consecutive failures” — fix your endpoint, then PATCHisActive: trueto re-enable. -
Symptom: Signature verification fails. Fix: Make sure you’re computing HMAC-SHA256 over the raw request body, not the parsed JSON. Many web frameworks parse the body before you see it — most have a way to retain the raw bytes.