Conceitos

Paginação e filtros

As listas usam paginação por cursor com limit, after e before, e aceitam filtros na query string.

#Como funciona

Os endpoints que listam recursos (GET /emails, GET /domains, GET /logs…) devolvem os itens do mais recente para o mais antigo, numa página por vez:

200Resposta
{
  "object": "list",
  "has_more": true,
  "data": [
    {
      "object": "email",
      "id": "019a1b2c-51ab-7d30-8e11-2a3b4c5d6e7f",
      "…": "…"
    },
    {
      "object": "email",
      "id": "019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b",
      "…": "…"
    }
  ]
}
ParâmetroDescrição
limitItens por página, de 1 a 100. Padrão: 20.
afterID de um item: devolve os itens mais antigos que ele. Use o ID do último item da página para ir à próxima.
beforeID de um item: devolve os itens mais recentes que ele. Use o ID do primeiro item para voltar uma página.

has_more diz se há mais itens na direção pedida. Não dá para usar after e before juntos (422). Como o cursor é o ID, itens criados enquanto você pagina não fazem a lista pular nem repetir itens.

#Percorrer todas as páginas

Para ler uma lista inteira, peça páginas de 100 e siga o after até has_more ser false:

Paginação

cURL

# Primeira página
curl "https://api.postal.so/emails?limit=100" \
  -H "Authorization: Bearer $POSTAL_API_KEY"

# Próxima página: o ID do último item recebido
curl "https://api.postal.so/emails?limit=100&after=019a1b2c-4d5e-7f60-8a9b-0c1d2e3f4a5b" \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

async function listAll(path) {
  const items = [];
  let after;

  do {
    const url = new URL(path, 'https://api.postal.so');
    url.searchParams.set('limit', '100');
    if (after) url.searchParams.set('after', after);

    const response = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.POSTAL_API_KEY}` },
    });
    const page = await response.json();

    items.push(...page.data);
    after = page.has_more ? page.data.at(-1).id : undefined;
  } while (after);

  return items;
}

const bounces = await listAll('/emails?status=bounced');

Python

import os
import requests

def list_all(path, **filters):
    items, after = [], None

    while True:
        params = {"limit": 100, **filters}
        if after:
            params["after"] = after

        page = requests.get(
            f"https://api.postal.so{path}",
            headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
            params=params,
            timeout=10,
        ).json()

        items.extend(page["data"])
        if not page["has_more"]:
            return items
        after = page["data"][-1]["id"]

bounces = list_all("/emails", status="bounced")

PHP

function listAll(string $path, array $filters = []): array
{
    $client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);
    $items = [];
    $after = null;

    do {
        $page = json_decode($client->get($path, [
            'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
            'query' => [...$filters, 'limit' => 100, ...($after ? ['after' => $after] : [])],
        ])->getBody(), true);

        array_push($items, ...$page['data']);
        $after = $page['has_more'] ? end($page['data'])['id'] : null;
    } while ($after !== null);

    return $items;
}

$bounces = listAll('emails', ['status' => 'bounced']);

Para grandes volumes, prefira as exportações em CSV: elas usam os mesmos filtros e não gastam o seu limite de requisições.

#Filtros

Várias listas aceitam filtros na query string, combinados com a paginação. Filtros com vários valores aceitam uma lista separada por vírgula, como status=bounced,complained.

EndpointFiltros
GET /emailssearch, status, domain_id, api_key_id, start_date, end_date
GET /emails/receivinginbox_id, unread, search
GET /domainssearch, status, region
GET /api-keyssearch, permission
GET /templatessearch, status
GET /contactssearch, segment_id, topic_id, unsubscribed
GET /segments, GET /formssearch
GET /broadcastssearch, status
GET /broadcasts/{id}/recipientsstatus, search
GET /eventsname, contact
GET /automationssearch, status
GET /automations/{id}/runsstatus, contact
GET /logsstatus, method, source, user_agent, api_key_id, search, start_date, end_date