Where duplicate-charge protection actually lives
Droplinked derives a deterministic idempotency key for the outbound PSP call, anchored on the internal order id. A network blip, a deploy bounce, or an internal retry therefore re-sends the same key to the provider and gets the provider’s cached response back — the same payment intent, and no second authorisation on the buyer’s card.
The anchor is the order id, not the cart id and not the payment-intent id. A cart can be
forked into several checkout attempts; an order cannot. A new key is minted only when a
buyer explicitly re-attempts after a declined authorisation — which is the case where a
fresh intent is what you want.
Per-endpoint retry safety
Natural dedupe keys elsewhere on the platform
Several surfaces dedupe on a natural identifier rather than a supplied key. Where one exists, it is documented on the endpoint’s own page. Examples:- Wallet registration dedupes on
merchantId : network : lowercased address. - Agentic intent recording dedupes on a caller-supplied
intentId. - Brand-attestation requests dedupe on
(shopSlug, PENDING)— re-submitting returns the existing request id rather than a duplicate-conflict error.
What you should do
- Generate your own correlation id per logical operation and keep it in your logs. You will need it to reconcile a timeout, because the API will not dedupe for you.
- Never retry
POST /v2/ordersblind. On a timeout, read back the order by cart before creating another. - Retry
429and503; do not retry400,401,403,404. Back off usingRetry-After— remembering it is in milliseconds, see Rate limits. - Treat the webhook as the source of truth for “paid”. Not the intent response, not the redirect return.
Refund scope, stated precisely.
POST /v2/orders/:orderId/refund is merchant-only
(a customer token is rejected) and today it services Bonum-paid orders: the use case
verifies the order belongs to the caller’s shop, is CONFIRMED, and was paid via Bonum
before reversing it. It is not a universal cross-PSP refund route. Refunds for other
providers are handled through that provider’s own tooling — ask before you build a refund
flow against this endpoint.