Retry Policy
A delivery counts as successful if your endpoint returns 2xx within 10 seconds. A timeout, a connection error, a 3xx redirect, a 4xx or a 5xx response are all failures, and the event goes back onto the queue. Incapon tries the event 8 times in total with exponential backoff; a few seconds of random jitter are added to each attempt, so that after an outage the events do not all hit you at the same moment.
Attempt Schedule
| Attempt | After the previous attempt | Since the first attempt |
|---|---|---|
| 1 | When the event occurs | 0 |
| 2 | 1 minute | 1 min |
| 3 | 5 minutes | 6 min |
| 4 | 30 minutes | 36 min |
| 5 | 2 hours | 2 h 36 min |
| 6 | 6 hours | 8 h 36 min |
| 7 | 12 hours | 20 h 36 min |
| 8 | 24 hours | 44 h 36 min |
If the eighth attempt fails as well, the event is marked failed and is not sent again on its own. The response code, duration and first 1 KB of the response body of every attempt are kept in the dashboard's delivery log for 30 days.
Idempotency: Do Not Process the Same Event Twice
Because of retries, network trouble and manual replays, the same event can reach you more than once. Each event's X-Incapon-Event-Id header (and the id field in the body) is the same across all attempts. Write that id to a table with a unique constraint before processing; if the row already exists, skip the event and still return 200.
app.post('/webhooks/incapon', express.raw({ type: 'application/json' }), async (req, res) => {
// Signature verification happens here (see Signature Verification)
const eventId = req.headers['x-incapon-event-id'];
// Unique constraint: the same id cannot be inserted twice
const inserted = await db.query(
'INSERT INTO processed_events (id) VALUES ($1) ON CONFLICT DO NOTHING',
[eventId],
);
if (inserted.rowCount === 0) {
return res.status(200).send('already processed');
}
await queue.add('incapon-event', JSON.parse(req.body.toString()));
res.status(200).send('ok');
});Replay from the Dashboard
On the Settings → Webhooks → Deliveries screen you can filter failed events and resend them one by one or in bulk. A replayed event is sent with the same id, but with a current X-Incapon-Timestamp and a new signature, so it does not trip your timestamp tolerance. Events from the last 30 days can be replayed. The same action is available in the API as POST /v2.4/webhooks/events/{id}/replay.
Automatic Disabling
If an endpoint receives no successful delivery for about 3 days (72 hours), it is disabled automatically and the team admins are emailed. No new events are sent to a disabled endpoint, but events keep being recorded. Once you fix the problem and re-enable the endpoint from the dashboard, you can replay the events in between in bulk from the deliveries screen.
Most failures come from processing that runs past the 10-second limit. Verify the event, put it on a queue, return 200 at once and do the real work in the background.