错误码
API 的 HTTP 状态码遵循标准 REST 约定。请根据 HTTP 状态码 决定处理方式,错误信息只用于记录日志或展示。
错误结构
错误有两种格式。大多数错误 以带 message 的对象形式返回 error:
{
"success": false,
"data": null,
"error": {
"message": "CPF não encontrado na base de dados"
}
}身份认证和账户相关错误 以 字符串 形式返回 error:401、账户停用或封禁时的 403、余额为零时提交批量查询返回的 403 "Limite de créditos excedido"(积分额度已超出)、500 "Erro ao validar assinatura"(订阅校验出错)以及 503 "usage_unavailable"。标准查询和实时查询中因积分不足返回的 403 为对象格式。
{
"success": false,
"error": "API Key não fornecida"
}兼容两种格式读取错误信息:typeof body.error === 'string' ? body.error : body.error?.message。
以 HTTP 状态码为准
请根据 HTTP 状态码决定如何处理错误。错误信息为葡萄牙语,用于记录日志和展示,请不要在代码中比对文本。下文括号内的中文释义仅供参考。
完整参考
2xx:成功
| 状态码 | 信息 | 说明 |
|---|---|---|
200 OK | 无 | 查询成功。结果在 data 字段中。 |
202 Accepted | 无 | 仅限批量查询:批次已受理,等待处理。 |
4xx:客户端错误
| 状态码 | 信息 | 说明 |
|---|---|---|
400 Bad Request | CPF inválido. Deve conter 11 dígitos.(CPF 必须为 11 位数字) | 去除格式后 CPF 不是 11 位数字。 |
400 Bad Request | Data de nascimento inválida. Use o formato DD/MM/YYYY ou DDMMYYYY(出生日期有误,请使用 DD/MM/YYYY 或 DDMMYYYY 格式) | 仅限实时查询:birthDate 缺失或无效。 |
400 Bad Request | Campo 'cpfs' deve ser um array não vazio.(cpfs 字段必须是非空数组) | 仅限批量查询:cpfs 缺失、为空或不是数组。 |
400 Bad Request | Limite de 10000 CPFs por lote excedido.(超出每批 10,000 个 CPF 的上限) | 仅限批量查询:CPF 超过 10,000 个。 |
400 Bad Request | CNPJ inválido. Formato ou dígito verificador incorreto.(CNPJ 无效,格式或校验位错误) | 仅限 CNPJ 查询。不消耗积分。 |
400 Bad Request | Campo 'cnpjs' deve ser um array não vazio. 或 Limite de 10000 CNPJs por lote excedido. | 仅限 CNPJ 批量查询:cnpjs 缺失、为空、不是数组或超过 10,000 项。 |
401 Unauthorized | API Key não fornecida(未提供 API 密钥) | 缺少 x-api-key 请求头。error 为字符串。 |
401 Unauthorized | API Key inválida(API 密钥无效) | API 密钥不存在。error 为字符串。 |
401 Unauthorized | API Key inativa(API 密钥已停用) | 该 API 密钥已在控制台中被新密钥替换。error 为字符串。 |
403 Forbidden | Limite de créditos excedido(积分额度已超出) | 在未开通超额用量的套餐中,余额低于查询费用。标准查询和实时查询中 error 为对象。提交批量查询时如果余额连一次查询都不够,error 为字符串。CNPJ 查询中通常为字符串,请兼容两种格式。 |
403 Forbidden | Créditos insuficientes para o lote: N necessários.(批次积分不足:需要 N 个) | 仅限批量提交(CPF 或 CNPJ):在未开通超额用量的套餐中,余额不足以覆盖列表中所有有效证件号。 |
403 Forbidden | Usuário inativo. Entre em contato com o suporte.(用户已停用,请联系支持团队) | 账户已停用。error 为字符串。 |
403 Forbidden | Conta bloqueada. Entre em contato com o suporte.(账户已封禁,请联系支持团队) | 账户已封禁。error 为字符串。 |
404 Not Found | CPF não encontrado na base de dados(数据库中未查到该 CPF) | 仅限标准查询。不消耗积分。 |
404 Not Found | CNPJ não encontrado na base de dados(数据库中未查到该 CNPJ) | 仅限 CNPJ 查询。不消耗积分。 |
404 Not Found | Lote não encontrado.(未找到批次) | 仅限批次状态查询(CPF 或 CNPJ):jobId 不存在,或由其他 API 密钥创建。少数内部故障时也会出现,因此在判定批次不存在前请重试一次。 |
422 Unprocessable Entity | CPF inválido. Dígito verificador incorreto.(校验位错误) | CPF 未通过校验位的数学校验。 |
422 Unprocessable Entity | Nenhum CPF válido na lista enviada.(提交的列表中没有有效 CPF) | 仅限批量查询:列表中没有任何有效 CPF。 |
422 Unprocessable Entity | Nenhum CNPJ válido na lista enviada.(提交的列表中没有有效 CNPJ) | 仅限 CNPJ 批量查询:列表中没有任何有效 CNPJ。 |
422 Unprocessable Entity | Receita Federal 返回的信息 | 仅限实时查询:Receita Federal(巴西联邦税务局)拒绝了查询,例如出生日期不匹配。不消耗积分。 |
429 Too Many Requests | Limite de requisições por minuto excedido. Tente novamente em N segundos.(超出每分钟请求限制,请 N 秒后重试) | 超出了标准查询、实时查询、CNPJ 查询(与标准查询共用限制)或批量提交的每分钟限制。响应包含 Retry-After 请求头。不消耗积分。 |
429 Too Many Requests | Limite de N lotes pendentes por cliente excedido.(超出每个客户 N 个待处理批次的上限) | 仅限 CNPJ 批量提交:处理中的批次过多。响应包含 Retry-After: 60。请等待之前的批次完成。 |
429 Too Many Requests | Este CPF foi consultado repetidas vezes em sequência pela mesma chave. Novas consultas dele estão bloqueadas temporariamente para não consumir seus créditos. Verifique se sua integração está em loop. As consultas de outros CPFs seguem normais.(同一密钥连续多次查询了该 CPF) | 重复查询保护:同一密钥在 10 分钟内查询同一 CPF 达 20 次。仅适用于标准查询(GET /cpf/{cpf}),不适用于实时查询、CNPJ 查询或批量查询。封锁是临时的。不消耗积分。 |
不存在的路由会返回 404 和纯文本 NOT_FOUND,不带 JSON。将响应体按 JSON 解析前,请先检查 Content-Type。
5xx:服务器错误
| 状态码 | 信息 | 说明 |
|---|---|---|
500 Internal Server Error | Erro ao validar assinatura(订阅校验出错) | 读取套餐信息时发生内部故障。error 为字符串。 |
500 Internal Server Error | Banco de dados indisponível(数据库不可用) | 标准查询发生内部故障。 |
500 Internal Server Error | Falha ao criar lote.(创建批次失败) | 仅限批量提交(CPF 或 CNPJ):无法创建批次。 |
502 Bad Gateway | Falha ao interpretar a resposta da Receita Federal.(无法解析 Receita Federal 的响应) | 仅限实时查询。不消耗积分。 |
502 / 503 | A Receita Federal não respondeu a tempo. Tente novamente em alguns segundos. Nenhum crédito foi cobrado.(Receita Federal 未及时响应,请几秒后重试,未扣除积分) | 仅限实时查询。不消耗积分。 |
502 / 503 | A Receita Federal está com alta demanda agora. Tente novamente em alguns segundos. Nenhum crédito foi cobrado.(Receita Federal 当前请求量较大,请几秒后重试,未扣除积分) | 仅限实时查询。不消耗积分。 |
503 Service Unavailable | Não foi possível reservar os créditos. Tente novamente.(无法预留积分,请重试) | 为查询预留积分时发生内部故障。不消耗积分。 |
503 Service Unavailable | Falha ao registrar validação(记录查询失败) | 保存查询记录时发生内部故障。不消耗积分。 |
503 Service Unavailable | cnpj_unavailable | 仅限 CNPJ 查询:CNPJ 数据库暂时不可用。不消耗积分。请按递增间隔重试。 |
503 Service Unavailable | usage_unavailable | 无法查询积分余额。不消耗积分。 |
余额不可用时的 503 以字符串形式返回 error,并附带 message 字段:
{
"success": false,
"error": "usage_unavailable",
"message": "Não foi possível verificar o saldo de créditos. Tente novamente."
}错误处理示例
const res = await fetch(`https://api.cpfhub.io/cpf/${cpf}`, {
headers: { 'x-api-key': process.env.CPFHUB_API_KEY! },
signal: AbortSignal.timeout(10_000),
})
const isJson = res.headers.get('content-type')?.includes('application/json')
const body = isJson ? await res.json() : null
if (res.ok) {
console.log(body.data.name)
} else {
// error is a string in some errors and an object { message } in the rest
const message = typeof body?.error === 'string' ? body.error : body?.error?.message
switch (res.status) {
case 404:
// CPF not found: no credit used
break
case 400:
case 422:
// Bad input: fix it, do not retry
break
case 401:
case 403:
// Bad key, no credits left or blocked account: do not retry
throw new Error(message)
case 429:
// Per-minute limit: wait Retry-After seconds and retry
await new Promise(r => setTimeout(r, Number(res.headers.get('retry-after') ?? 5) * 1000))
break
default:
// 5xx: retry with backoff (see the table below)
throw new Error(message ?? `HTTP ${res.status}`)
}
}import os, time, requests
res = requests.get(
f"https://api.cpfhub.io/cpf/{cpf}",
headers={"x-api-key": os.environ["CPFHUB_API_KEY"]},
timeout=10,
)
is_json = "application/json" in res.headers.get("content-type", "")
body = res.json() if is_json else {}
if res.ok:
print(body["data"]["name"])
else:
error = body.get("error")
message = error if isinstance(error, str) else (error or {}).get("message")
if res.status_code == 404:
print("CPF not found")
elif res.status_code == 429:
time.sleep(int(res.headers.get("retry-after", "5"))) # then retry
elif res.status_code >= 500:
pass # retry with backoff
else:
raise RuntimeError(message)重试
| 状态码 | 是否重试 | 方式 |
|---|---|---|
429 | 是 | 等待 Retry-After 请求头给出的时间 |
GET 请求(标准查询、批次状态、余额)返回的 500、502、503 | 是,最多 3 次 | 退避间隔:1 秒、2 秒、4 秒 |
POST /cpf/realtime 返回的 502、503 | 是,最多 3 次 | 退避间隔:2 秒、4 秒、8 秒 |
400、401、403、404、422 | 否 | 修正输入、密钥或余额 |
POST 请求不是幂等的
POST /cpf/realtime 和 POST /cpf/bulk 不支持幂等键。如果连接中断或在收到响应前触发了超时,查询可能已完成并计费,批次也可能已创建。重试前,请先用 GET /quota 查看余额,如果是批量查询,还要在控制台查看最近的提交记录。只有在收到 429、502 或 503 时,才可以不经检查直接重试。
不消耗积分的测试
以下状态码不消耗积分:400、401、404、422 和 429。您可以免费测试错误处理逻辑:
| 测试项 | 请求 | 响应 |
|---|---|---|
| CPF 少于 11 位 | GET /cpf/123 | 400 |
| 校验位错误 | GET /cpf/11111111111 | 422 |
| 出生日期无效 | POST /cpf/realtime,请求体为 {"cpf":"12345678909","birthDate":"1990-06"} | 400 |
| 未提供 API 密钥 | 任意路由,不带 x-api-key 请求头 | 401 |
| 账户余额 | GET /quota | 200,始终免费 |
200响应会消耗积分。免费版 提供 50 个积分,可用于测试成功路径。- 示例中的 CPF
12345678909是虚构的。测试成功响应时,请使用已获得持有人授权查询的 CPF。
更新于 2026 年 10 月 15 日