Apinoa Docs

错误代码

Apinoa API 返回的错误代码完整参考。

查看原始 .mdx

错误响应格式

所有错误响应遵循一致的封装格式:

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "可读的错误描述"
  }
}

网关端点还包含用于追踪的 requestId

{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Your balance does not cover this call. Top up at https://apinoa.com/dashboard/balance."
  },
  "requestId": "550e8400e29b41d4a716446655440000"
}

平台 API 错误

这些错误来自 gateway.apinoa.com,每一个都带有 requestId —— 联系支持团队时请附上它。

您的账户

代码状态含义
UNAUTHORIZED401缺少 x-api-key 头,或密钥已吊销、已过期或无法识别
INSUFFICIENT_BALANCE402本次调用费用超过剩余余额。请在 控制台 > 余额 中充值
FORBIDDEN403密钥有效,但不允许发起该调用
ACCOUNT_SUSPENDED403账号已被停用:解除前该账号下的所有密钥都会被拒绝。请联系客服

需要重点处理的是 402。在按量付费模式下,它表示余额正常用尽,而非故障 —— 重试无法解决, 充值之前的每次调用都会返回同样的结果。

背压

代码状态含义
CAPACITY_SATURATED429暂无容量处理本次调用,平台本身没有问题
MARKETPLACE_SATURATED429同上,但仅限某一个平台

两者都带有以秒为单位的 Retry-After。它是真实的估算值而非固定常量 —— 请等待相应时间后重试。 两者均不计费。

您的请求

代码状态含义
UNKNOWN_MARKETPLACE404平台不存在。GET /v1/marketplaces 可列出所有平台
UNKNOWN_OPERATION404该平台未实现此操作
INVALID_PARAMS400参数缺失、无法识别或超出范围;错误信息会指明具体参数
QUERY_REQUIRED IMAGE_REQUIRED CATEGORY_REQUIRED400缺少该操作唯一的必填输入
CATEGORY_NOT_BROWSABLE400该类目是没有商品的导航类目。请用同一 id 调用 categories,再浏览其子类目
BROWSABLE_ONLY_UNAVAILABLE400对尚无测量数据的平台使用了 browsableOnly=true。去掉该参数即可获得完整分类
INVALID_CURSOR400cursor 并非该操作签发的。请不带游标重新开始
PAGE_NOT_SUPPORTED400该操作按 cursor 翻页,而不是 page
CURRENCY_NOT_SUPPORTED400平台不以所请求的货币标价
INVALID_PRODUCT_ID400该 id 不是此平台使用的格式
PRODUCT_NOT_FOUND404平台上没有该商品
REVIEWS_NOT_FOUND404商品存在,且确实一条评价也没有

400 从不计费。

覆盖范围

代码状态含义
OPERATION_UNSUPPORTED501该操作存在,但不支持此输入
REVIEW_APP_UNSUPPORTED501商家通过我们尚未支持的应用发布评价
REVIEWS_UNREACHABLE501评价确实存在(评价数或平均分可以证明),但一条也没有取回

501 有意区别于 404 和空列表:数据存在,只是我们无法读取。

上游

代码状态含义
UPSTREAM_ERROR502平台返回了无法使用的内容
UPSTREAM_UNAVAILABLE502平台没有响应
UPSTREAM_READ_FAILED502响应被中途截断
UPSTREAM_TIMEOUT502平台未能及时响应
SERVICE_UNAVAILABLE503我方的临时故障,请重试

没有返回任何内容的调用,无论状态码如何,都不计费。 请使用指数退避重试。 本页列出的代码就是全部。平台错误始终以其中之一返回,不会直接暴露更细的代码。提供 requestId, 支持团队即可查到具体情况。

平台错误

这些与具体平台无关,任何路径、任何平台都可能返回。

代码状态含义
BAD_REQUEST400请求根本无法解析:格式错误的请求体、无法解析的查询字符串
UNSUPPORTED_MEDIA_TYPE415向 JSON 端点发送了非 application/json 的内容
PAYLOAD_TOO_LARGE413请求体超过该端点接受的大小
NOT_FOUND404该路径上没有路由
NOT_IN_V1404该路径存在于 /v1 之前,并不属于 v1。响应体的 successor 字段和 Link: …; rel="successor-version" 响应头会指明替代路径
RATE_LIMITED429该 API 密钥每秒请求数超过允许值。请等待 Retry-After 秒后重试;被拒绝的调用不计费
QUOTA_EXCEEDED429账户没有可覆盖此 API 的计费安排
INTERNAL_ERROR500我方故障。请重试;若持续出现,请提供 requestId

图片翻译错误

代码状态含义
INVALID_IMAGE422这些字节不是可读的图片
UNSUPPORTED_IMAGE_FORMAT422图片可读,但格式不在翻译支持范围内
IMAGE_TOO_LARGE413图片的像素尺寸超过该端点的上限。错误信息会给出实际尺寸与上限
NETWORK_ERROR504图片 URL 未能及时响应
TRANSLATION_FAILED502文字已读取,但翻译失败
RENDER_FAILED502译文无法重新绘制回图片
ROUTING_INCIDENT502请求未能处理,请重试
WORKER_USER_FAULT4xx请求本身被拒绝——状态码与错误信息会说明原因

FONT_* 代码属于自定义字体,列在 自定义字体 一页中。还有两个可能直接由翻译调用返回: 用不属于该私有字体的密钥指定字体时的 FONT_AUTH_REQUIRED(401),以及字体加载失败时的 FONT_RESOLVE_ERROR(500)。

AliExpress 错误

代码状态含义
ITEM_NOT_FOUND404商品在平台上不存在
PROHIBITED_COUNTRY403无法配送到所请求的国家
TOKEN_EXPIRED503AliExpress 暂时不可用,请稍后重试

如果 AliExpress 返回了自身的错误编号,它会出现在响应体的 upstreamCode 字段以及 X-Apinoa-Upstream-Code 响应头中。

错误处理

重试策略

对于临时性错误(UPSTREAM_* 系列、SERVICE_UNAVAILABLETOKEN_EXPIRED),建议实现指数退避重试。 对于 CAPACITY_SATURATEDMARKETPLACE_SATURATED,请按响应给出的 Retry-After 等待,而不要自行猜测:

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) {
      return response.json();
    }

    const error = await response.json();
    const code = error.error?.code;

    // 客户端错误不进行重试
    // INSUFFICIENT_BALANCE 不会自行恢复 —— 重试只会白白耗尽重试次数
    if (["INSUFFICIENT_BALANCE", "UNAUTHORIZED", "FORBIDDEN", "ACCOUNT_SUSPENDED", "INVALID_PARAMS",
         "ITEM_NOT_FOUND", "PRODUCT_NOT_FOUND"].includes(code)) {
      throw new Error(`${code}: ${error.error.message}`);
    }

    // 临时性错误使用指数退避重试
    if (attempt < maxRetries - 1) {
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }

  throw new Error("Max retries exceeded");
}
# 使用 curl 进行简单重试
for i in 1 2 3; do
  response=$(curl -s -w "\n%{http_code}" -X POST \
    https://gateway.apinoa.com/v1/aliexpress/search \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{"query": "phone case"}')

  http_code=$(echo "$response" | tail -1)

  if [ "$http_code" -eq 200 ]; then
    echo "$response" | head -1
    break
  fi

  sleep $((2 ** i))
done

本页内容