Agentes de IA já estão lendo os erros da sua API

Compartilhar

Em março, a Mintlify somou um mês de tráfego dos sites de documentação que hospeda. Deu cerca de 790 milhões de requisições, e 45,3% delas foram feitas por agentes de programação com IA. Os navegadores fizeram 45,8%. Só o Claude Code mandou um quarto de tudo (os números da Mintlify).

É tráfego para documentação, não para APIs. Mas os agentes que leem a documentação são os mesmos que depois escrevem a requisição, executam e leem o que voltar. Na pesquisa State of the API 2025 do Postman, 24% dos desenvolvedores disseram que já projetam APIs pensando em agentes. Quando saiu, parecia cedo. Não parece mais.

Quase tudo o que construímos aqui é sobre falha: endpoints que devolvem 500, travam ou param no meio de uma resposta. Então a pergunta que fazíamos era bem específica. Quando um agente recebe um erro da sua API, ele tem o suficiente para fazer a coisa certa em seguida?

Um agente leva sua mensagem de erro ao pé da letra

Um desenvolvedor que recebe {"error":"E4021"} procura o código, não acha nada e pergunta a um colega. Um agente não pode perguntar a ninguém. Ele trabalha com o corpo que você mandou, e se o corpo não diz nada útil, ele chuta: repete a mesma requisição ou muda um campo que estava certo.

Isto é o que o nosso endpoint de produtos diz quando o ID não existe:

Terminal
$ curl -i https://api.testingapis.com/api/Products/99999
HTTP/1.1 404 Not Found
content-type: application/json; charset=utf-8

{"status":404,"error":"Not Found","message":"Product with ID 99999 does not exist."}

É uma frase sem graça, e tudo bem. Ela cita o recurso e o ID, então quem ler, pessoa ou programa, sabe que o problema é o ID e que mandar de novo não vai adiantar.

Se você quer um formato padrão para erros, a RFC 9457 (Problem Details for HTTP APIs) define type, title, status, detail e instance, servidos como application/problem+json. Ela substituiu a RFC 7807 em 2023. Não achamos que o formato exato importe muito. O que importa é ter uma frase clara em algum lugar.

Diga quanto tempo esperar

Agentes tentam de novo. Se o seu 429 ou 503 não diz quanto esperar, o cliente precisa escolher um número, e um agente trabalhando numa tarefa em loop vai continuar escolhendo. O Retry-After faz parte do HTTP há décadas e resolve isso com um cabeçalho:

Terminal
$ curl -i https://api.testingapis.com/api/status/429
HTTP/1.1 429 Too Many Requests
content-type: application/json; charset=utf-8
retry-after: 5

{"status":429,"statusText":"Too Many Requests","category":"client-error","message":"This is a 429 response. Use /api/status/{code} to request any status."}
GET/api/status/429

A IETF também está trabalhando nos cabeçalhos RateLimit e RateLimit-Policy, que deixam o cliente ver sua cota antes de acabar, e não depois. O rascunho 11 saiu em maio. A sintaxe é assim:

Cabeçalhos
RateLimit-Policy: "default";q=100;w=60
RateLimit: "default";r=50;t=30

Isso se lê como "100 requisições a cada 60 segundos, faltam 50, a janela reinicia em 30". Ainda é um rascunho, então não tiraríamos os cabeçalhos X-RateLimit-* que seus clientes já leem. Mandar os dois custa muito pouco.

Retries criam duplicatas

Repetir um GET não faz mal. Repetir um POST faz, se a primeira tentativa chegou ao servidor e só a resposta se perdeu. Você acaba com dois pedidos. Uma pessoa costuma perceber a cobrança dupla. Um agente vê que a segunda tentativa deu certo e segue em frente.

A solução de sempre é uma chave de idempotência. O cliente envia um cabeçalho Idempotency-Key único com a escrita e, se a mesma chave chegar de novo, o servidor devolve o primeiro resultado em vez de fazer o trabalho duas vezes. A Stripe funciona assim há anos, e existe um rascunho da IETF para o cabeçalho, embora ainda não seja uma RFC. Se a sua API recebe pagamentos ou cria algo chato de limpar, vale a pena adicionar antes que os agentes comecem a chamá-la.

Servidores MCP estão virando APIs HTTP comuns

Muitos agentes não vão chamar sua API REST diretamente. Vão passar por um servidor MCP que a envolve. A especificação do MCP lançada em 28 de julho removeu o handshake de sessão e o cabeçalho Mcp-Session-Id. Cada requisição agora leva a própria versão do protocolo e os dados do cliente, e os nomes do método e da ferramenta viajam em cabeçalhos HTTP, então um gateway pode rotear e limitar requisições sem analisar o corpo.

O resultado é que um servidor MCP agora se comporta como qualquer outro serviço HTTP sem estado. Ele pode ficar atrás de um balanceador de carga comum, e os conselhos acima valem para ele do jeito que estão. Quando uma chamada de ferramenta falha, o agente precisa de um motivo e de um tempo de espera do seu servidor MCP, assim como da sua API.

Uma verificação rápida

Este é o script que rodamos enquanto escrevíamos. Ele manda quatro requisições que falham e verifica duas coisas em cada uma: existe um motivo que um programa consegue ler, e existe um Retry-After?

check-errors.mjs
// For each failure: is there a reason a program can read, and a time to wait?
const BASE = "https://api.testingapis.com";

const cases = [
  ["missing product", "/api/Products/99999"],
  ["rate limited", "/api/status/429"],
  ["server down", "/api/Products/1?error=503"],
  ["bad request", "/api/status/400"],
];

for (const [name, path] of cases) {
  const res = await fetch(BASE + path);
  const body = await res.json().catch(() => ({}));
  const reason = body.message ?? body.detail ?? body.title;
  const wait = res.headers.get("retry-after");
  console.log(
    name.padEnd(16),
    res.status,
    reason ? "reason: yes" : "reason: NO ",
    wait ? `retry-after: ${wait}s` : "retry-after: -",
  );
}
Saída (Node 24, 9 de outubro de 2026)
missing product  404 reason: yes retry-after: -
rate limited     429 reason: yes retry-after: 5s
server down      503 reason: yes retry-after: -
bad request      400 reason: yes retry-after: -

Toda resposta tem um motivo, o que é bom. Mas olhe a terceira linha. /api/status/503 manda Retry-After: 5, e ?error=503 num endpoint real não manda nada. Um cliente testado contra ele nunca aprenderia quando tentar de novo. Esse está na nossa lista.

Aponte o mesmo script para os caminhos de falha da sua própria API. Se você não consegue fazer sua API falhar quando quer, o guia de respostas de erro mostra como obter da nossa um 500, um 429, um timeout ou um corpo truncado.

Nada disso é conselho novo. Mensagens de erro claras e Retry-After eram boas ideias muito antes de alguém construir um agente. O que mudou é que uma pessoa confusa acaba mandando um e-mail, e um agente simplesmente tenta de novo.