Skip to content

Delivery, retries, and idempotency

Behavior What to expect
Success Any HTTP status below 400. Respond as soon as you have stored the payload.
Timeout 5 seconds. Do your processing after responding, not before.
Retries Up to 10 retries after the first attempt. The delay starts at 30 seconds and doubles each time — 30s, 1m, 2m, 4m, and so on up to roughly 4 hours — about 8½ hours of attempts in total.
Giving up After the last retry the delivery is marked failed and stays in the portal, where you can retry it by hand.
Duplicates Delivery is at-least-once, so the same event can arrive more than once. Deduplicate on the payload’s id.
Ordering Not guaranteed. Order by date_time, not by arrival.

Use the stable payload id to make business processing idempotent. Store it with the result of processing and skip work you have already completed.

Do not use delivery.id for business deduplication. It identifies one generated delivery and changes when Levno rebuilds the payload.

  1. Validate the event envelope.
  2. Start a transaction in your own system.
  3. Insert the stable event id into a table with a unique constraint.
  4. Apply the business change only when the insert succeeds.
  5. Commit, then return a success status below 400.

This pattern makes duplicate deliveries harmless regardless of retry timing.

  • Return success quickly and do the real work asynchronously — a slow endpoint turns into retries and duplicates.
  • Verify the signature on every request — see verifying webhooks.
  • Make your handler idempotent, keyed on the payload id.
  • Ignore fields you do not recognise instead of rejecting the payload.
  • Keep your endpoint’s TLS certificate valid — an expired certificate looks like a failed delivery.