TL;DR — Two real transactions with different
request_ids both succeeded — that’s a genuine duplicate, not a replay. Void the extra one while its settlement batch is still open, or refund it once the batch closes.When this happens
- Your server retried a purchase or authorize call after a timeout or network error, but generated a new
request_idfor the retry instead of reusing the one from the first attempt. RadiumOne has no way to know the two calls were the same attempt, so both go through as separate, legitimate transactions. - A double-click, a page refresh, or a resubmitted form reaches your server twice, and your server builds a fresh payment call — with its own
request_id— each time, instead of recognizing it’s the same attempt. - You’re integrating through Hosted checkout or Elements and the duplicate started upstream of the Payments API call itself — see Prevent duplicate sessions and double payments or Prevent double submission.
This is different from an idempotency conflict. Idempotency is the mechanism that stops a repeated
request_id/operation_id from charging twice; a duplicate payment is the problem it exists to prevent. It shows up here specifically because the same attempt got two different keys, so nothing on RadiumOne’s side ever saw them as the same request. A 409 idempotency-body-mismatch or 409 tx:duplicate-operation is actually the safe outcome — it means a reused key was caught before a second charge went through. See that page for what those responses mean and how to resolve them.What you see
- Two transactions with different
ids and differentrequest_ids, bothAUTHORIZEDorCAPTURED, for the same order. - Two separate webhook deliveries —
payment.capturedorauthorization.createdtwice, each with a different eventidand a differentdata.transaction.id. That’s not the same as one event delivered twice: a repeated eventidfor the same transaction is a redelivery, not a duplicate charge — see Recover from missed, duplicate or out-of-order webhooks.
What to do
1
Confirm it's a real duplicate, not a replay or a redelivery
Check both transaction Two distinct
ids (API reference):ids, each with its own request_id, both successful — that’s a genuine duplicate. The same id reported twice is a webhook redelivery, not a double charge; see Recover from missed, duplicate or out-of-order webhooks instead.2
While the batch is still open, void the extra transaction
3
Once the batch has closed, refund the extra transaction instead
(API reference)See Resolve void and refund conflicts if you’re not sure which side of the batch boundary you’re on.
4
Fix the retry path so it doesn't happen again
Persist the
request_id before you send the first call, and reuse that exact value on every retry of the same attempt — see Prevent it below.Prevent it
- Generate one
request_idper payment attempt, save it to your database before you send the request, and reuse the exact same value for every retry of that attempt — never mint a new one just because the first call was slow or failed. - Give capture and void each their own
operation_id. They’re different operations on the same transaction, so reusing one operation’s key for the other returns409 tx:duplicate-operationinstead of doing what you meant — it doesn’t create a second charge, but it does mean your retry logic needs its own key per operation type. - If a call times out or fails without a response, resend it with the same key — a replay returns the original result instead of charging again, so it’s always safe (see Handle timeouts and unknown outcomes). Start a new attempt with a new key only once you know the first one didn’t succeed — from the confirming webhook (recommended) or status inquiry.
- Disable your pay action for the whole attempt, not just the network call, so a double-click can’t reach your server twice with two different keys.
Test it
See Test your integration: idempotent replay and body mismatch to confirm your retry path reuses the key correctly before you go live.Related
Handle failures
Back to every Payments API failure scenario.
Handle replays and idempotency conflicts
What happens when a key is reused correctly — or incorrectly.
Prevent duplicate payments
The cross-product guide, checklist, and anti-patterns.
Resolve void and refund conflicts
Void vs refund, and the batch-boundary rule.