Skip to main content
Webhook delivery is at-least-once and unordered. Both are deliberate trade-offs for reliability, not bugs — design your handler around them rather than assuming a single, ordered, exactly-once stream.

Delivery guarantees

  • At-least-once: the same event can arrive more than once — after a retry, after a network blip that hides a successful 2xx from RadiumOne, or (rarely) more than once for other reasons. Dedupe on the top-level id before you act on an event a second time. See Build your handler.
  • Unordered: deliveries for different events, and even for the same transaction, aren’t guaranteed to arrive in the order they occurred. See Ordering below for how to recover the right sequence when it matters.

Retry schedule

If your endpoint doesn’t return a 2xx (timeout, non-2xx status, connection error), RadiumOne retries on this backoff schedule by default. The schedule is a platform-configurable default, not a contractual guarantee — build your reconciliation job (see below) to not depend on an exact attempt count or timing. Eight attempts total, spanning ≈29.6 hours from the first attempt to the last, by default — not the ~72 hours you may see quoted elsewhere; the schedule above is the authoritative source. After the final attempt fails, that delivery is exhausted and isn’t retried further.
A 2xx you return after a slow but eventually-successful attempt still counts as delivered — it’s specifically the timeout/non-2xx cases above that trigger the next scheduled retry.

Timeouts

Respond within RadiumOne’s delivery timeout. If your handler needs to do slow work (database writes, calling other services), enqueue it and respond 2xx immediately — see Build your handler. A handler that’s merely slow, not broken, looks identical to a failing one from RadiumOne’s side and consumes the same retry budget.

Ordering

Deliveries for the same transaction aren’t guaranteed to arrive in the order the underlying state changes happened — a retry of an earlier event can arrive after a later one. Don’t assume “the last webhook I received” is the current state.
  • Use each event’s created_at as the ordering token if you need to reconcile the sequence of events for one transaction.
  • If your logic depends on the current state rather than the event history (for example, deciding whether to fulfil an order), call GET /v1/transactions/{id}/status (API reference) to re-fetch the authoritative current state instead of trusting whichever event arrived most recently.

Endpoint suspension

RadiumOne stops sending to an endpoint that’s provably broken, not merely slow or temporarily down:
  • What trips it: sustained failures whose cause can’t fix itself — an unresolvable hostname, a bad TLS certificate, an SSRF-blocked address, or a 410 Gone response. This must recur across multiple separate deliveries (at least 5 by default) over a sustained window (24 hours by default) before your endpoint is suspended.
  • What never counts: timeouts, 5xx responses, and ordinary 4xx responses. These are treated as transient — a bad deploy afternoon doesn’t get you suspended.
  • What suspension means: a suspended endpoint receives nothing. Events aren’t queued for it and aren’t replayed once it’s re-activated — they’re dropped for that endpoint entirely while it’s suspended.
  • Recovery is manual, not automatic. There’s no health probe and no auto-resume. Contact support to re-activate a suspended endpoint once you’ve fixed the underlying issue. Re-activating an endpoint that’s still broken simply suspends it again once the same failure pattern recurs.
Because a suspended endpoint silently receives nothing, monitor your own delivery health (for example, alert if you haven’t received any webhook in an unexpectedly long window) rather than relying on RadiumOne to tell you your endpoint stopped receiving events.

Reconciliation job

Webhooks are the primary signal, not the only one you should rely on. Because delivery can be delayed, retried, or (if your endpoint was suspended) missed entirely, run a periodic reconciliation job as a backstop:
  1. For transaction ids you already stored (from create responses or prior webhooks) that you haven’t heard a terminal outcome for, poll GET /v1/transactions/{id}/status. RadiumOne has no list-by-order_reference endpoint, so this only works against ids you’ve already recorded. For settlement batches, use Retrieve a settlement batch.
  2. Compare their current state against your own records.
  3. Treat a mismatch — a transaction you expected to be CAPTURED that your records still show as pending, or a settlement batch your records never saw — as a signal to investigate, not just to log.
See Recover from missed, duplicate or out-of-order webhooks for the full walkthrough. This is the same authenticated-read pattern used to recover from a timed-out request — see Recovery after timeouts.

Test your integration

See Test your integration for simulated retry, duplicate-delivery, and out-of-order scenarios.

Go-live notes

  • Make your handler idempotent on event id before you go live — a retried or duplicate delivery must never double-process an order.
  • Set up a reconciliation job (see above) rather than treating webhooks as infallible.
  • Review the full go-live checklist.

Next steps

Webhooks overview

Endpoint setup and the handler steps these guarantees assume.

Webhook event types

Every event and its payload shape.
Last modified on September 15, 2026