B2B platform for digital goods

Gift-Card API — Code Retrieval and Automated Delivery 2026

The full path of a gift-card code — from order placement to buyer delivery, without double-issuance and with evidence you can defend.

Gift-Card API — Code Retrieval and Automated Delivery

A gift card differs from every other digital product in one respect: the code is irreversible. Once that string reaches a buyer you have no way of knowing whether it has been redeemed, and every dispute is settled by your log rather than by common sense. Below is the full path of a code from order to delivery, focused on the places where money is actually lost.

Five stages you must keep separate

Most code-issuance bugs happen because a developer treats all of this as one operation. It is five operations with five different failure modes:

Stage What happens Who owns the state
1. Order You submit a purchase request Your DB + supplier
2. Issuance Supplier reserves and issues a code Supplier
3. Retrieval You pull the code out of the response Your DB
4. Storage Code sits encrypted on your side Your DB
5. Delivery Buyer sees the code Your frontend / email

Every transition should be its own timestamped row in your database. If you have one status column covering the whole journey, the first failure leaves you unable to answer the only question that matters: was a code issued at all?

Stage 1. Placing the order

An order is created with a product ID and quantity:

curl -X POST "https://public-api.foxreload.com/api/orders" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "itemId": "product_01krgfgww8eth9xvvysd6y7r4j",
        "quantity": 1
      }
    ],
    "isMock": false
  }'

The response is an order object with status active, plus id, price, createdAt, paymentExpiresAt and an items[] array.

Three rules at this stage:

  • Record the intent in your database before calling the supplier, not after. A row saying "we are about to order this for customer X" must exist before the HTTP request leaves — otherwise a process crash between send and response leaves no trace at all.
  • Persist the supplier's order_id the moment it arrives. It is the only key by which you will ever find that order again.
  • Never mix mock and production orders in one table without an explicit flag. FoxReload's order object carries isMock — copy it into your own schema.

Stage 2. Issuance on the supplier's side

After creation the order moves activepaid (balance debited) → processing (supplier issuing) → completed.

The processing phase belongs to someone else's system and can last from seconds to noticeably longer depending on card type. Your only job here is to do nothing destructive while the state is unknown. No "it probably failed, let's order another one."

Stage 3. Retrieving the code

The code is retrieved by polling the order:

curl "https://public-api.foxreload.com/api/orders/{order_id}" \
  -H "X-API-Key: YOUR_API_KEY"

When status == "completed", each items[] entry carries:

  • product — the product object with id, name, userGuide, attributes
  • externalData[] — the array of issued codes or PINs
  • error — a per-item error, if there is one

The userGuide field is not decorative. It is the supplier's activation instruction and it should reach the buyer alongside the code — half of all "the code doesn't work" tickets actually mean the buyer is redeeming it in the wrong region or the wrong part of their account.

About webhooks — check your own supplier

Some suppliers can notify you when an order completes, often with an HMAC signature on the callback. Verify whether your specific supplier implements this. FoxReload does not support webhooks — results are retrieved by polling only.

Even where webhooks exist, keep polling as the safety net: delivery is never guaranteed and your handler may be down at exactly the wrong moment. The webhook is an accelerator; polling is the source of truth.

Partial fulfilment

On a multi-line order, items complete independently. One line can return a code while another fails with a populated items[].error.

The correct response:

  1. Whatever was genuinely issued gets stored and delivered. That money is already spent and the code exists.
  2. For the missing part, either re-order as a separate operation or refund the customer.
  3. Never mark the whole order failed once some codes have gone out. That path ends in refunding goods the customer already received.

Stage 4. Duplicate-issuance protection

This is the most expensive mistake in the category, and it arises in two different places.

Duplicates at the order level

You send an order-creation request, get a timeout, retry — and create two orders. You have now bought two codes, delivered one, and the second either sits dead on your books or, worse, goes out to the next buyer by accident.

Some APIs accept an Idempotency-Key header that solves this on the supplier's side. Verify whether your supplier actually implements it — many do not. FoxReload does not support an Idempotency-Key header.

So the protection lives with you:

  1. Persist a unique operation key in your database before the call.
  2. On a timeout, query the supplier's order list first, filtered by status, and check whether the order exists.
  3. Only retry once you have confirmed it does not.
curl "https://public-api.foxreload.com/api/orders/?statuses=active,processing&limit=20" \
  -H "X-API-Key: YOUR_API_KEY"

Duplicates at the delivery level

The second source is a race inside your own system. A customer clicks "get my code" twice, two concurrent requests both read the order row as "code ready, not delivered", and both proceed to deliver.

Fix it with a transaction and a row lock: delivery marks the order as delivered and commits before the code leaves your system. If the code goes out by email, the send is enqueued inside that same transaction rather than performed synchronously in the middle of it.

Retries

The general rule: only retry what is safe to repeat.

  • 429 and 5xx — retry with exponential backoff and jitter.
  • 4xx other than 429 — never retry, the answer will not change.
  • A timeout on order creation — not a retry, a state check first.

More detail in the retry and backoff patterns article.

Stage 5. Storage — encryption and access

A gift-card code is a bearer instrument. Whoever reads it can spend it.

  • Encrypt the code value at the application layer with a key from your secret manager. Disk encryption is not enough: a database dump, a stolen backup or an SQL injection all read the disk already decrypted.
  • Restrict decryption to one service. Your analytics replica, your support admin panel and your debugging scripts should not hold the decryption right.
  • Never write codes to logs. Not to standard logs, not to debug output, not to APM traces, not into the body of a support ticket. Mask the value on the way out of your data-access layer rather than at every individual print site.
  • Store a hash alongside the code. It lets you prove "this is the code we issued" without exposing the value a second time.
  • Set a retention period. Once delivered and past the dispute window, the encrypted value can be deleted while the hash and metadata remain.

Stage 6. Delivery and the audit trail

Delivery is itself an operation that can fail. Email bounces, tabs close, buyers mistype their address.

A working pattern:

  • The code is displayed once, on a protected order page available only to the authenticated buyer.
  • Re-access happens through the account area, with every view written to a log.
  • Any one-time view link is short-lived and single-use.
  • The first display is recorded with a timestamp — that is the fact you will cite in a dispute.

The audit trail

The minimum set of events to record per code:

Event What you capture
Order created Internal ID, product, buyer, timestamp
Supplier ID received The supplier's order_id
Code retrieved Code hash, line item, timestamp
Code shown to buyer Timestamp, IP, session identifier
Dispute opened Link to order and ticket
Dispute resolved Refund, denial, replacement

This log — not a support thread — is what answers "was the code delivered, and when". How that evidence plays out in practice is covered in avoiding chargebacks on digital goods.

Keep in mind the risks no amount of code can fix: issuer-side revocation, regional redemption restrictions, and cards voided when the issuer suspects fraud. Those scenarios are broken down in handling code revocation and region locks.

Where to source gift cards wholesale

The pipeline above is worth building once, against a catalogue wide enough to cover your whole range. FoxReload is a wholesale digital-goods supplier with 900+ SKUs — gift cards, game keys, top-ups, eSIM and software licences — all behind one REST API with automated delivery and multi-region SKUs. One order model and one response shape across every category, instead of a separate integration per issuer.

Read next

Frequently asked questions

How do I retrieve a gift-card code through an API?
You place an order with a product ID and quantity, the supplier issues the code, and you retrieve it by polling the order's status. On FoxReload the code arrives in items[].externalData once the order reaches completed. FoxReload has no webhooks, so polling is the standard and only way to learn the outcome. Retrieve the code immediately and persist it encrypted on your side.
How do I avoid issuing the same code twice on a retry?
One rule: always re-read state on the supplier's side before re-placing an order. A timeout does not mean the order was not created. FoxReload does not support an Idempotency-Key header, so duplicate protection is your responsibility — persist a unique operation key before the call, query the supplier's order list before retrying, and only retry once you have confirmed nothing exists. Separately, close the race inside your own delivery path with a row lock in a transaction.
How should gift-card codes be stored?
Encrypt them at the application layer with a key from your secret manager, not just at the disk level — a dumped database, a stolen backup or an SQL injection all read the disk already decrypted. Restrict decryption to the delivery service alone, not the whole team. Codes must never reach ordinary logs, analytics pipelines or support emails. Store a hash of the code alongside it so you can prove which code you issued without exposing the value again.
What do I do when an order is only partially fulfilled?
Handle line items independently. On a multi-line order one item can reach completed while another fails, with items[].error carrying the per-item reason. Deliver whatever was actually issued to the buyer, then either re-order the missing part as a separate operation or refund it. Marking the whole order failed and refunding everything is wrong if some codes have already reached the customer.
See FoxReload wholesale prices

Related articles