Autenticação
Toda requisição usa uma chave de API no cabeçalho Authorization. As chaves podem ter acesso total ou só de envio, e ser restritas a um domínio.
#Chave de API
Toda requisição precisa de uma chave de API no cabeçalho Authorization, no formato Bearer:
Authorization: Bearer ps_4Fq9xLmT2vKp8sWd1Yc5Hf3Lz9Ag6Ej0Qm8rBnX
As chaves começam com ps_. Crie em Chaves de API no painel, ou pela API com POST /api-keys. O token completo aparece uma única vez, na criação: a Postal guarda só o hash e os primeiros caracteres (token_start), para você reconhecer a chave na lista.
cURL
curl https://api.postal.so/domains \
-H "Authorization: Bearer $POSTAL_API_KEY"
Node.js
const response = await fetch('https://api.postal.so/domains', {
headers: {
Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
},
});
const data = await response.json();
Python
import os
import requests
response = requests.get(
"https://api.postal.so/domains",
headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
timeout=10,
)
data = response.json()
PHP
$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);
$response = $client->get('domains', [
'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);
$data = json_decode($response->getBody(), true);
#Permissões
| Permissão | O que pode fazer |
|---|---|
full_accessAcesso total | Toda a API: envio, domínios, templates, webhooks, logs, chaves… |
sending_accessSó envio | Enviar: POST /emails, POST /emails/batch, POST /events e o SMTP.Consultar: o status e os eventos dos e-mails que ela mesma enviou, por API ou SMTP ( GET /emails/{id}; os e-mails de outras chaves ou do painel respondem 404), e o plano, as cotas e o limite de requisições em GET /usage. Todo o resto pede acesso total.Pode ser restrita a um domínio ( domain_id): aí só envia com remetentes desse domínio. |
Criar chaves só de envio ou restritas a um domínio depende do plano (restricted_api_keys); o número de chaves também (api_keys). Veja Limites.
Use chaves só de envio nos sistemas que apenas disparam e-mails ou eventos (o checkout, o WordPress, o ERP) e reserve as de acesso total para automações de infraestrutura. Se uma chave de envio vazar, ela não muda sua configuração nem lê seus contatos, domínios ou os e-mails de outras chaves: só vê o que ela mesma enviou e os limites do plano.
#Erros de autenticação
| Status | Nome | Quando acontece |
|---|---|---|
401 | missing_api_key | Faltou o cabeçalho Authorization. |
403 | invalid_api_key | A chave não existe, foi excluída ou não começa com ps_. |
401 | restricted_api_key | Uma chave só de envio tentou usar outro endpoint (ela pode enviar, ler os e-mails que enviou com GET /emails/{id} e chamar GET /usage). |
403 | restricted_api_key | Uma chave restrita a um domínio tentou enviar de outro domínio. |
403 | paused_by_plan | A chave passou do limite de chaves do plano atual e foi pausada (paused_by_plan: true em GET /api-keys). Ela não autentica até o plano ou a contagem permitirem de novo; veja Limites. |
403 | team_suspended | A conta foi suspensa pela plataforma que a gerencia. |
#Idioma das mensagens e origem das mudanças
Duas escolhas opcionais por requisição:
Accept-Language: pt-BR(ouen) escolhe o idioma damessagedos erros e dos outros textos que a API escreve para a sua requisição (veja a tabela abaixo). Sem o cabeçalho, vem em inglês. Onameé sempre o mesmo.X-Postal-Source: erpdá um rótulo às mudanças que a chave faz nos contatos. O rótulo aparece emsourcenos webhooks de contato e emlast_change_sourcedo contato, e permite que um webhook ignore o que o próprio sistema fez.
O idioma de cada texto que a Postal escreve depende de para quem ele é:
| Texto | Idioma |
|---|---|
| Os textos das respostas da API | A message dos erros, os rótulos (como o label de paused em GET /usage), o sending.reason do mesmo endpoint, o diagnostic dos registros DNS do domínio, o sufixo dos nomes de cópias (“(copy)” ou “(cópia)”), o prefixo [Test] ou [Teste] do teste de campanha e do teste de template e o “Other:” ou “Outro:” dos CSV de respostas de formulário. Seguem o Accept-Language da requisição (pt-BR ou en, o primeiro que a Postal conhece). Com chave de API ou sem credenciais, sem o cabeçalho vêm em inglês; GET /plans, que é público, vem em português sem ele. |
| Texto da IA do diagnóstico | POST /ai/emails/{id}/fix-insights: o parâmetro language (pt-BR, en ou es); sem ele, o idioma da requisição. |
| Webhooks de pausa | O reason sai no idioma do time, o que o dono escolheu no painel; em inglês enquanto ele não escolhe. O reason_code não depende de idioma. |
| Rodapé de descadastro e página de preferências | O idioma de cada destinatário: language da campanha, propriedades do contato, idioma do time. Veja Idioma do rodapé e da página. |
| Formulários públicos e e-mail de confirmação | settings.language do formulário, senão o Accept-Language de quem preenche, senão pt-BR. Veja Idioma do formulário. |
| Em português de propósito | Os modelos padrão dos e-mails de autenticação do Supabase, que você edita na conexão. |
#Boas práticas
- Guarde a chave em variável de ambiente ou num cofre de segredos, nunca no código. Não use a chave no navegador ou em apps: qualquer pessoa poderia copiá-la. Chame a API a partir do seu servidor.
- Use uma chave por sistema e por ambiente. Assim, dá para revogar uma sem derrubar as outras e ver nos logs quem fez cada requisição.
- Se uma chave vazar, exclua-a na hora (
DELETE /api-keys/{id}) e crie outra. - Para dar a um assistente de IA acesso à conta, prefira o OAuth do servidor MCP, que limita o acesso a um time e a escopos e se revoga sem trocar chave.