B2B platform for digital goods

How to Connect a Digital-Goods Supplier API — Integration Walkthrough 2026

From your first API key to production — how to build a reliable integration layer between a supplier API and your storefront.

How to Connect a Digital-Goods Supplier API

Connecting a supplier API is not "write one curl and ship it." It is a service layer that has to survive somebody else's outages, must never hand the same code to two customers, and must not take your storefront down when the supplier deploys. Below is the working sequence, from first credential to go-live checklist.

Architecture — three layers, not two

The only shape that holds up in production is:

Supplier API → your middleware → storefront.

The middleware is your own service (or a set of background jobs plus internal endpoints) that holds the supplier key, keeps a local copy of the catalogue, places orders, polls their status, and hands the storefront nothing but normalised data.

Three things you must not do:

  • Call the supplier API directly from a browser or mobile app. That means the key is on the client. A supplier key is a server-side secret, without exception.
  • Hit the supplier API on every catalogue page render. You will hit rate limits and make your own availability hostage to someone else's.
  • Put fulfilment logic in a storefront controller. Fulfilment must be an idempotent operation in a dedicated service, or a customer's double-click becomes a double order.

Step 1. Credentials and environments

The first thing you get is a key. Establish three facts about it before writing code:

  1. Which auth header. It might be X-API-Key, it might be Authorization: Bearer, it might be a request signature. FoxReload uses X-API-Key: YOUR_API_KEY — no Bearer tokens, no OAuth, no client_id/client_secret pair.
  2. Whether the key can be retrieved again. With most suppliers, no. FoxReload shows the key exactly once, so it goes straight into a secret manager (Vault, AWS Secrets Manager, Doppler) rather than a .env file in your repo.
  3. Whether IP allowlisting exists. If it does, turn it on. FoxReload keys can be restricted by IP or CIDR, up to 10 entries; a request from an unlisted IP returns HTTP 403, which is a far better outcome than a leaked key that works from anywhere.

The environment question

Many suppliers give you a separate sandbox host. Many do not. FoxReload has no separate sandbox environment: you test with isMock: true in the order-creation body, which returns mock codes in the same response shape as a real order without debiting your balance.

This matters architecturally. Ask your supplier how testing actually works before you write your first integration test. If the test mode is a flag in the request body rather than a different host, your code has to thread that flag through the whole stack, and your database has to distinguish mock orders from real ones.

Step 2. Catalogue and price sync

The catalogue is a background job, not an on-demand request.

curl "https://public-api.foxreload.com/api/categories/?limit=20" \
  -H "X-API-Key: YOUR_API_KEY"

Then pull products per category:

curl "https://public-api.foxreload.com/api/products/?category_id_or_slug=gift-cards&limit=20" \
  -H "X-API-Key: YOUR_API_KEY"

Each product carries id, name and price. The id is what you later pass as itemId when placing an order, so persist it in your own table as the supplier's foreign key.

Practical sync rules:

  • Store supplier_product_id alongside your own internal SKU. Never bind your storefront directly to one supplier's identifiers, or adding a second supplier becomes a rewrite.
  • Refresh prices on a separate, more frequent job than the full catalogue crawl. Names and descriptions change rarely; prices change constantly.
  • Never delete a product because it was absent from one response. Flag it unavailable instead. A partial response or a timeout must not wipe your catalogue.
  • Keep markup in your own system, not baked into the cost price. The supplier's price is an input; your retail price is the output of your own pricing engine.

Step 3. Balance checks

Wholesale digital-goods APIs usually run on a prepaid balance: you fund an account and orders debit it. That introduces a failure class that has nothing to do with your code — the order failed because you ran out of money.

What to build:

  • Read the balance before placing an order when the amount is material.
  • Run background balance monitoring with two thresholds — warning and critical — alerting to a channel somebody actually reads at 3 a.m.
  • Handle the insufficient-funds error properly. On FoxReload it surfaces as BalanceNotEnough, and top-ups go through POST /api/topups/crypto/. Ask your own supplier which funding methods they support and how long settlement takes, because that number directly determines how large a float you need to hold.

Think through the customer-facing side too. If your balance ran dry, the buyer should not get a 500. They should get a clear refusal — or, better, should never have been able to check out an item you cannot currently source.

Step 4. Placing the order

An order is a POST with an array of line items:

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 id, price, status, createdAt, paymentExpiresAt and an items[] array.

A necessary caveat about idempotency

Some APIs accept an Idempotency-Key header so that re-sending the same request cannot create a second order. Verify whether your specific supplier actually implements this — many do not. FoxReload does not support an Idempotency-Key header.

Where there is no support, you build duplicate protection yourself:

  1. Generate a unique operation key on your side and persist it before calling the supplier.
  2. On a network error or timeout, do not blindly re-place the order — first query the supplier's order list and check whether it was in fact created.
  3. Only once you have confirmed it does not exist do you retry.

A timeout on order creation is ambiguity, not failure. Treating it as failure and immediately retrying is the most expensive way to learn the difference.

Step 5. Status retrieval — polling as the baseline

Polling is the mechanism that always works. Webhooks are an optional extra.

Check whether your supplier offers webhooks and whether they sign them (HMAC or otherwise). If they do, treat webhooks as an accelerator — but keep polling as the safety net, because delivery is never guaranteed and your endpoint may be down at exactly the wrong moment. FoxReload offers no webhooks at all; order results are retrieved purely by polling.

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

A workable polling schedule:

Phase Behaviour
First minute Frequent polling, every few seconds
Afterwards Widening interval (backoff)
Deadline Your own cut-off, after which the order is flagged for attention
Terminal states Polling stops — the outcome is recorded in your database

FoxReload orders move activepaidprocessingcompleted, with terminal branches cancelled (carrying a cancelReason) and failed (with a per-item error in items[].error). On completed, codes sit in items[].externalData. The full state walkthrough is in the order flow article.

Step 6. Error handling

Split errors into three buckets and treat them differently:

  • Never retry. HTTP 400, 401, 403, 404 are your bug or your configuration. Retrying returns the same answer. Log and investigate.
  • Retry with backoff. HTTP 429 (rate limit) and 5xx. Exponential backoff with jitter, a bounded attempt count, a ceiling on the interval.
  • Verify before retrying. Network timeouts on mutating calls. Find out what happened on the supplier's side first, act second.

Per-item errors inside an order are their own case. An order can complete partially: one line delivered, another not. Your data model has to represent partial fulfilment, or your refund logic will be wrong.

Step 7. Go-live checklist

  • Key is in a secret manager, absent from git, and repo history has been checked.
  • IP allowlist enabled if the supplier supports it.
  • Mock (or sandbox) orders run against every product type you sell.
  • Catalogue sync is scheduled and does not wipe on a partial response.
  • Balance is monitored with two alert thresholds.
  • Order placement is duplicate-protected on your side.
  • Polling has a deadline and a stuck-order queue with an alert.
  • Retries fire only on 429 and 5xx.
  • Every supplier request and response is logged against your internal order ID — this is your evidence in a dispute.
  • A manual runbook exists: what an operator does when an order hangs and the customer is already in your inbox.

Where to source inventory

An integration layer is worth building once, against a catalogue broad enough to cover most of your range. FoxReload is a wholesale digital-goods supplier with 900+ SKUs — game keys, gift cards, game top-ups, eSIM and software licences — all behind one REST API with automated delivery and multi-region SKUs. One key, one response shape, one order model across the whole range, instead of five integrations against five different auth schemes.

Read next

Frequently asked questions

Where should I start when integrating a supplier API?
Start by proving authentication works — make one request against the simplest endpoint the supplier offers, usually an account-profile or category-list call, and confirm you get an HTTP 200. Only then move on to the catalogue. That order eliminates most first-day problems: wrong header name, wrong host, key not on the IP allowlist. Catalogue sync comes second, order placement third.
Do I need to cache the supplier catalogue on my side?
Yes, always. Your storefront should read products and prices from your own database rather than calling the supplier on every page render — otherwise you hit rate limits and make your site's availability dependent on somebody else's uptime. A background job refreshes your local table at whatever cadence suits your category. Price and availability still get re-validated at order time.
How do I get the order result if my supplier has no webhooks?
By polling — periodically re-fetching the order by its ID. Polling is the baseline mechanism that works with any REST supplier, including FoxReload, which does not offer webhooks at all. A sensible pattern is frequent polling for the first minute, then a widening interval until a terminal state. Always set a deadline and alert on orders that exceed it.
What should I verify before going live?
That the key is in a secret manager and never entered git; that catalogue sync is scheduled and survives a supplier outage; that order placement checks balance; that polling has a timeout and an alert queue for stuck orders; that retries only fire on 429 and 5xx; and that every supplier request and response is logged against your internal order ID. Separately, test what happens at zero balance and with the catalogue endpoint down.
See FoxReload wholesale prices

Related articles