2

Como preparei uma API PHP para ser consumida nativamente pelo ChatGPT (e a batalha contra o CORS)

Fala, pessoal! Quero compartilhar um aprendizado técnico e uma dor de cabeça que resolvi recentemente enquanto construía a infraestrutura do meu projeto.

Eu estou desenvolvendo a ANX Dev, que é um hub de APIs para o mercado brasileiro (validação de documentos B2B, cálculo de dias úteis, etc). O modelo clássico todo mundo conhece: o dev pega o cURL, joga no código dele, bate no endpoint e segue a vida.

Mas nas últimas semanas, notei um padrão diferente: as pessoas não querem mais apenas integrar no código fonte delas, elas querem plugar a API direto em Agentes de IA (Custom GPTs, n8n, Make, LangChain). Fui tentar fazer minha API conversar nativamente com o ChatGPT através das Custom Actions. E foi aí que o problema começou.

1. O mapa para a IA: openapi.json

Para o ChatGPT (ou qualquer Agente) entender a API sozinho, não basta uma documentação humana. Você precisa de um arquivo openapi.json (usando a OpenAPI Specification 3.1.0) mapeando cada endpoint, os schemas de requisição e os códigos de erro. Até aí tranquilo, montei o schema. A IA leu os endpoints perfeitamente. Mas na hora de executar a chamada de teste... Erro de Conexão.

2. O Vilão Inesperado: CORS e o Preflight (OPTIONS)

Nós estamos acostumados a lidar com CORS quando o front-end (React/Vue/JS) tenta bater numa API hospedada em outro domínio. O que eu não sabia (e descobri na marra) é que o ChatGPT, ao testar as Actions no modo rascunho de criação, dispara as requisições pelo próprio browser do usuário antes de rodar diretamente nos servidores da OpenAI.

Ele manda uma requisição OPTIONS (Preflight) para checar as permissões. E a minha rota PHP estava interceptando esse OPTIONS e tentando processar como se fosse um GET, devolvendo erro 400 (porque, obviamente, a requisição preflight vem sem a API Key no Header).

A solução definitiva:
Tive que criar um "escudo" no topo da minha arquitetura PHP para responder aos preflights imediatamente com HTTP 200, matando o script antes mesmo de chegar na verificação de autenticação. O código final ficou assim:

*php
// Liberações de CORS necessárias para Agentes de IA
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

// O SEGREDO: Interceptar o Preflight (OPTIONS) e matar a execução com status 200
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
http_response_code(200);
exit();
}*

Só depois de incluir esse bloco, o ChatGPT conseguiu completar o handshake e consumir os dados reais com a chave de API no header Authorization.

O Resultado (Para quem quiser testar)
Para validar se a infraestrutura nova estava aguentando o tranco (e testar se o CORS estava realmente curado em qualquer ambiente), criei duas ferramentas gratuitas em cima dos meus próprios endpoints:

Gerador de CPF/CNPJ Válidos: Focado pra galera de QA. Ele gera documentos aleatórios que passam pela regra matemática exata do Módulo 11.

Calculadora de Dias Úteis: Pula finais de semana e devolve a data exata de SLAs (em breve vou plugar a base de feriados nacionais nela).

O Hub completo com o painel para gerar chaves de API (e o famigerado openapi.json liberado para vocês importarem nos GPTs de vocês) está em anxdev.com.br.

Alguém aqui já está criando Agentes no ChatGPT usando APIs próprias? Tiveram problemas com timeout da OpenAI nas respostas da API? Estou medindo a latência agora e adoraria trocar ideia com quem já passou por essa fase de otimização para IA!

Carregando publicação patrocinada...
1

parabéns brigrar com o cross é um ritual de passagem de todo dev. lembro até hoje dos meus primeiros projeto que davam erro e eu não sabia porque, mesmo a api funcionado no insominia, nada de funcionar no frontend...

agora é padrão em todo projeto incluir bloco basico

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

// O SEGREDO: Interceptar o Preflight (OPTIONS) e matar a execução com status 200
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
http_response_code(200);
exit();

você ainda pode se deparar com problemas com envio de cookies pra aprender a coloca credential:include em todo ajax tambem .

agora o curioso é saber que o agente faz a requisição direto do navegador do usuario, se ele fizesse internamente poderia ignorar os headers

um serviço gratuito que pode te salvar quando o problema de cross vem de uma api que você não controla é usar o https://www.cors-anywhere.com/

1

Realmente, apanhar do CORS pela primeira vez é um evento canônico na vida de qualquer dev hahaha. Aquele momento em que o Insomnia retorna 200 OK, mas o browser cospe um erro em vermelho no console é inesquecível. Sobre o envio de cookies e o credentials: include, excelente adição! No caso dessa infra da ANX Dev, como a autenticação é 100% stateless (apenas validação do Bearer Token no Header), acabamos não sofrendo com isso, mas para quem usa sessão/cookies no front, é batata. O detalhe do agente fazer a requisição no navegador é exatamente o maior "pegão" dessa integração com a OpenAI. Quando você publica o Custom GPT, as requisições partem dos IPs dos servidores deles (e aí eles não ligam pro CORS). Mas na tela de Preview/Draft (enquanto você está testando e montando o schema da Action), a chamada parte do seu próprio browser. Se a API não tratar o Preflight ali na hora, você simplesmente não consegue salvar e testar a integração.E o cors-anywhere é um clássico! Já me salvou muito no passado quando eu precisava consumir APIs engessadas de terceiros direto no front-end.

Valeu demais por agregar à discussão com essa visão técnica! Fica o convite para testar os endpoints gratuitos lá depois, e qualquer feedback é muito bem-vindo.