<!-- BEGIN:gaio-api-agent-rules -->
## API da Gaio

Este projeto chama a API pública da Gaio, em beta fechado, que não está nos seus dados de treino. Antes de escrever ou mudar código que a usa, leia https://gaio.social/developers/llms.txt e a página da tarefa. As rotas e os corpos estão em https://gaio.social/developers/openapi.yml: uma rota que não está lá não existe.

Base `https://api.gaio.social/v1`, JSON em snake_case, `Authorization: Bearer $GAIO_API_KEY`, só de servidor para servidor (sem CORS).

### Chave
- Leia a chave só da variável de ambiente `GAIO_API_KEY`, no servidor. Nunca a ponha em código, repositório, URL, código de navegador ou de app, log ou mensagem de erro, e mascare o cabeçalho `Authorization` nos logs de HTTP.
- Não peça a chave no chat: peça para exportarem `GAIO_API_KEY`.
- `GET /v1/me` mostra os escopos e a validade (`expires_at`) da chave.

### Efeitos reais
- Não há modo de teste. Enviar mensagem (`POST /v1/conversations/{id}/messages`), iniciar uma automação (`POST /v1/workflows/{id}/runs`), publicar, despublicar e excluir atingem pessoas e a conta de verdade. Não chame essas rotas para explorar nem em testes automatizados (simule a API), e peça confirmação a uma pessoa antes.
- Contatos e mensagens são dados pessoais: não os copie para logs, fixtures ou prompts.
- Envie `consent: true` em `POST /v1/contacts` só com o opt-in daquela pessoa registrado. Nunca fixe esse valor no código.

### Envios
- Sempre com `Idempotency-Key`: derivada do evento de negócio (`pedido-enviado:<id>`) ou um UUID guardado antes da primeira tentativa. Repita a mesma chave nas novas tentativas da mesma operação e nunca a gere dentro do laço de novas tentativas.
- Confira `reply_window.state` da conversa antes de enviar. `messaging_window_closed` e `template_required` não se resolvem repetindo.
- `outcome_unknown` (502, ou 409 com a mesma chave): o efeito pode ter acontecido, e repetir com a mesma chave devolve o mesmo erro. Não reenvie sozinho: confira as mensagens da conversa ou as execuções da automação e, na dúvida, deixe para uma pessoa.
- `idempotency_in_progress` (409) e `service_unavailable` (503): espere e repita com a mesma chave. `idempotency_key_reused` (422) é erro na geração da chave: não repita.

### Automações
- Monte o corpo pelo guia https://gaio.social/developers/automacoes.md, partindo dos exemplos dele, e pelo catálogo atual (`GET /v1/workflow-graph-schema`).
- Valide antes de salvar e de publicar: `POST /v1/workflows/validate` (só `channel`, `trigger` e `graph`; com `title` ou `description`, a resposta é 400) e `POST /v1/workflows/{id}/validate` (o rascunho salvo). Os `errors` impedem a publicação; leia também os `warnings`.
- No `PATCH`, envie o `ETag` da leitura em `If-Match` (sem ele, 428). `graph` e `trigger` substituem o valor inteiro. Em `412 version_conflict`, leia de novo e reaplique a mudança; nunca sobrescreva às cegas.
- Publique com `If-Match` igual ao `ETag` da validação do rascunho.
- Devolva como vieram os tipos de bloco e os campos que você não conhece. Mantenha o `id` dos botões e a ordem das opções de um `randomizer` que já rodou.

### Webhooks
- Monte o receptor pelo guia https://gaio.social/developers/webhooks.md.
- Confira o `Gaio-Signature` sobre o corpo cru, antes de interpretar o JSON: HMAC-SHA256 de `<t>.<corpo>` com o segredo inteiro (`whsec_…`), comparado em tempo constante com cada `v1`, e recuse um `t` a mais de 5 minutos. Leia o segredo de uma variável de ambiente, como a chave.
- Responda `2xx` em até 10 segundos e processe depois, por uma fila. Descarte os eventos repetidos pelo `id` e não conte com a ordem: quando ela importa, leia o recurso de novo pela API.
- Cadastrar um endpoint ou mudar a URL dele passa a enviar os dados da conta para aquele endereço: peça confirmação a uma pessoa antes.

### Erros e limites
- Decida pelo `context.code`, nunca pela `message` nem só pelo status. `401` e `403` sem `context` vêm do gateway: chave inválida ou conta sem acesso.
- Limites por conta, por minuto: leitura 120, escrita 60, envio 20. No `429`, espere o `Retry-After`; sem ele, use backoff exponencial com jitter.
- Listas usam cursor opaco e `limit` até 100, menos `GET /v1/webhooks`, que vem numa página só e não aceita `limit` nem `cursor`. Um parâmetro de consulta desconhecido dá `400`.
- A `/v1` só cresce: tolere campos, valores de enumeração e códigos de erro novos.

Para atualizar, troque o que está entre os marcadores pelo conteúdo de https://gaio.social/developers/AGENTS.md.
<!-- END:gaio-api-agent-rules -->
