API externa (chaves de API)
MangoStudio expõe a mesma API HTTP para sessões no navegador e para clientes de automação. Chamadas externas autenticam com chaves de API com escopo em vez de cookies.
Habilitar acesso
- Entre no app e abra Configurações → API externa.
- Ative Habilitar acesso à API externa (
externalApiSettings.enablednas configurações do app). Com o toggle desligado, todas as chaves do usuário são recusadas comEXTERNAL_API_DISABLED(403). - Crie uma chave: nome, escopo e expiração opcional. A chave em texto claro aparece uma vez na UI — copie imediatamente; ela não fica no cache de queries e não pode ser recuperada depois.
Gerenciar chaves (criar, listar, revogar) exige sessão por cookie. Chaves de API não podem gerenciar outras chaves.
Autenticação
Envie a chave em cada request:
x-api-key: mango_…
O Better Auth resolve a chave pelo mesmo caminho de sessão do navegador, então
rotas protegidas continuam com requireAuth sem um stack separado. Chaves nunca
funcionam em /api/auth/**.
Escopos
| Escopo | Métodos permitidos |
|---|---|
read-only |
GET, HEAD, OPTIONS |
full |
Todos os métodos permitidos |
Escrita ou exclusão com chave read-only retorna API_KEY_SCOPE_FORBIDDEN (403).
Descobrir endpoints
OpenAPI interativo em /scalar no host da API (mesma origem que /api). Use
para explorar rotas e schemas quando você tem cookie de sessão.
Para shapes de contrato, os schemas TypeBox em @mangostudio/shared são a fonte
da verdade; testes de integração frequentemente validam responses com
Value.Check.
Erros
Erros HTTP usam ApiErrorResponse de @mangostudio/shared/errors:
{ "error": "Mensagem legível", "code": "CODIGO_OPCIONAL" }
Envie Accept: application/problem+json para receber problem details da RFC
9457, com o mesmo status e o mesmo code. É opt-in e aditivo — nenhuma
integração existente precisa mudar. Veja
Formato Da Resposta De Erro para o contrato
completo.
Códigos comuns para tráfego de API externa:
| Código | Status típico | Significado |
|---|---|---|
EXTERNAL_API_DISABLED |
403 | Toggle do usuário desligado |
API_KEY_SCOPE_FORBIDDEN |
403 | Método não permitido para o escopo da chave |
RATE_LIMITED |
429 | Limite do bucket; veja Retry-After |
Rate limiting usa buckets separados para health, auth, navegador (general) e
tráfego com chave (api-key). Os contadores ainda são por IP dentro de cada
bucket hoje, então um pico com x-api-key não consome o contador general da
sessão no mesmo host (bucketing por chave está em #737). O teto do api-key
fica abaixo do general de propósito: um script faz os requests que pretende
fazer, enquanto o general precisa absorver o fan-out por página do navegador.
Notas de segurança
- A API escuta em
0.0.0.0por padrão. Fora de localhost, termine TLS no proxy reverso e definaTRUST_PROXY=trueapenas quando o proxy substitui headers de IP do cliente (vejadocs/pt-br/operations/deployment.md). - Chaves são armazenadas hasheadas no servidor; só o prefixo aparece na lista. Trate chaves em texto claro como senhas.
- Não commite chaves em git nem cole em logs públicos.
Exemplos
Substitua BASE e KEY pela origem da API e pela chave.
curl
export MANGO_API_KEY='mango_sua_chave_aqui'
export BASE='http://localhost:3001'
curl -sS -H "x-api-key: $MANGO_API_KEY" "$BASE/api/health"
curl -sS -H "x-api-key: $MANGO_API_KEY" "$BASE/api/chats"Bun
const base = process.env.BASE ?? 'http://localhost:3001';
const key = process.env.MANGO_API_KEY;
if (!key) throw new Error('Set MANGO_API_KEY');
const res = await fetch(`${base}/api/chats`, {
headers: { 'x-api-key': key },
});
console.log(res.status, await res.json());
Script de smoke
Na raiz do repo, com servidor de dev e chave válida:
MANGO_API_KEY='mango_…' bun run scripts/examples/external-api-smoke.ts http://localhost:3001