MobileWalletPartner Gateway Docs

Idempotency

Safely retrying a request that may have already succeeded.

Every transaction-creating request (MOMO_DEPOSIT, MOMO_WITHDRAWAL, CRYPTO_BUY, CRYPTO_SELL) takes a partnerOrderId — a string you choose, unique per partner. This is your idempotency key.

Why this matters

A network timeout doesn't tell you whether your request reached the gateway before the connection dropped. If you blindly retry, you risk creating a second real transaction for what the customer experiences as one payment. Idempotency keys solve this: retry with the same partnerOrderId as many times as you need, and the gateway guarantees it only ever creates the transaction once.

How it behaves

Submit the same partnerOrderId twice (whether that's a genuine retry or a bug on your end):

{
  "transactionId": "0192b7a4-6f1e-7c3a-9d2b-4e5f6a7b8c9d",
  "partnerOrderId": "deposit-2026-10-10-001",
  "status": "GW-00-PENDING",
  "duplicate": true
}

duplicate: true tells you this is the original transaction's current state, not a new one. Everything else in the response — transactionId, status — reflects the real, already-existing transaction. You can safely treat a duplicate: true response exactly like a successful create: it's giving you a status check for free.

How it's enforced

This isn't just an application-level check — it's backed by a real unique database constraint on (PartnerId, PartnerOrderId). Two concurrent requests with the same key can both pass an initial "does this exist yet?" check (a genuine race), but only one of them can win the insert; the other's write fails on the constraint, and the gateway re-reads the winner's row and returns it with duplicate: true instead of surfacing a database error. This is deliberately not a soft, best-effort check — the correctness holds under real concurrent traffic, not just sequential retries.

Choosing a partnerOrderId

  • It only needs to be unique within your own partner account — other partners' values live in a completely separate namespace.
  • Use something your own system already generates for the underlying payment/order, so a retry is naturally the same key without extra bookkeeping on your side.
  • It's a string — UUIDs, your own internal order numbers, and composite keys ("order-42-attempt-1") all work, as long as you don't reuse one for two genuinely different transactions.

On this page