> ## 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 分销商 API

> Point Topup 分销商可以调用的六个签名接口：商品目录查询、采购余额查询、带 resellerRequestId 幂等键的订单创建、单笔与分页订单查询、履约查询，以及四个订单状态和采购通知。

> [!NOTE]
>
> 本页面向**分销商（reseller）**——通过 API、凭预付余额从 Waffo Point Topup 采购点卡库存的一方。它不属于商户支付 API，也不是[Point Topup 集成概览](/docs/zh/developer-docs/point-topup/overview)中供应商侧的 Mode A/B/C 集成。

报文格式、金额与时间约定、`code` / `msg` / `data` 信封结构以及 RSA 密钥交换与 Point Topup 其余部分相同——见[Point Topup API 通用规范](/docs/zh/developer-docs/point-topup/api-common)。

## 我可以调用哪些接口？

六个接口全部是 `POST`，请求体为 JSON。Sandbox 和生产环境的基础 URL 在入网时下发。

| 接口 | 用途 |
| - | - |
| `/api/v1/gamepin/products` | 你的商品目录：商品、SKU、价格、定价策略 |
| `/api/v1/gamepin/balance` | 各币种的可用采购余额 |
| `/api/v1/gamepin/create` | 下采购订单 |
| `/api/v1/gamepin/inquiry` | 读取一笔订单，可选返回卡密序列号 |
| `/api/v1/gamepin/orders-inquiry` | 按时间窗口分页的订单列表 |
| `/api/v1/gamepin/fulfillment-inquiry` | 直充订单的履约结果 |

## 分销商认证和 `order/create` 有什么不同？

传输方式相同——`X-API-KEY` 加上对原始请求体计算的 `X-SIGNATURE`，用你在入网时交换的公钥验证，并返回一个供你反向验证的签名响应。有三点不同：

| | 商户支付 API | Point Topup 分销商 API |
| - | - | - |
| 密钥背后的身份 | 你的商户 id（MID） | 你的 `resellerId` |
| 请求体中的身份 | 不重复携带 | **每个**请求体都携带 `resellerId`，且必须等于密钥背后的 id |
| 密钥的范围 | 一套商户 API | 密钥有范围限定：采购密钥可访问全部六个接口，Mode C 直充密钥仅可访问 `fulfillment-inquiry` |

`resellerId` 与密钥不匹配属于参数错误；调用密钥范围之外的接口返回 `A0004`。

## 怎么拉取商品目录，`priceStrategy` 是什么？

`products` 返回你的分销合同上处于生效状态的商品。传 `itemId` 可缩小到单个商品，不传则返回全部；未知或未生效的 `itemId` 返回空列表，而不是报错。

| 字段 | 含义 |
| - | - |
| `category` | `GAME_PIN`——向你交付卡密序列号；`TOP_UP`——直接为游戏账户充值 |
| `skuList[].price` / `currency` | 单价，以及订单计费所用的币种 |
| `skuList[].priceStrategy` | `FIXED_PRICE`——按所列价格购买该 SKU；`SPECIFIED_FACE_VALUE`——由你指定面值，价格由面值推算 |
| `skuList[].purchaseMaxLimit` | 在 `SPECIFIED_FACE_VALUE` SKU 上你可以指定的最高面值 |

随后 `balance` 按币种各返回一条记录，给出当前**可用**余额。请与 SKU 的币种对应：订单按 SKU 自身的币种计费。

## `create` 需要哪些字段？

| 字段 | 说明 |
| - | - |
| `resellerRequestId` | 你自己的 id，最长 32 个字符。必填，且它是幂等键 |
| `resellerId` | 必须与 API 密钥匹配 |
| `itemId` / `skuId` | 来自 `products`。未知 SKU 返回 `A0005` |
| `skuQuantity` | 必须为 `1`；其他值返回 `A0006` |
| `skuFaceValue` | `SPECIFIED_FACE_VALUE` SKU 上必填，且必须是该 SKU 面值单位的整数倍 |
| `notifyUrl` | 必填，必须是合法 URL。采购通知发往此处 |
| `requestedAt` | 你的请求时间，格式 `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`。其他格式会被拒绝 |
| `buyerInfo` | 可选。在 `TOP_UP` SKU 上携带该商品要求的充值账户信息 |
| `extendInfo` | 可选，必须能解析为 JSON 对象，最长 128 个字符。原样回传，不做解析 |

有两个行为需要知道：`buyerInfo.userEmail` 总是会被替换为你分销商账户上的邮箱，所以你在其中填写的客户地址不起作用；订单币种下的可用余额会在订单被接受**之前**校验，因此余额不足的账户会以 `A0009` 快速失败，而不会生成订单。

## 为什么 `create` 总是返回 `IN_PROGRESS`？

因为接受和履约是分开的。`create` 返回 `resellerRequestId`、Waffo 的 `orderId` 以及 `status` 为 `IN_PROGRESS`；扣款和供货在之后进行，结果会到达你的 `notifyUrl` 或通过 `inquiry` 获取。永远不要把 create 的响应当作采购结果。

重复发送同一个 `resellerRequestId` 会按 `resellerId` + `resellerRequestId` 去重：你会拿回原来的 `orderId`，状态仍为 `IN_PROGRESS`，即使该订单已经完成——所以重复请求之后请跟一次 `inquiry`。不会创建第二个订单，重复请求中的其他字段会被忽略。两个完全相同的请求并行竞争时返回 `A0010`；稍后重试即可。

## 怎么查询一笔订单，或者查多笔？

`inquiry` 接受 `orderId` **或** `resellerRequestId`——至少传一个，且订单必须属于你。把 `returnGameCard` 设为 `true` 可获得 `gameCardList`：序列号、密码（SKU 使用密码时）、`expiryType`（`FROM_PURCHASE` 或 `FROM_REDEMPTION`）以及 `expiry`。卡信息仅在订单为 `SUCCESS` 后才出现。

`orders-inquiry` 是分页形式。`page`、`pageSize`、`startTime` 和 `endTime` 全部必填；时间窗口按 `requestedAt`——**你**发送请求的时间——过滤，采用相同的 ISO 8601 格式，且应保持在 6 个月以内。`resellerRequestId`、`orderId` 和 `status` 可进一步缩小范围。`records` 包裹在 `total`、`size`、`current` 和 `pages` 中，每条形状与单笔 `inquiry` 相同，但不含卡密序列号。

## 订单状态和金额各是什么意思？

| `status` | 含义 |
| - | - |
| `IN_PROGRESS` | 已接受，正在支付或正在供货。非最终状态 |
| `SUCCESS` | 已供货；通过 `returnGameCard` 可获取卡信息 |
| `PAY_SUCCESS` | 已支付，履约由你自行完成——Waffo 不交付该 SKU |
| `FAILURE` | 支付或供货失败。`failureCode` 和 `failureReason` 会填充，已扣的金额会退回你的余额 |

`totalAmount` 是你所购内容的标价，`totalAmountAfterDiscount` 是你的合同实际收取的金额，`currency` 对两者都适用。`completedTime` 在订单为最终状态后出现。

`fulfillment-inquiry` 属于直充（Mode C）流程，而不是采购流程，所以它的形状不同：调用方以 `supplierId` 标识自己，订单以 `salesOrderId` 或 `payOrderId`（至少一个）标识，返回的是 `fulfillmentStatus`——`IN_PROGRESS`、`SUCCESS`、`PAY_SUCCESS`、`PAY_SUCCESS_SUPPLY_FAILED` 或 `PAYMENT_FAILED`——而不是上面的四个值。见
[Mode C：直充](/docs/zh/developer-docs/point-topup/mode-c-direct-fulfillment)。

## 我的 `notifyUrl` 会收到什么？

订单进入最终状态后，Waffo 会 POST 一个带签名的 JSON 请求体：

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

`result` 是完整的 `inquiry` 载荷，包含卡密序列号。用 Waffo 的公钥验证 `X-SIGNATURE`，然后以严格的 `{"message": "success"}` 进行确认——任何其他响应体或非 2xx 响应都算投递失败并会被重试。重试不会无限进行，所以请保留一个以 `inquiry` 为事实来源的对账轮询。

## 这些接口会返回哪些错误码？

| 错误码 | 在此流程中的含义 |
| - | - |
| `0` | 已接受。仍需检查业务 `status` |
| `A0001` / `A0002` | 未知 API 密钥 / 签名验证失败 |
| `A0003` | 参数校验失败，包括 `resellerId` 与密钥不匹配 |
| `A0004` | 该密钥不能调用此接口 |
| `A0005` | 商品或 SKU 不在你的分销合同上 |
| `A0006` | `skuQuantity` 不为 1 |
| `A0007` | 订单不存在，或不属于你 |
| `A0009` | 订单币种下的分销商余额不足 |
| `A0010` | 同一 `resellerRequestId` 的重复并发请求 |
| `C0001` | 系统错误。重新提交前请先查询 |

***

有对不上的地方？请[联系支持](mailto:support@waffo.com)，并提供你的 `resellerId` 以及 `orderId` 或 `resellerRequestId` 之一。


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