Retries and rate limits
How failed deliveries are tried again, how to limit how fast we send to your app, and how to send failed deliveries again.
When your app does not take a delivery, we try again, with a wait that grows each time, until the destination’s last attempt. A rate limit keeps us from sending faster than your app can take.
What counts as a failure
An attempt succeeds when your app answers with a 2xx status. Anything else fails it:
lastErrorClass | Means |
|---|---|
http | Your app answered with a status that is not 2xx. lastStatusCode holds it |
redirect | Your app answered with a redirect, which is not followed |
timeout | Your app did not answer within the destination’s timeoutSeconds |
dns | The address’s name could not be found |
tls | The secure connection could not be made, such as with an expired certificate |
connect | The connection was refused or dropped |
blocked | The address is on a private network, so it is never called |
request | The request could not be sent to that address |
lost | The attempt was cut short on our side. It is tried again straight away |
transformation | The connection’s transformation failed. It is not tried again |
cancelled | The delivery was cancelled before it was sent |
When we try again
After a failed attempt, the next one waits 30 seconds, then twice as long each time, up to an hour:
| After attempt | Next attempt |
|---|---|
| 1 | 30 seconds later |
| 2 | 1 minute later |
| 3 | 2 minutes later |
| 4 | 4 minutes later |
| 5 | 8 minutes later |
| 6 | 16 minutes later |
| 7 | 32 minutes later |
| 8 and later | 1 hour later |
When your app answers 429 or 503 with a Retry-After header, we wait that long instead when it is longer, up to an hour.
A destination makes 6 attempts by default. Set maxAttempts, from 1 to 20, to change it. After the last attempt, the delivery is failed.
Limit how fast we send
A rate limit caps how many attempts a destination gets in a second, a minute, or an hour:
{ "rateLimit": { "count": 50, "period": "minute" } }Deliveries over the limit wait their turn; nothing is dropped. At most 5 attempts are in flight to one destination at once, so one slow destination never holds up the others. Leave rateLimit out, or set it to null, for no limit.
Send failed deliveries again
Sending a delivery again makes a new delivery of the same event to the same destination, sent straight away with a full set of attempts. It keeps the same webhook-id, so your app can tell it has seen the event.
- One delivery:
POST /v1/projects/{project}/deliveries/{delivery}/resend - Up to 100 you choose:
POST /v1/projects/{project}/deliveries/resendwith their IDs indeliveryIds - Every failed delivery, of one destination or the whole project:
POST /v1/projects/{project}/deliveries/resend-failed. It skips a delivery that was already sent again, and sends up to 1,000 at a time.
curl -X POST "$HOOKS_URL/deliveries/resend-failed" \
-H "Authorization: Bearer $HOOKS_API_KEY" \
-H "Content-Type: application/json" \
-d "{ \"destinationId\": \"$DESTINATION_ID\" }"The answer says how many were sent again, as resent. In the console, select deliveries and choose Send again.
Cancel a waiting delivery
A delivery that is pending or retrying can be cancelled, so it is never sent:
curl -X POST "$HOOKS_URL/deliveries/$DELIVERY_ID/cancel" \
-H "Authorization: Bearer $HOOKS_API_KEY"A delivery that is being sent, or has finished, gets 409 with the code delivery_not_waiting.
Last updated