Skip to content
Hoursmith Docs
Webhooks

Retries & replay

How Hoursmith delivers webhooks — timeouts, the exponential backoff retry schedule, idempotency, replaying past deliveries, and test events.

This page covers how deliveries succeed or fail, how Hoursmith retries them, and how to make your handler safe against duplicates.

Delivery

Events are delivered as an HTTP POST with Content-Type: application/json and roughly a 10-second timeout:

  • A 2xx response means success.
  • Anything else — a non-2xx status or a timeout — means failure and triggers a retry.

Return your 2xx fast and do the real work asynchronously. If your handler does heavy processing inline and exceeds the ~10-second budget, the delivery is counted as failed even though you received it.

Retry schedule

Failed deliveries are retried with exponential backoff at these offsets, in seconds, with a little jitter:

AttemptOffset after the original
Retry 15 seconds
Retry 260 seconds
Retry 3300 seconds (5 minutes)
Retry 41,800 seconds (30 minutes)
Retry 57,200 seconds (2 hours)
Retry 621,600 seconds (6 hours)
Retry 786,400 seconds (24 hours)

That's 7 attempts spread over roughly 32 hours. After the 7th failed attempt, the delivery is marked failed and the endpoint's status flips to "failing".

A "failing" endpoint stays enabled — Hoursmith keeps sending new events to it. It's up to you to fix the receiver or disable the endpoint. See Troubleshooting and My webhook is failing.

Idempotency

All retries of one event share the same event id. Because of this — and because replays reuse the same id too — your handler should be idempotent: processing the same event twice must have the same effect as processing it once.

The simplest approach is to dedupe on the event id:

  1. When an event arrives, check whether you've already recorded its id.
  2. If you have, acknowledge with a 2xx and stop.
  3. If you haven't, record the id, process the event, then acknowledge.
async function handleEvent(event) {
  // Dedupe: store ids and skip ones you've already handled.
  const isNew = await markProcessed(event.id); // false if already seen
  if (!isNew) return;

  switch (event.type) {
    case 'invoice.paid':
      await onInvoicePaid(event.data.invoice, event.data.payment);
      break;
    // ...other event types
  }
}

Replaying a delivery

An Owner or Admin can replay a past delivery from Settings → Webhooks (hoursmith.app/settings/webhooks). A replay reuses the same event id with a fresh timestamp and signature.

Because the id is unchanged, an idempotent handler treats a replay safely — useful for re-delivering events your endpoint missed while it was down.

Test events

When you add an endpoint, an Owner or Admin can send a synthetic test event to confirm it's wired up. Test events:

  • carry livemode: false, and
  • include data.test: true.

Use the livemode flag (and data.test) to keep test deliveries out of your production data paths.

Housekeeping

Delivery history is pruned automatically:

  • Succeeded deliveries are kept for about 30 days.
  • Failed deliveries are kept for about 90 days.
Was this page helpful?

On this page