Documentación de la API
Envía y recibe correos electrónicos, gestiona dominios y sigue cada entrega con una API REST sencilla, en portugués y con la opción de procesar los correos en São Paulo.
#Visión general
La API de Postal es una API REST con JSON. Envías correos transaccionales, recibes mensajes en tus buzones de entrada, gestionas dominios, plantillas, webhooks y la lista de supresión, te encargas de la audiencia de marketing (contactos, segmentos, temas y formularios de suscripción), envías campañas, montas automatizaciones a partir de eventos de tu producto y consultas registros y métricas, todo con una clave de API. Quien prefiere SMTP usa la misma clave en smtp.postal.so.
- Primeros pasosVerifica un dominio, crea una clave y envía el primer correo en cinco minutos.
- AutenticaciónClaves de acceso total o solo de envío, restringidas a un dominio.
- Guía del panelQué hace cada pantalla del panel y cada botón: correos, audiencia, campañas, dominios, configuración y más.
- WebhooksRecibe entregas, rebotes, aperturas y correos recibidos en tiempo real.
- SMTPPara sistemas que solo hablan SMTP:
smtp.postal.socon tu clave. - Encabezado OTP-TokenCódigos de un solo uso que el cliente de correo puede rellenar: formato, envío, lectura y seguridad.
- Dominios y DNSLos registros DKIM, SPF y MX, la región de envío y el seguimiento.
- Integra tu appStripe, Supabase, Clerk, Auth0 y Firebase se convierten en contactos y eventos; los correos de inicio de sesión salen por Postal.
- ErroresEl formato de las respuestas de error y qué hacer con cada una.
- SDKNode.js, PHP y Laravel:
npm install postal-soocomposer require postal-so/postal-php. - CLIEl comando
postalpara enviar correos y eventos desde la terminal. - Migrar desde ResendMismos recursos y formatos: cambia la URL y la clave y mira qué cambia.
#URL base
Todas las solicitudes van a:
https://api.postal.so
Usa siempre HTTPS. El cuerpo de las solicitudes y de las respuestas es JSON (Content-Type: application/json), en UTF-8. La excepción es la subida de imágenes, en multipart/form-data, y los mensajes originales (/raw), en texto plano.
#Tu primera solicitud
Con una clave en POSTAL_API_KEY y un dominio verificado, un envío es solo esto:
cURL
curl -X POST https://api.postal.so/emails \
-H "Authorization: Bearer $POSTAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Loja Exemplo <[email protected]>",
"to": ["[email protected]"],
"subject": "Seu pedido #10482 saiu para entrega",
"html": "<p>O pedido <b>#10482</b> está a caminho.</p>"
}'
Node.js
const response = await fetch('https://api.postal.so/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'Loja Exemplo <[email protected]>',
to: ['[email protected]'],
subject: 'Seu pedido #10482 saiu para entrega',
html: '<p>O pedido <b>#10482</b> está a caminho.</p>',
}),
});
const data = await response.json();
Python
import os
import requests
response = requests.post(
"https://api.postal.so/emails",
headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
json={
"from": "Loja Exemplo <[email protected]>",
"to": ["[email protected]"],
"subject": "Seu pedido #10482 saiu para entrega",
"html": "<p>O pedido <b>#10482</b> está a caminho.</p>",
},
timeout=10,
)
data = response.json()
PHP
$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);
$response = $client->post('emails', [
'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
'json' => [
'from' => 'Loja Exemplo <[email protected]>',
'to' => ['[email protected]'],
'subject' => 'Seu pedido #10482 saiu para entrega',
'html' => '<p>O pedido <b>#10482</b> está a caminho.</p>',
],
]);
$data = json_decode($response->getBody(), true);
{
"id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b"
}
El paso a paso completo, con el registro del dominio y de la clave, está en Primeros pasos.
#Convenciones
- Los ID son UUID ordenados por tiempo, como
019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b. - Las fechas vienen en ISO 8601, en UTC (
2026-10-24T13:02:11.000000Z). En las que envías, incluye la zona horaria, como2026-10-25T09:00:00-03:00. - Los objetos incluyen el campo
object(email,domain,list…), que indica qué es la respuesta. - Las listas usan paginación por cursor, con
has_more. - Las eliminaciones responden
{"object": "…", "id": "…", "deleted": true}. - Los errores siguen siempre el formato
{"statusCode", "name", "message"}. Consulta Errores. - Los nombres de campos y de errores están en inglés, para facilitar la búsqueda y la integración. El
messagede los errores viene en inglés, o en portugués conAccept-Language: pt-BR.
#Recursos de la API
La referencia está agrupada por recurso. Cada endpoint incluye los parámetros, ejemplos en cURL, Node.js, Python y PHP, la respuesta y los errores posibles.
#Retención de datos
Los correos enviados (con contenido, adjuntos y eventos), las entregas de webhooks y los registros de la API se conservan 30 días. Después se eliminan automáticamente. Si necesitas un historial más largo, guarda los eventos que recibes por los webhooks o usa las exportaciones.