Iniciar sesión Crear cuenta
Conceptos

Idempotencia

Repite una solicitud de envío con seguridad, sin el riesgo de mandar el mismo correo electrónico dos veces.

#Cómo usarla

Una solicitud de envío puede dar timeout después de que Postal ya haya aceptado el correo electrónico. Repetirla sin cuidado envía el correo electrónico dos veces. Para evitarlo, manda un identificador único de la operación en el encabezado Idempotency-Key:

POST /emails

cURL

curl -X POST https://api.postal.so/emails \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Idempotency-Key: order-10482-shipped" \
  -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',
    'Idempotency-Key': 'order-10482-shipped',
  },
  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']}",
        "Idempotency-Key": "order-10482-shipped",
    },
    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'),
        'Idempotency-Key' => 'order-10482-shipped',
    ],
    '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);

Si la misma clave llega de nuevo en un plazo de 24 horas, con el mismo cuerpo, Postal no envía otra vez: devuelve la respuesta guardada de la primera solicitud, con el mismo estado y el mismo ID.

#Reglas

  • Vale para POST /emails, POST /emails/batch, POST /events (un evento repetido no inicia la automatización de nuevo), POST /contacts/batch y POST /segments/merge. En los demás endpoints, el encabezado se ignora.
  • La clave tiene de 1 a 256 caracteres; fuera de ese rango, la respuesta es 400 invalid_idempotency_key.
  • Las claves valen por equipo: dos claves de API del mismo equipo comparten las mismas claves de idempotencia.
  • Solo se guardan las respuestas de éxito (2xx). Si el primer intento falló con 422 o 429, corrige y repite con la misma clave.
  • Misma clave con otro cuerpo, método o ruta: 409 invalid_idempotent_request.
  • Misma clave mientras la primera solicitud sigue en curso: 409 concurrent_idempotent_requests. Espera un poco y repite.

#Cómo elegir la clave

Usa algo que identifique el motivo del envío, no el intento: order-10482-shipped, password-reset-8f2a91 o un UUID generado y guardado junto con el pedido. Generar un UUID nuevo en cada intento anula la protección.