PlatformIdempotency

Idempotency

How to retry requests safely: idempotencyKey on transfers and other duplicate-protection mechanisms.

Network failures make retries unavoidable. V3 Custody protects you from accidental duplicates. First and foremost, transfers accept an idempotencyKey, so retrying a request never duplicates a payment.

idempotencyKey on transfers

POST /api/v1/vaults/{code}/transfers accepts an idempotencyKey. Retrying the request with the same key returns the transfer that was already created and doesn't repeat the broadcast: the response contains the existing operation (replay).

# the first request creates the transfer; a retry with the same key returns the same one
curl -X POST "[BASE_URL]/api/v1/vaults/acme-otc/transfers" \
  -H "Authorization: Bearer $V3_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fromAddressId": "cmr3f41z20001psp7phmyapw3",
    "toAddress": "TQ2m...p4rX",
    "token": "usdt",
    "amount": "1350.00",
    "idempotencyKey": "payout-2026-03-14-001"
  }'

The key is stored together with the created transfer: a second request with the same key short-circuits to the existing operation instead of creating and broadcasting it again.

Recommendations

  • Always pass an idempotencyKey on transfers.
  • Make the key a stable identifier of the business operation (an invoice or payout ID), not a random value generated on each retry. Otherwise, a retry creates a new payment.
  • One key = one payment; a new payment needs a new key.

Other safe-retry mechanisms

idempotencyKey applies to transfers. Other write operations have their own protection against duplicates and race conditions:

OperationMechanismBehavior on retry or race
transfer (POST /transfers)idempotencyKeysame key → same operation (replay)
address grant (POST /shares)idempotent per subjectupdates or reactivates, never duplicates
final approval of a requestoptimistic locktarget changed → REJECTED (stale)
address creationpathIndex selection retryconcurrent requests can't claim the same path

For details on the approval request optimistic lock, see Approvals.

Common mistakes

SymptomCause
a retry duplicated the paymentthe key was random on each retry instead of stable
"same key, different payment"the key was reused for a new operation; one key = one payment
a retry without a key was duplicatedidempotencyKey wasn't passed
request REJECTED (stale)the target changed after the request was created; this is the optimistic lock, not a network failure
grant "created twice"it wasn't: POST /shares is idempotent, so the second call updated the same grant

Next steps