Skip to content
Elara One docs

Retries and delivery

How CRM webhooks are delivered at least once, retried with backoff, switched off when failing, and sent again from the delivery log.

CRM webhooks are queued the moment a change is saved and delivered in the background. A failed delivery is retried for several hours, and every attempt is written to a delivery log you can read in the admin. This page explains what your receiver can expect.

At least once

Delivery is at least once. You may receive the same event more than once, for example when your 2xx answer was lost on the way back. Every retry of an event carries the same X-ElaraOne-Delivery header (the body's id), so use it to skip repeats:

Skip events you have already handled
const deliveryId = req.headers.get('X-ElaraOne-Delivery')!

// A unique constraint on delivery_id makes this safe under concurrency.
const firstTime = await db.webhookDeliveries.insertIfAbsent({ delivery_id: deliveryId })
if (!firstTime) return Response.json({ received: true }) // already done: still answer 2xx

Events about one record usually arrive in order, but a retry can overtake a newer event. Compare created_at, or read the record's current state through the merchant CRM API.

What counts as success

Your answerResult
Any 2xxDelivered.
410 GoneDelivery stops at once for this event. No more retries.
Any other status, including 3xxThe attempt failed and will be retried. Redirects are never followed.
No answer within 10 seconds, or a connection errorThe attempt failed and will be retried.

Answer 2xx as soon as you have verified and stored the event, and do the real work afterwards. Do not answer 410 for a bad signature: use a 4xx such as 400, so a configuration mistake on your side is retried once fixed.

The retry schedule

A failed delivery is retried with exponential backoff and a little jitter: about 30 seconds, then 1 minute, 2 minutes, 4 minutes and so on, each wait capped at 6 hours. If your endpoint answers with a longer Retry-After, that wins.

After 8 failed attempts the delivery gives up and is marked dead in the log. Each attempt is signed afresh, so the t in X-ElaraOne-Signature is always current.

Automatic switch-off

Each endpoint keeps a count of failed attempts in a row, reset by any success. When an endpoint has failed 20 times in a row and has not succeeded for 24 hours (or never has), it is switched off and its waiting deliveries give up.

The staff member who added the endpoint (or else the store's admins) gets a notification in the admin and an email. Neither names any contact. Once your receiver is fixed:

  1. Switch the endpoint back on in Settings → CRM → Webhooks. This clears its failure count.
  2. Send the missed deliveries again from the delivery log.

While an endpoint is switched off, changes send nothing to it.

The delivery log

Settings → CRM → Webhooks → Delivery log lists every delivery, newest first, with its event, record, state, attempts, last answer, error and the exact payload sent. You can filter by endpoint, state and event.

StateMeaning
pendingQueued, not yet attempted.
deliveringAn attempt is in progress.
deliveredYour endpoint answered 2xx.
failedThe last attempt failed and a retry is due.
deadIt gave up: 8 failed attempts, a 410, or the endpoint was switched off.

Send again puts a dead delivery back in the queue with its attempt count reset. It keeps the same event id, so your deduplication still works.

Delivered entries are kept for 30 days and dead ones for 90 days. Entries hold ids and field names only.

Test events

Send a test on an endpoint sends one signed webhook.test event straight away and writes it to the log. It does not count towards the endpoint's failure streak, so you can test a receiver that is not ready yet without risking a switch-off.

webhook.test
{
  "id": "01jb3m2c5d7f9h1k3m5p7r9t1v",
  "type": "webhook.test",
  "created_at": "2026-10-24T10:02:00+00:00",
  "store": "hearth-and-oak",
  "api_version": "2026-10-01",
  "data": {
    "object": "endpoint",
    "id": 4,
    "message": "A test from Settings → CRM → Webhooks."
  }
}

Handle webhook.test by verifying the signature and answering 2xx. There is nothing else to do with it.

Staging stores

A staging store sends webhooks too, signed with its own endpoint secrets and marked with X-ElaraOne-Environment: staging. A receiver that serves your live store can ignore events with that header.