# API 错误及其含义

Source: https://help.didit.me/zh/integration/api-errors
Updated: 2026-10-12

先读响应体：401 是密钥问题，403 是权限或环境问题，404 常是应用不对，429 是速率限制，余额错误则与额度而非状态码有关。

**先读响应体。** Didit 的错误会附带一条消息，通常还有一个说明真实问题的详情代码，
因为状态码本身很少能充分说明情况。
401 是密钥问题，403 是权限或环境问题，429 是速率限制，余额错误则与额度而非代码有关。

## 先阅读响应体

HTTP 状态码告诉你问题的类别。
**响应体**告诉你实际发生了什么。
在 API 集成中，几乎所有可以避免的调试时间，都花在了猜测状态码上，而答案其实就在那个被丢弃的响应体里。

![Didit 控制台中的 API 密钥页面，显示密钥状态和最近一次使用情况](https://help.didit.me/screenshots/api-keys-light.webp)

*大多数 401 和 403 错误的答案都在这个页面上。*

在每个环境中，对每一次失败的调用，都要记录完整的错误响应体，包括状态码、请求头和负载。
你之后会用到它，而且事后重建要困难得多。

## 每种状态码通常代表什么

| 状态码 | 常见原因 |
|---|---|
| **400** | 请求格式错误：缺少必填字段、枚举值不正确、嵌套对象结构错误 |
| **401** | 认证失败。`x-api-key` 请求头缺失、格式错误，或不是有效的密钥 |
| **403** | 已认证但不被允许。环境错误、密钥没有该权限，或账户未启用该功能 |
| **404** | 资源不存在，或存在于与你所用密钥不同的应用下 |
| **409** | 与现有状态冲突，例如某个操作已经执行过 |
| **422** | 请求格式正确，但取值不可接受：这是校验失败而非语法失败 |
| **429** | 触发速率限制。详见下文 |
| **5xx** | Didit 一侧的问题。请使用退避重试，并查看 [status.didit.me](https://status.didit.me) |

## 401 与 403 的区别：能帮你省时间

**401** 表示密钥完全没有被接受。
请检查是否发送了 `x-api-key`，其值是否包含多余的空格或引号，以及你是否误把 webhook 签名密钥当成了 API 密钥粘贴进去。这是两个不同的东西，也是常见的错误。

**403** 表示密钥有效，但这次调用不被允许。按可能性排序，有三个原因：

1. **环境不匹配。** 仅限沙盒使用的字段（例如 `sandbox_scenario`）在正式应用上会被拒绝，反之亦然。正式环境和沙盒是两个独立的应用，拥有各自的密钥。
2. **缺少权限。** 部分操作需要你的密钥或角色不具备的权限。如果你需要会话创建和管理权限但目前没有，这应该向支持团队提出请求，而不是修改代码。
3. **功能未启用。** 部分能力是按组织开通的。如果你认为自己应该拥有某个功能却收到 403，值得先询问一下，再重写调用逻辑。

> **Tip:** 没有内置的方式能通过外观分辨沙盒密钥和正式密钥，因此请在你的密钥管理工具中用清晰不同的名称存储它们，
> 永远不要让一个环境变量保存"当前用的那个密钥"。
> 在测试环境中使用正式密钥会消耗真实额度。

## 404 但资源明明应该存在

如果一个会话或工作流返回 404，而你确定它是存在的，通常的答案是它存在于**另一个应用**下，而不是你用来认证的那个密钥所属的应用。
资源是按应用划分的；应用 A 的密钥看不到应用 B 的会话。

## 余额和额度错误

因额度不足而失败的调用，不是代码问题。
你本月的套餐额度和余额无法覆盖工作流中的某项检查。
这是迄今为止最常见的"API 坏了"报告，其原因通常是白标、AML 或 NFC 增加了工作流的价格，或者是免费套餐上的手机验证，因为免费套餐额度不能支付它。
参见[修复"额度不足"错误](https://help.didit.me/zh/billing-credits/not-enough-credits)。

## 429 速率限制

限制按**标识符**应用：你的 `x-api-key`，或在未发送密钥时按客户端 IP，每个作用域在 60 秒滑动窗口内都有独立的计数器。

全局默认值：

| 作用域 | 方法 | 限制 |
|---|---|---|
| 通用读取 | `GET` | 600 次/分钟 |
| 通用写入 | `POST`、`PATCH`、`DELETE` | 300 次/分钟 |

部分高影响端点在全局限制**之外**还有更严格的限制，先超出计数器的作用域会返回 429。
完整表格参见[速率限制](https://docs.didit.me/integration/rate-limiting)。

处理 429 时应使用带抖动的指数退避。
针对速率限制的密集重试循环只会让问题更严重，甚至可能让你被无限期限制。

> **Note:** 429 的常见来源是批处理任务，例如夜间导入任务在几秒内触发数百次创建请求。
> 应把任务分散执行，而不是不断提高并发直到不再报错。

## 功能级详情代码

除了 HTTP 状态码之外，各项独立检查还会针对提供方层面的问题返回自己的详情代码，例如某个注册表集成在某个国家没有访问某个产品的权限。
遇到详情代码时，它会精确说明具体情况，因此在咨询时请直接引用该代码。

如果响应中缺少了你从目录中预期会有的详情代码，这值得报告，而不是绕过它。缺失的代码是一个真实的缺口，也会让下一个人更难排查同样的问题。

## 空响应不等于成功

由提供方支持的检查如果返回空响应体，并不等同于一个干净的结果。
应在代码中把"无数据"当作独立的情况处理，而不是将其映射为通过，这一点对数据库验证和钱包筛查尤其重要，因为服务未开通和真正的无匹配从外部看起来可能很相似。

## 测试错误路径

沙盒会确定性地强制触发特定的失败，这是测试你的错误处理逻辑的唯一可靠方式。
参见[在沙盒中测试](https://help.didit.me/zh/getting-started/sandbox-and-testing)。
