> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Point Topup Reseller APIs

> The six signed endpoints a Point Topup reseller can call: catalogue lookup, purchase-balance inquiry, order creation with the resellerRequestId idempotency key, single and paged order inquiry, fulfillment inquiry, plus the four order statuses and the purchase notification.

> [!NOTE]
>
> This page is for **resellers** — parties that buy point-card inventory from Waffo Point Topup through an API against a prepaid balance. It is not part of the merchant payment APIs, and it is not the supplier-side Mode A/B/C integration in [Point Topup integration overview](/docs/en/developer-docs/point-topup/overview).

Message format, amount and time conventions, the `code` / `msg` / `data` envelope and the RSA key exchange are shared with the rest of Point Topup — see [Point Topup API common specifications](/docs/en/developer-docs/point-topup/api-common).

## Which endpoints can I call?

All six are `POST` with a JSON body. The sandbox and production base URLs are issued during onboarding.

| Endpoint | Purpose |
| - | - |
| `/api/v1/gamepin/products` | Your catalogue: items, SKUs, prices, pricing strategy |
| `/api/v1/gamepin/balance` | Available purchase balance per currency |
| `/api/v1/gamepin/create` | Place a purchase order |
| `/api/v1/gamepin/inquiry` | Read one order, optionally with the card serials |
| `/api/v1/gamepin/orders-inquiry` | Paged order list over a time window |
| `/api/v1/gamepin/fulfillment-inquiry` | Fulfillment result of a direct-fulfillment order |

## How is reseller authentication different from `order/create`?

Same transport — `X-API-KEY` plus an `X-SIGNATURE` over the raw body, verified with the public key you exchanged at onboarding, and a signed response to verify in return. Three things differ:

| | Merchant payment APIs | Point Topup reseller APIs |
| - | - | - |
| Identity behind the key | your merchant id (MID) | your `resellerId` |
| Identity in the body | not repeated | **every** body carries `resellerId`, and it must equal the id behind the key |
| Scope of the key | one merchant API set | keys are scoped: a purchase key reaches all six endpoints, a Mode C direct-fulfillment key reaches `fulfillment-inquiry` only |

A `resellerId` that does not match the key is a parameter error; an endpoint outside the key's scope returns `A0004`.

## How do I pull the catalogue, and what is `priceStrategy`?

`products` returns the items active on your reseller contract. Pass `itemId` to narrow to one item, omit it for everything; an unknown or inactive `itemId` gives an empty list, not an error.

| Field | Meaning |
| - | - |
| `category` | `GAME_PIN` — a card serial is delivered to you; `TOP_UP` — the game account is topped up directly |
| `skuList[].price` / `currency` | Unit price, and the currency the order is charged in |
| `skuList[].priceStrategy` | `FIXED_PRICE` — buy the SKU as listed; `SPECIFIED_FACE_VALUE` — you choose the face value and the price derives from it |
| `skuList[].purchaseMaxLimit` | Highest face value you may specify on a `SPECIFIED_FACE_VALUE` SKU |

`balance` then returns one entry per currency with the currently **available** balance. Match it to the SKU's currency: an order is charged in the SKU's own currency.

## What does `create` require?

| Field | Notes |
| - | - |
| `resellerRequestId` | Your own id, max 32 chars. Required, and it is the idempotency key |
| `resellerId` | Must match the API key |
| `itemId` / `skuId` | From `products`. An unknown SKU returns `A0005` |
| `skuQuantity` | Must be `1`; anything else returns `A0006` |
| `skuFaceValue` | Required on `SPECIFIED_FACE_VALUE` SKUs, and must be a whole multiple of the SKU's face-value unit |
| `notifyUrl` | Required, must be a valid URL. Where the purchase notification goes |
| `requestedAt` | Your request time, format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`. Other formats are rejected |
| `buyerInfo` | Optional. On `TOP_UP` SKUs it carries the top-up account details the item asks for |
| `extendInfo` | Optional, must parse as a JSON object, max 128 chars. Echoed back, not interpreted |

Two behaviours to know: `buyerInfo.userEmail` is always replaced with the e-mail on your reseller account, so your customer's address there has no effect; and the available balance in the order currency is checked **before** the order is accepted, so an underfunded account fails fast with `A0009` instead of producing an order.

## Why does `create` always come back `IN_PROGRESS`?

Because acceptance and fulfillment are separate. `create` returns `resellerRequestId`, the Waffo `orderId` and `status` `IN_PROGRESS`; the debit and the supply run afterwards, and the outcome arrives at your `notifyUrl` or from `inquiry`. Never read the create response as a purchase result.

A repeat of the same `resellerRequestId` is deduplicated on `resellerId` + `resellerRequestId`: you get the original `orderId` back, again as `IN_PROGRESS`, even if that order already finished — so follow a duplicate with an `inquiry`. No second order is created and the repeat's other fields are ignored. Two identical requests racing in parallel return `A0010`; retry after a moment.

## How do I query one order, or many?

`inquiry` takes `orderId` **or** `resellerRequestId` — at least one, and the order must be yours. Set `returnGameCard` to `true` for `gameCardList`: serials, passwords where the SKU uses them, `expiryType` (`FROM_PURCHASE` or `FROM_REDEMPTION`) and `expiry`. Cards appear only once the order is `SUCCESS`.

`orders-inquiry` is the paged form. `page`, `pageSize`, `startTime` and `endTime` are all required; the window filters on `requestedAt` — the time **you** sent — in the same ISO 8601 format, and is meant to stay within 6 months. `resellerRequestId`, `orderId` and `status` narrow it further. `records` come wrapped in `total`, `size`, `current` and `pages`, each shaped like a single `inquiry` but with no card serials.

## What do the order statuses and amounts mean?

| `status` | Meaning |
| - | - |
| `IN_PROGRESS` | Accepted, being paid or being supplied. Not final |
| `SUCCESS` | Supplied; card details available with `returnGameCard` |
| `PAY_SUCCESS` | Paid, and fulfillment is yours to complete — Waffo does not deliver this SKU |
| `FAILURE` | Payment or supply failed. `failureCode` and `failureReason` are populated, and any debited amount is returned to your balance |

`totalAmount` is the list price of what you bought, `totalAmountAfterDiscount` is what your contract charges, and `currency` applies to both. `completedTime` appears once the order is final.

`fulfillment-inquiry` belongs to the direct-fulfillment (Mode C) flow, not the purchase flow, which is why its shape differs: the caller identifies itself as `supplierId`, the order as `salesOrderId` or `payOrderId` (at least one), and the answer is a `fulfillmentStatus` — `IN_PROGRESS`, `SUCCESS`, `PAY_SUCCESS`, `PAY_SUCCESS_SUPPLY_FAILED` or `PAYMENT_FAILED` — not the four values above. See
[Mode C: direct fulfillment](/docs/en/developer-docs/point-topup/mode-c-direct-fulfillment).

## What arrives at my `notifyUrl`?

Once an order is final, Waffo posts a signed JSON body:

```json theme={null}
{
  "eventType": "GAMEPIN_PURCHASE_NOTIFICATION",
  "result": { "orderId": "...", "status": "SUCCESS", "gameCardList": [ ... ] }
}
```

`result` is the full `inquiry` payload, card serials included. Verify `X-SIGNATURE` against Waffo's public key, then acknowledge with exactly `{"message": "success"}` — any other body, or a non-2xx response, counts as a failed delivery and is retried. Retries do not continue forever, so keep a reconciliation poll against `inquiry` as the source of truth.

## Which error codes do these endpoints return?

| Code | Meaning on this flow |
| - | - |
| `0` | Accepted. Still check the business `status` |
| `A0001` / `A0002` | Unknown API key / signature verification failed |
| `A0003` | Parameter validation failed, including a `resellerId` that does not match the key |
| `A0004` | The key may not call this endpoint |
| `A0005` | The item or SKU is not on your reseller contract |
| `A0006` | `skuQuantity` other than 1 |
| `A0007` | The order does not exist, or is not yours |
| `A0009` | Insufficient reseller balance in the order currency |
| `A0010` | Duplicate concurrent request for the same `resellerRequestId` |
| `C0001` | System error. Query before re-submitting |

***

Something not matching? [Contact support](mailto:support@waffo.com) with your `resellerId` and either the `orderId` or the `resellerRequestId`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.