Skip to content

Webhook delivery

What each webhook request carries, how it's signed, and how Soosh retries, pauses and turns off an endpoint.

Soosh sends a webhook endpoint one POST for each event it subscribes to. Choose the events in Settings > Webhooks (opens Soosh in a new tab), or with POST /v1/webhooks. Every event, and the envelope it comes in, is in Webhook events.

Part Value
Method POST
Content-Type application/json
User-Agent Soosh-Webhook/1.0
webhook-id The delivery’s ID. The same every time the delivery is sent: each retry, a resend and a replay.
webhook-timestamp When this try was sent, in Unix seconds.
webhook-signature v1, and the base64 HMAC-SHA256 of webhook-id, ., webhook-timestamp, . and the body. During a secret rotation, two signatures separated by a space.
Your own headers Up to 10, set on the endpoint.

The signing secret is whsec_ and the base64 of 32 random bytes. The HMAC key is the base64-decoded part after whsec_. Turn away requests whose timestamp is more than 5 minutes from your clock. For code, see Verify webhooks.

When a secret is rotated, the old one keeps signing for the overlap you choose: 0 to 168 hours, 24 by default.

Rule Value
Success Any 2xx status.
Time limit 10 seconds for each try. No answer in time is a failure.
Redirects Not followed. A 3xx is a failure.
Your answer’s body Soosh reads at most 4 KB of it. When the try fails, it keeps the start of the answer, up to 1,024 bytes, with your custom header values and the signatures taken out. The delivery shows it as your server’s last answer for as long as the delivery is kept: 3 days once delivered, 30 days if it fails.
At once Up to 16 requests to one endpoint, and 32 across all of a workspace’s endpoints. A request your server takes more than 5 seconds to answer counts as two of the 32, so slow answers mean fewer at once. A paused endpoint gets one at a time until one succeeds.
Duplicates An event can come more than once. Every time a delivery is sent it has the same webhook-id.

A failed try is sent again on this schedule, counted from the try before.

Try Waits after the try before
1 Sent at once
2 30 seconds
3 2 minutes
4 10 minutes
5 30 minutes
6 1 hour
7 2 hours
8 4 hours
9 8 hours
10 12 hours
11 24 hours

That’s 11 tries over about 52 hours. After the 11th failure the delivery is Failed, and you can send it again from the webhook’s Deliveries list.

When your endpoint answers 429 or 503 with a Retry-After header (seconds or an HTTP date), Soosh waits that long instead, if it’s longer than the schedule, up to 1 hour.

Status When What happens
Active Normally Events are sent as they happen.
Paused After 10 failures in a row Soosh waits, then tries again: 1 minute, then twice as long after each failed try, up to 60 minutes. Events wait meanwhile and aren’t lost.
Turned off After 24 hours of nothing but failures, and at least 20 failed tries No new events are queued for it. The members who can create and edit webhooks get an email saying Soosh stopped sending events to it. Over the API the endpoint shows status: disabled and disabled_reason: failing.

An endpoint that has no signing secret is turned off at once (disabled_reason: no_secret), with the same email: Soosh never sends an event unsigned. Rotate its secret, then turn it back on. If Soosh itself can’t open a secret or header, the endpoint stays on: each delivery waits for its next try, with “Soosh couldn’t sign this request” as its last answer.

An endpoint made with an API key is also turned off when that key is revoked (disabled_reason: key_revoked), expires without a replacement (key_expired), or loses webhooks:write or the read scope of an event the endpoint sends (key_scopes), with the same email. Rotating the key moves the endpoint to the new key. Whoever turns it back on owns it from then on. While the plan’s API keys are switched off, a key’s endpoints pause: no new events are queued for them, and deliveries already waiting keep to the retry schedule unsent, so they fail at its end if API keys aren’t back by then. They go on when API keys are switched back on.

Any success sets the endpoint back to normal, as does a new URL or new headers. While an endpoint is turned off, the deliveries already waiting for it are kept for one day from when it was turned off: turn it back on within a day and they’re still sent. After that they fail with “Not sent: the webhook was turned off for more than a day.” Turn it back on with Turn back on in the app, or PATCH /v1/webhooks/{id} with enabled: true.

Rule Value
Endpoints per workspace 3, unless your plan sets another number (at most 20)
URL https:// only. No username or password. Any port. It can’t point to an internal or private address; Soosh checks when you save and on every connection.
Custom headers At most 10. Names are 1 to 64 letters, digits or hyphens. Values are at most 1,024 characters, with no line breaks or control characters. Values are never shown; a new URL on another server (scheme, host or port) needs every value sent again, or it’s refused with 422 invalid_field on headers.<name>.
Headers you can’t set Host, Content-Length, Content-Type, Content-Encoding, Transfer-Encoding, TE, Trailer, Connection, Keep-Alive, Upgrade, Expect, User-Agent, Proxy-* and Webhook-*
Test events 10 a minute for each workspace
Resending one delivery 10 a minute for each workspace
Replaying failed deliveries The deliveries that failed in a range of at most 7 days, by when they failed. The app offers the last hour, 24 hours, 3 days or 7 days under Failed in the last. Up to 10,000 at a time, once a minute.
Delivery Kept for
Delivered 3 days
Failed 30 days