Deliveries and retries
A delivery is one event sent to one webhook. This page describes what a delivery request looks like, when it counts as successful, how failed deliveries are retried and what happens when an endpoint keeps failing.
The request
POST /beepclock/webhooks HTTP/1.1
Host: integration.example.com
Content-Type: application/json; charset=utf-8
User-Agent: BeepClock-Webhooks/1.0
X-BeepClock-Webhook-Id: c5d8a2e7-4b19-4f63-8a0d-3e7b9c1f6a52
X-BeepClock-Event: timeEntry.created
X-BeepClock-Delivery: 8f2c6a1d-4e7b-5c93-a0d5-1b8e3f6c9a24
X-BeepClock-Attempt: 1
X-BeepClock-Signature: t=1791788292,v1=5d1f…c2a8
{"id":"8f2c6a1d-4e7b-5c93-a0d5-1b8e3f6c9a24","event":"timeEntry.created",…}
The body is the event envelope as compact JSON.
Headers
| Header | Description |
|---|---|
X-BeepClock-Webhook-Id | Identifier of the webhook the delivery belongs to. |
X-BeepClock-Event | Event type, for example timeEntry.created. See the event reference. |
X-BeepClock-Delivery | Identifier of the delivery, the idempotency key. Equal to the id field of the envelope. |
X-BeepClock-Attempt | Attempt number, starting at 1. |
X-BeepClock-Signature | HMAC signature. See Verify signatures. |
Custom headers configured for the webhook, for example Authorization, are added to every request, including test events. Their names cannot start with X-BeepClock- and cannot replace transport headers such as Content-Type, Host or User-Agent. Their values may contain only printable ASCII characters.
Transport
| Property | Rule |
|---|---|
| Method | POST |
| URL | https only, absolute, at most 2048 characters, without user:password@. |
| Target host | Must be publicly reachable. Loopback, private, link-local, carrier-grade NAT, documentation, multicast and reserved addresses, in IPv4 and IPv6, are blocked. The check runs when the URL is saved and again on every connection, after DNS resolution. |
| Timeout | 10 seconds. |
| Redirects | Not followed. A 3xx response counts as a failure. |
| Success | Any 2xx status code. Everything else, including timeouts and connection or TLS errors, is a failure. |
| Response body | Ignored. |
Retry schedule
When an attempt fails, BeepClock retries the delivery on a fixed schedule:
| Attempt | Delay after the previous attempt |
|---|---|
| 1 | immediately |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 8 hours |
| 7 | 24 hours |
A delivery has at most 7 automatic attempts, spread over about 35 hours. After the last failed attempt the delivery is marked as failed. You can still resend it once the endpoint is fixed.
Automatic pausing
BeepClock pauses a webhook automatically when:
- the endpoint responds with
410 Gone. The delivery is not retried and the webhook is paused immediately. Return410only when the endpoint is permanently retired. - 20 deliveries in a row have failed. A delivery counts once, after all its attempts have failed, and any successful delivery resets the counter.
When a webhook is paused automatically, BeepClock emails the users of the account with the reason and a link to the webhook. The webhook list shows the reason in its status.
While a webhook is paused, automatically or with Pause sending:
- deliveries that are waiting for a retry are not sent. They are marked as failed with the error
Webhook is disabled or deleted.; - events that occur while the webhook is paused are not delivered later. After Resume sending, only new events are sent.
Delivery log
The webhook page shows every delivery from the last 30 days, newest first, and can be filtered by status. Select a delivery to see:
- each attempt with its HTTP status code, duration and error;
- the exact payload that was sent;
- when the next attempt is scheduled, if the delivery is still pending.
Resending a delivery
Resend delivery in the delivery details sends the delivery again with the same delivery ID and the same body. The attempt number continues from the previous attempts: a delivery that succeeded on attempt 1 is resent as attempt 2.
Resending is available when the webhook is active and the delivery is no longer pending. A delivery that has been pending for more than an hour after its scheduled attempt, for example after an interrupted send, can also be resent.
If a resent attempt fails, the automatic retry schedule continues from that attempt number; from attempt 7 on there are no further automatic retries. A resent delivery counts towards automatic pausing like any other delivery.
Test events
Send test event immediately sends a signed webhook.test event with the current secret and custom headers, and shows the response. A test event:
- has a new random delivery ID each time and
X-BeepClock-Attempt: 1; - is sent once and never retried;
- is not added to the delivery log and does not count towards automatic pausing;
- can be sent while the webhook is paused, to check the endpoint before resuming.
Idempotency and ordering
Delivery is at least once: the same event can reach your endpoint more than once, for example when your 2xx response is lost on the way back.
- The delivery ID (
X-BeepClock-Delivery, equal to the envelopeid) is deterministic for each pair of webhook and source event. Automatic retries and manual resends carry the same ID and the same body; onlyX-BeepClock-Attempt,tand the signature change. - Store the IDs you have processed and treat a repeated delivery as harmless.
- The order of arrival is not guaranteed. A retry can deliver an older event after a newer one. Use
occurredAtto order events about the same object.