Fazer a primeira chamada na APIBrasil leva cinco minutos. Deixar a integração robusta em produção exige conhecer alguns comportamentos que fogem do padrão REST e que, se ignorados, fazem o código funcionar no caminho feliz e falhar em silêncio no resto.
A própria documentação da APIBrasil, na aba Instruções para IA de cada endpoint em doc.apibrasil.io, lista essas armadilhas. Neste guia reunimos todas elas e montamos um cliente TypeScript reutilizável para qualquer API do catálogo.
Armadilha 1: o erro chega no corpo, com HTTP 200
A resposta da APIBrasil traz um campo error (booleano) e uma message. Uma consulta pode falhar e mesmo assim devolver HTTP 200. Se o seu código checa só response.ok, ele vai tratar a falha como sucesso e tentar ler um data que não existe.
Regra: valide em duas etapas, primeiro o status HTTP e depois error === false. As duas precisam passar.
Armadilha 2: saldo e custo são texto em formato brasileiro
Os campos balance, tax e extra_charges.total chegam como string, e o formato varia entre APIs. A documentação cita valores como "154,380", "497,84", "0,000" e "0.19": vírgula em umas, ponto em outras, duas ou três casas decimais.
Em JavaScript, parseFloat("154,380") devolve 154 e perde os centavos sem erro nenhum, e Number("154,380") devolve NaN. Use um conversor próprio:
export function valorBR(v: string | number | null | undefined): number {
if (v === null || v === undefined || v === "") return 0;
if (typeof v === "number") return v;
const s = v.trim();
// Com vírgula: vírgula é o decimal e ponto é milhar ("1.234,56").
if (s.includes(",")) return Number(s.replace(/\./g, "").replace(",", "."));
return Number(s); // "0.19"
}

Armadilha 3: cada chamada custa dinheiro
Retry cego multiplica a conta. A regra da documentação é clara:
- Nunca repita automaticamente um 4xx. Parâmetro errado repetido continua errado e continua cobrando.
- Repita só tempo esgotado e 5xx, com recuo exponencial e um teto pequeno de tentativas.
Armadilha 4: HTTP 402 é saldo insuficiente
O 402 é o único status que exige ação humana: recarregar a conta em app.apibrasil.io/recargas. Trate como erro terminal, com mensagem própria, e não junto com os outros 4xx. É um ótimo gatilho para um alerta no Slack ou por e-mail.
Armadilha 5: extra_charges é cobrado à parte
Quando o corpo pede serviços adicionais, a resposta traz cada um com o preço e um total que não está incluído no valor base da consulta. Se você mostra o custo para o usuário ou repassa ao cliente, some os dois.
O cliente TypeScript completo
Com as cinco regras em mente, este é um cliente genérico que serve para qualquer API do catálogo:
import { valorBR } from "./valores";
const BASE = "https://gateway.apibrasil.io/api/v2/";
export class SaldoInsuficiente extends Error {}
export class ErroAPIBrasil extends Error {
constructor(msg: string, public http?: number) { super(msg); }
}
export interface RespostaAPIBrasil<T> {
error: boolean;
message: string;
balance: string;
tax: string;
valor_consulta: number;
api_limit_for: "credit" | "homolog" | string;
homolog?: boolean;
data: T;
extra_charges?: { total?: string };
}
const HOMOLOG = process.env.APIBRASIL_HOMOLOG !== "false";
const espera = (ms: number) => new Promise((r) => setTimeout(r, ms));
export async function apibrasil<T>(
rota: string,
corpo: Record<string, unknown>,
{ tentativas = 3, timeoutMs = 120_000 } = {}
): Promise<RespostaAPIBrasil<T> & { custoTotal: number; saldo: number }> {
const payload = { homolog: HOMOLOG, ...corpo };
for (let t = 1; t <= tentativas; t++) {
const inicio = Date.now();
let res: Response;
try {
res = await fetch(BASE + rota, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.APIBRASIL_TOKEN}`,
},
body: JSON.stringify(payload),
signal: AbortSignal.timeout(timeoutMs),
});
} catch (e) {
// Timeout ou falha de rede: pode repetir.
if (t === tentativas) throw e;
await espera(2 ** (t - 1) * 1000);
continue;
}
if (res.status === 402) throw new SaldoInsuficiente("Saldo insuficiente: recarregue a conta");
if (res.status >= 500) {
if (t === tentativas) throw new ErroAPIBrasil(`HTTP ${res.status}`, res.status);
console.warn(JSON.stringify({ api: rota, http: res.status, tentativa: t }));
await espera(2 ** (t - 1) * 1000);
continue;
}
if (res.status >= 400) {
// 4xx: não repita, corrija a chamada.
throw new ErroAPIBrasil(`HTTP ${res.status}: ${await res.text()}`, res.status);
}
const body = (await res.json()) as RespostaAPIBrasil<T>;
if (body.error) throw new ErroAPIBrasil(body.message || "Erro na consulta", res.status);
const custoTotal = valorBR(body.tax) + valorBR(body.extra_charges?.total);
const saldo = valorBR(body.balance);
console.info(JSON.stringify({ api: rota, http: res.status, error: false, tax: custoTotal, balance: saldo, ms: Date.now() - inicio }));
return { ...body, custoTotal, saldo };
}
throw new ErroAPIBrasil("Não foi possível concluir a chamada");
}
E o uso fica simples, para qualquer API:
const r = await apibrasil<{ cnpj: { nome_fantasia: string } }>("dados/cnpj/credits", {
tipo: "cnpj",
cnpj: "44959669000180",
});
console.log(r.data.cnpj.nome_fantasia, "custou", r.custoTotal);

Homologação: ligada por padrão fora de produção
O campo homolog: true faz a APIBrasil responder com dados válidos, api_limit_for: "homolog" e sem tarifação. O cliente acima já lê isso de APIBRASIL_HOMOLOG, com homologação ligada por padrão. Assim, uma suíte de testes esquecida rodando na CI não gasta saldo real.
| Ambiente | APIBRASIL_HOMOLOG |
|---|---|
| Desenvolvimento local | true (padrão) |
| CI / testes automatizados | true |
| Homologação do cliente | true |
| Produção | false |
Mais práticas que fazem diferença
- Token só no back-end. Nunca chame a APIBrasil direto do navegador ou do app: o Bearer Token ficaria exposto. Veja como proteger tokens com variáveis de ambiente.
- Cache inteligente. CNPJ, CEP e FIPE mudam pouco. Um cache de horas ou dias corta boa parte do custo.
- Timeout generoso. A documentação usa
--max-time 120nos exemplos. Algumas consultas dependem de fontes externas e podem demorar. - Validação local antes da chamada. Dígitos do CPF e do CNPJ, formato de placa e CEP: tudo isso dá para conferir sem gastar.
- Alerta de saldo. Com o
saldojá convertido em número, dispare um alerta quando cair abaixo de um limite. - Consultas assíncronas para volume. O catálogo tem uma categoria de Consultas Assíncronas, e as APIs de mensageria aceitam o sufixo
/queuepara enfileirar envios em lote.
Use as Instruções para IA a seu favor
Cada endpoint em doc.apibrasil.io tem a aba Instruções para IA, com a especificação completa do endpoint, as armadilhas e os requisitos de implementação. Cole esse texto no seu assistente de código (Claude, Cursor, Copilot) e peça o cliente na linguagem do seu projeto: ele já vem com as regras deste artigo. Se preferir que o assistente chame as APIs diretamente, veja o MCP da APIBrasil.
Checklist antes de ir para produção
- Validação em duas etapas: status HTTP e campo
error. balance,taxeextra_charges.totalconvertidos com função própria.- Retry só em timeout e 5xx, com recuo exponencial e teto.
- 402 tratado à parte, com alerta.
homologconfigurável e ligado por padrão fora de produção.- Token em variável de ambiente, só no back-end.
- Log estruturado com custo e saldo.
Próximos passos
Aplique o cliente nos tutoriais da série: consulta de CNPJ com Python, placa com valor FIPE em Node.js e verificação por SMS OTP.
![]()









