OpenPoly logo
Wallet Adapter

Idempotency

Idempotency key formats and replay expectations for wallet operations.

Idempotency

Every wallet mutation must be idempotent by idempotency_key.

idempotency_key is required on every mutation request.

Why

  • network timeout may occur after wallet write
  • OpenPoly and operator wallet are not one atomic transaction
  • retries and manual reconciliation must not double-charge the user

Expectations

  • same key + same user, direction, amount, currency, reason, and material metadata -> same effective result
  • same key + conflicting params -> reject or return a conflict without creating a second mutation
  • persist both request fingerprint and effective result for the full reconciliation lifetime; permanent ledger retention is safest
  • key scope is per operator wallet system; a new HTTP request ID does not create a new financial operation

Example keys

  • mini_app_order:1:debit
  • mini_app_order:1:debit_reversal
  • mini_app_order:2:credit
  • mini_app_redemption_item:42:credit
  • mini_app_polyflight_purchase:{purchaseRequestId}:debit
  • mini_app_polyflight_purchase:{purchaseRequestId}:debit_reversal
  • mini_app_polyflight_ticket:{ticketId}:win
  • mini_app_polyflight_ticket:{ticketId}:refund
  • mini_app_polyflight_ticket:{ticketId}:loss

Recovery rule

Raw REST v1 mutation responses must return succeeded, failed, or pending. The Mini App processor may record an internal unknown result after a timeout, network failure, or ambiguous HTTP response; that internal state does not allow unknown in a direct mutation response.

Direct mutation outcomeMini App processor behavior
Timeout, network error, or invalid HTTP 2xx responsePreserve internal unknown state and send the primary operation to manual review.
HTTP 408, 429, or 5xx without a valid REST v1 status bodyPreserve internal unknown state because the mutation may already have landed.
Other HTTP 4xx without a valid status bodyTreat as a failed mutation; do not assume a wallet write occurred.
Any HTTP response with a valid succeeded, failed, or pending bodyHonor the body. pending remains ambiguous and requires reconciliation.

When the operation is tied to a known operator user, direct mutation responses should include external_user_id so reconciliation tools can display the affected wallet without decoding the idempotency key.

Polyflight loss credits have an exactly zero amount but still require durable request fingerprints and acknowledgement records. Duplicate delivery of the same :loss key returns the original effective result without another result record or any balance change. Ambiguity still requires authenticated wallet evidence and the existing manual-resolution process, not a new key. remote_reference is optional.

Preserve already-planned/dispatched requests exactly, including older win metadata without result. Do not add new metadata to their fingerprints or regenerate historical losing-ticket deliveries. Newly planned win credits use result: "won"; newly settled losses use operation: "loss" and result: "lost".

Copyright © 2026