Agentes de IA já estão lendo os erros da sua API
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:
$ 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:
$ 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."}/api/status/429A 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:
RateLimit-Policy: "default";q=100;w=60
RateLimit: "default";r=50;t=30Isso 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?
// 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: -",
);
}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.