v2.4 CURRENT PROTOCOLIdempotency

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

AttemptAfter the previous attemptSince the first attempt
1When the event occurs0
21 minute1 min
35 minutes6 min
430 minutes36 min
52 hours2 h 36 min
66 hours8 h 36 min
712 hours20 h 36 min
824 hours44 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.

Answer first, process later

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.

Next Steps & Guides

Was this guide helpful?

Your feedback helps us improve our documentation.