REST API · v1

商品下单 API 接入文档

使用专用的 dy_sk_ 商品下单 Key 和统一预付余额,按当前用户等级价查询商品、检查数量并购买兑换码。 本文给出可直接使用的请求、响应、幂等恢复和错误处理规则。

Base URL
https://api.dingyue.app/shop/v1
Authentication
Bearer dy_sk_...
Machine readable

快速开始

  1. 登录 API Hub,充值余额并显式选择“商品下单 Key”。密钥只会完整显示一次。
  2. 服务端调用 GET /products,取得商品 ID 和当前等级价。
  3. 为自己的业务订单持久化一个唯一 externalOrderId
  4. 调用 POST /orders;请求结果不确定时复用同一参数重试。
  5. 把每个 code 和响应中的 redeemUrl 一起交付给最终用户。
最重要的规则:发送下单请求前先保存 externalOrderId。任何超时、断网或 5xx 重试都必须使用相同 externalOrderId、productId 和 qty,不能生成新值。

鉴权

除 OpenAPI 和 llms.txt 外,所有接口都需要:

Authorization: Bearer dy_sk_your_api_key

shop:read 可读取商品与余额;下单、订单列表和订单详情都需要 shop:order。普通 AI Key 无法访问订单数据。

商品下单 Key 可直接消耗账户余额,只能保存在后端服务、服务器密钥或本地环境变量中。

接口一览

方法路径所需权限用途
GET/productsshop:read查询已开放商品、当前等级价与履约状态
GET/products/:id/availability?qty=Nshop:read实时检查指定数量是否可购
GET/balanceshop:read查询统一 API 余额、预留金额与等级
POST/ordersshop:order从余额购买兑换码;externalOrderId 幂等
GET/ordersshop:order按游标查询订单,可用 externalOrderId 过滤;不返回 codes
GET/orders/:idshop:order查询订单详情;已交付订单返回 codes

金额全部使用十进制字符串,例如 "21.99",不要用二进制浮点数自行计算或比较。

商品与报价

查询当前等级价

curl https://api.dingyue.app/shop/v1/products \
  -H "Authorization: Bearer dy_sk_your_api_key"
{
  "level": {
    "level": 2,
    "scoreMicrocents": 10000000000,
    "score": "100.00",
    "nextLevel": {
      "level": 3,
      "thresholdMicrocents": 50000000000,
      "remainingMicrocents": 40000000000,
      "remaining": "400.00"
    }
  },
  "products": [{
    "id": "prod_chatgpt_plus",
    "slug": "chatgpt-plus",
    "name": "ChatGPT Plus",
    "price": "21.99",
    "currency": "USD",
    "inStock": true,
    "stockMode": "on_demand",
    "stock": null,
    "availabilityStatus": "available",
    "deliveryMode": "automatic"
  }]
}
  • price 是当前 API Key 所属账户的最终单价,不是供货成本。
  • availabilityStatus 描述当前履约状态;下单前仍应检查目标数量。
  • 客户端应保存商品 ID,不要用商品名称作为稳定标识。

检查指定数量

curl "https://api.dingyue.app/shop/v1/products/prod_chatgpt_plus/availability?qty=2" \
  -H "Authorization: Bearer dy_sk_your_api_key"
{
  "productId": "prod_chatgpt_plus",
  "qty": 2,
  "available": true,
  "unitPrice": "21.99",
  "currency": "USD",
  "stockMode": "on_demand",
  "availabilityStatus": "available",
  "deliveryMode": "automatic",
  "checkedAt": 1787600000
}

单次数量范围为 1–1000。可购性是调用时刻的结果,不构成长期库存或 SLA 保证。

余额与等级价格

curl https://api.dingyue.app/shop/v1/balance \
  -H "Authorization: Bearer dy_sk_your_api_key"
{
  "balance": "125.0000",
  "reserved": "0.0000",
  "available": "125.0000",
  "currency": "USD",
  "level": {
    "level": 2,
    "scoreMicrocents": 12500000000,
    "score": "125.00",
    "nextLevel": {
      "level": 3,
      "thresholdMicrocents": 50000000000,
      "remainingMicrocents": 37500000000,
      "remaining": "375.00"
    }
  }
}

available 等于余额减去正在处理订单的预留金额;创建订单时以可用余额为准。

等级等级分门槛
Lv1$0
Lv2$100
Lv3$500
Lv4$2,000
Lv5$10,000

等级分随 API 账户正向充值累计,只升不降;购买商品和消耗 AI API 余额不会降级。每个商品都可以配置独立的 Lv1–Lv5 价格。

创建订单

POST /orders 会从统一 API 余额扣款并返回兑换码。该请求可能产生真实费用。

字段要求说明
externalOrderId必填,1–64 字符你方唯一订单号,也是幂等键
productId必填来自 GET /products
qty必填,整数 1–1000购买数量
expectedUnitPrice推荐,最多两位小数锁定用户单价,变化时拒绝下单
curl -X POST https://api.dingyue.app/shop/v1/orders \
  -H "Authorization: Bearer dy_sk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "externalOrderId": "merchant-order-20260825-001",
    "productId": "prod_chatgpt_plus",
    "qty": 2,
    "expectedUnitPrice": "21.99"
  }'
{
  "orderId": "aord_xxxxxxxxxxxx",
  "externalOrderId": "merchant-order-20260825-001",
  "productId": "prod_chatgpt_plus",
  "productName": "ChatGPT Plus",
  "qty": 2,
  "unitPrice": "21.99",
  "amount": "43.98",
  "currency": "USD",
  "status": "delivered",
  "codes": ["CODE-ONE", "CODE-TWO"],
  "redeemUrl": "https://redeem.example.com",
  "errorCode": null,
  "createdAt": 1787600000,
  "deliveredAt": 1787600002,
  "reused": false
}
  • reused=false 表示本次首次处理;幂等重放成功时为 true。
  • 成功响应的 code 数量应与 qty 完全一致。
  • 兑换网址可能调整,必须使用每笔响应中的 redeemUrl,不要在客户端硬编码。

查询订单与恢复未知结果

按你方订单号查找

curl "https://api.dingyue.app/shop/v1/orders?externalOrderId=merchant-order-20260825-001&limit=1" \
  -H "Authorization: Bearer dy_sk_your_api_key"

列表支持 limit=1..100 和不透明 cursor。列表不返回兑换码;需要取码时调用订单详情。

查询详情

curl https://api.dingyue.app/shop/v1/orders/aord_xxxxxxxxxxxx \
  -H "Authorization: Bearer dy_sk_your_api_key"

当状态为 delivered 时,详情会返回 codes 和 redeemUrl。

订单状态

  • processing:供应结果仍可能在确认,保留余额预留;复用原请求重试。
  • retryable:已确认可安全重试;仍复用原 externalOrderId。
  • delivered:已扣款并交付,可从详情恢复兑换码。
  • failed / refunded:订单已关闭;如需重新购买,使用新的 externalOrderId。

完整 Node.js 示例

以下示例会读取实时商品价格并创建一笔真实余额订单。运行前请确认商品、数量和账户余额。

const BASE_URL = "https://api.dingyue.app/shop/v1";
const API_KEY = process.env.DINGYUE_API_KEY;

if (!API_KEY) throw new Error("Missing DINGYUE_API_KEY");

async function request(path, init = {}) {
  const response = await fetch(BASE_URL + path, {
    ...init,
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      ...(init.body ? { "Content-Type": "application/json" } : {}),
      ...init.headers,
    },
  });
  const data = await response.json();
  if (!response.ok) {
    throw Object.assign(new Error(data.message || data.error), {
      status: response.status,
      code: data.error,
      details: data.details,
    });
  }
  return data;
}

const catalog = await request("/products");
const product = catalog.products[0];
if (!product) throw new Error("No API product is currently available");

// Persist this value with your own order before sending the request.
// If the response is lost, retry with the SAME value, productId and qty.
const externalOrderId = `merchant-${crypto.randomUUID()}`;

const order = await request("/orders", {
  method: "POST",
  body: JSON.stringify({
    externalOrderId,
    productId: product.id,
    qty: 1,
    expectedUnitPrice: product.price,
  }),
});

for (const code of order.codes) {
  console.log({ code, redeemUrl: order.redeemUrl });
}

生产代码应先把 externalOrderId 与本地业务订单写入数据库,再发出 POST;不要只保存在进程内存中。

错误处理与安全重试

错误响应使用稳定的 error 码。业务逻辑应按错误码和 HTTP 状态分支,不要依赖可变的 message 文案。

{
  "error": "price_changed",
  "message": "Product price changed; refresh the quote and retry",
  "details": {
    "expectedUnitPrice": "21.99",
    "actualUnitPrice": "22.49"
  }
}
HTTP错误码处理方式
400invalid_input / bad_request请求字段、数量或游标无效;修正请求后再调用
401unauthorizedAPI Key 缺失、无效、已撤销或账户不可用
403insufficient_scope当前 Key 没有接口所需权限;创建专用商品下单 Key
403key_order_limit_exceeded订单金额超过该 Key 的单笔上限;减少数量或在个人中心调高限额
402insufficient_balance可用余额不足;充值后复用原 externalOrderId
402key_daily_limit_exceeded该 Key 当日消费达到日上限;等 UTC 零点重置或在个人中心调高限额
404not_found商品或订单不存在,或不属于当前账户
409price_changed用户售价变化;重新读取商品并确认新价格
409idempotency_conflict同一 externalOrderId 被用于不同商品或数量
409out_of_stock当前数量暂不可履约;稍后重新检查可购性
409supplier_price_changed供货成本超过保护线,等待平台更新报价
429rate_limited账户级请求过快;指数退避后重试
503supplier_unavailable供货服务暂不可用;POST 重试必须复用原 externalOrderId
503supplier_not_configured平台尚未配置供货密钥;不要循环重试,联系平台处理
503order_in_progress已有请求正在处理;按 details.retryAfterSeconds 等待并复用原 externalOrderId
503order_commit_pending供应结果正在确认;必须复用原 externalOrderId 重试
500server_error服务内部错误;记录时间和请求参数后联系支持
对 POST /orders 而言,即使无法判断供应端是否已经扣款,也可以安全地用原 externalOrderId 和相同参数重试。平台会恢复同一订单,不会创建第二笔采购。

安全建议

  • 不要把 API Key 或兑换码写入前端代码、公开仓库、分析事件或普通日志。
  • externalOrderId 不要包含姓名、邮箱、手机号等个人信息。
  • 仅向订单所属用户展示 codes,并把 code 与 redeemUrl 一起交付。
  • 如果怀疑 API Key 泄露,请立即在 API Hub 撤销并重新生成。