Conceitos

Idempotência

Repita uma requisição de envio com segurança, sem o risco de mandar o mesmo e-mail duas vezes.

#Como usar

Uma requisição de envio pode dar timeout depois de a Postal já ter aceitado o e-mail. Repetir sem cuidado manda o e-mail duas vezes. Para evitar isso, envie um identificador único da operação no cabeçalho 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);

Se a mesma chave chegar de novo em até 24 horas, com o mesmo corpo, a Postal não envia outra vez: devolve a resposta guardada da primeira requisição, com o mesmo status e o mesmo ID.

#Regras

  • Vale para POST /emails, POST /emails/batch e POST /events (um evento repetido não inicia a automação de novo). Nos outros endpoints, o cabeçalho é ignorado.
  • A chave tem de 1 a 256 caracteres; fora disso, a resposta é 400 invalid_idempotency_key.
  • As chaves valem por time: duas chaves de API do mesmo time compartilham as mesmas chaves de idempotência.
  • Só respostas de sucesso (2xx) são guardadas. Se a primeira tentativa falhou com 422 ou 429, corrija e repita com a mesma chave.
  • Mesma chave com outro corpo, método ou caminho: 409 invalid_idempotent_request.
  • Mesma chave enquanto a primeira requisição ainda está em andamento: 409 concurrent_idempotent_requests. Espere um pouco e repita.

#Como escolher a chave

Use algo que identifique o motivo do envio, não a tentativa: order-10482-shipped, password-reset-8f2a91 ou um UUID gerado e salvo junto com o pedido. Gerar um UUID novo a cada tentativa anula a proteção.