Autenticación
Toda solicitud usa una clave de API en el encabezado Authorization. Las claves pueden tener acceso total o solo de envío, y restringirse a un dominio.
#Clave de API
Toda solicitud necesita una clave de API en el encabezado Authorization, con el formato Bearer:
Authorization: Bearer ps_4Fq9xLmT2vKp8sWd1Yc5Hf3Lz9Ag6Ej0Qm8rBnX
Las claves empiezan por ps_. Créalas en Claves de API en el panel, o por la API con POST /api-keys. El token completo aparece una sola vez, al crearla: Postal guarda solo el hash y los primeros caracteres (token_start), para que reconozcas la clave en la 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);
#Permisos
| Permiso | Qué puede hacer |
|---|---|
full_accessAcceso total | Toda la API: envío, dominios, plantillas, webhooks, registros, claves… |
sending_accessSolo envío | Enviar: POST /emails, POST /emails/batch, POST /events y el SMTP.Consultar: el estado y los eventos de los correos electrónicos que ella misma envió, por API o SMTP ( GET /emails/{id}; los correos de otras claves o del panel responden 404), y el plan, las cuotas y el límite de solicitudes en GET /usage. Todo lo demás requiere acceso total.Puede restringirse a un dominio ( domain_id): entonces solo envía con remitentes de ese dominio. |
Crear claves solo de envío o restringidas a un dominio depende del plan (restricted_api_keys); el número de claves también (api_keys). Consulta Límites.
Usa claves solo de envío en los sistemas que únicamente disparan correos electrónicos o eventos (el checkout, WordPress, el ERP) y reserva las de acceso total para automatizaciones de infraestructura. Si una clave de envío se filtra, no cambia tu configuración ni lee tus contactos, dominios o los correos de otras claves: solo ve lo que ella misma envió y los límites del plan.
#Errores de autenticación
| Estado | Nombre | Cuándo ocurre |
|---|---|---|
401 | missing_api_key | Falta el encabezado Authorization. |
403 | invalid_api_key | La clave no existe, fue eliminada o no empieza con ps_. |
401 | restricted_api_key | Una clave solo de envío intentó usar otro endpoint (puede enviar, leer los correos que envió con GET /emails/{id} y llamar a GET /usage). |
403 | restricted_api_key | Una clave restringida a un dominio intentó enviar desde otro dominio. |
403 | paused_by_plan | La clave superó el límite de claves del plan actual y fue pausada (paused_by_plan: true en GET /api-keys). No se autentica hasta que el plan o el conteo lo permitan de nuevo; consulta Límites. |
403 | team_suspended | La cuenta fue suspendida por la plataforma que la gestiona. |
#Idioma de los mensajes y origen de los cambios
Dos opciones por solicitud:
Accept-Language: pt-BR(oen) elige el idioma delmessagede los errores y de los demás textos que la API escribe para tu solicitud (consulta la tabla de abajo). Sin el encabezado, viene en inglés. Elnamees siempre el mismo.X-Postal-Source: erppone una etiqueta a los cambios que la clave hace en los contactos. La etiqueta aparece ensourceen los webhooks de contacto y enlast_change_sourcedel contacto, y permite que un webhook ignore lo que hizo el propio sistema.
El idioma de cada texto que escribe Postal depende de a quién va dirigido:
| Texto | Idioma |
|---|---|
| Los textos de las respuestas de la API | El message de los errores, las etiquetas (como el label de paused en GET /usage), el sending.reason del mismo endpoint, el diagnostic de los registros DNS del dominio, el sufijo de los nombres de copias (“(copy)” o “(cópia)”), el prefijo [Test] o [Teste] de la prueba de campaña y de la prueba de plantilla y el “Other:” u “Outro:” de los CSV de respuestas de formulario. Siguen el Accept-Language de la solicitud (pt-BR o en, el primero que Postal conoce). Con clave de API o sin credenciales, sin el encabezado vienen en inglés; GET /plans, que es público, viene en portugués sin él. |
| Texto de la IA del diagnóstico | POST /ai/emails/{id}/fix-insights: el parámetro language (pt-BR, en o es); sin él, el idioma de la solicitud. |
| Webhooks de pausa | El reason sale en el idioma del equipo, el que eligió el propietario en el panel; en inglés mientras no elija. El reason_code no depende del idioma. |
| Pie de cancelación de suscripción y página de preferencias | El idioma de cada destinatario: language de la campaña, propiedades del contacto, idioma del equipo. Consulta Idioma del pie y de la página. |
| Formularios públicos y correo electrónico de confirmación | settings.language del formulario; si no, el Accept-Language de quien lo rellena; si no, pt-BR. Consulta Idioma del formulario. |
| En portugués a propósito | Las plantillas predeterminadas de los correos electrónicos de autenticación de Supabase, que editas en la conexión. |
#Buenas prácticas
- Guarda la clave en una variable de entorno o en un gestor de secretos, nunca en el código. No uses la clave en el navegador ni en apps: cualquier persona podría copiarla. Llama a la API desde tu servidor.
- Usa una clave por sistema y por entorno. Así puedes revocar una sin tumbar las demás y ver en los registros quién hizo cada solicitud.
- Si una clave se filtra, elimínala de inmediato (
DELETE /api-keys/{id}) y crea otra. - Para dar a un asistente de IA acceso a la cuenta, prefiere el OAuth del servidor MCP, que limita el acceso a un equipo y a ámbitos, y se revoca sin cambiar de clave.