Entrar Criar conta
Referência da API

Uso e métricas

O consumo do plano e as métricas de entrega, abertura e clique.

Consulte quanto do plano o time já usou e as métricas de entrega dos seus e-mails.

#Uso do plano

GET/usage

Acesso total ou só envio

Cotas de envio do dia e do mês (dias e meses em UTC), domínios, inboxes, pessoas no time, campanhas do mês (broadcasts: enviadas, enviando ou agendadas), execuções de automação iniciadas no mês, créditos de IA, se o envio está pausado e o limite de requisições por segundo. limit: null significa sem limite.

Quais chaves podem chamar: qualquer chave, de acesso total ou sending_access, e o painel. Assim, um app que só tem uma chave de envio lê o limite de requisições (rate_limit), as cotas diária e mensal e a pausa de envio do plano. Para as chaves sending_access, email_verifications não traz a lista de pacotes do Adicional de validação (grants), só os totais, e reputation não traz o history; o resto da resposta é igual.

Campos: plan (o plano de envio e o de marketing), emails.daily e emails.monthly (used, limit e resets_at; em emails.daily, também plan_limit e limited_by, veja abaixo; sent repete used e received é sempre 0), emails.credits (a reserva do Adicional de envios: veja abaixo), contacts (used, limit, plan_limit e packs dos contatos do plano de marketing: veja abaixo), audience (veja abaixo), overage dentro de emails.monthly e de contacts (se o excedente está ligado para o produto, enabled; se está valendo, active; e o que passou do limite no período, extra, em pacotes de 1.000, packs; em contatos, peak é o maior número do período), domains, team_members, inboxes, broadcasts, automation_runs, ai_credits (com remaining e resets_at), email_verifications (os créditos de validação de e-mails: used, limit, remaining, monthly_remaining, grant_credits, grants, resets_at e free_preview_remaining), features, paused, sending, reputation (veja abaixo) e rate_limit. A cota mensal de e-mails e o limite de contatos seguem a faixa de volume contratada (veja Planos).

emails.daily.limit é o limite diário que vale: o menor entre o do plano e o teto da reputação da conta (null: sem limite). emails.daily.plan_limit é só o do plano, e emails.daily.limited_by diz qual dos dois limita: plan, reputation ou null quando não há limite. Um limite diário definido pela equipe da Postal para o time substitui o teto da reputação, e aí limited_by vem plan. Ao atingir o limite, os envios recebem 429 daily_quota_exceeded; quando é a reputação que limita, a mensagem é Your account is at reputation level 2 of 5, which allows 2000 emails a day while it builds its sending history. The limit grows with each day of sending without bounces or complaints. It resets at 00:00 UTC.

reputation é a reputação da conta: score (de 0 a max_score, 100), level (de 1 a max_level, 5), daily_limit (o teto do nível; null no nível 5, sem teto da reputação), next (o próximo nível, com level, score e daily_limit; null no nível 5), levels (a tabela dos níveis, cada um com level, score mínimo, daily_limit e max_bounce_rate, a taxa de bounces permanentes que pausa os envios) e rules (os pontos por dia limpo conforme o volume, gain, cada degrau com o nível máximo até onde ele leva a conta, max_level; as taxas de um dia limpo, clean, e de um dia grave, severe; e as penalidades warning_penalty, severe_penalty e pause_penalty). As taxas são frações. history traz até 30 mudanças, da mais recente para a mais antiga, cada uma com day, kind, delta (os pontos somados ou tirados), score (a pontuação depois dela) e created_at. kind é day (a avaliação de um dia, com outcome: clean, quiet com menos de 10 e-mails e sem mudança, warning ou severe; e com sent, bounce_rate, complaint_rate, content_rejected_rate e all_bounce_rate; e com capped_at_level quando o ganho parou no topo do nível que o volume do dia permite), pause (uma pausa dos envios, com reason_code; outcome é null) ou staff (um ajuste da equipe da Postal; a nota da equipe não aparece). As chaves sending_access recebem o bloco sem history. Veja Reputação da conta.

sending mostra se os envios do time estão pausados por reputação: paused, paused_at, reason (o motivo em texto, no idioma da requisição: Accept-Language: pt-BR ou en, sem o cabeçalho em inglês), reason_code (bounce_rate, complaint_rate, content_rejected, all_bounce_rate ou manual; null sem pausa e nas pausas antigas), reason_details (os números do motivo, com as taxas como frações e a janela em window_days ou, na janela das últimas 24 horas, window_hours; null sem pausa, em manual e nas pausas antigas: veja a pausa de envios) e review_requested_at (quando a revisão foi pedida, ou null). paused, no nível de cima, lista os recursos que o plano atual pausou por estarem acima do limite, em [{"key", "label", "count"}] (vazia quando nada está pausado; o label segue o Accept-Language): veja Limites e recursos do plano.

audience é a Audiência de contatos em relação ao limite do plano de marketing, para avisar antes de a captura dos e-mails transacionais parar: used (contatos), limit (null: sem limite), percent (inteiro, de 0 a mais de 100; null sem limite), capture_enabled (o time guarda os destinatários dos e-mails transacionais na Audiência) e capture_paused (a captura está ligada, mas o limite foi atingido, então os novos destinatários não estão sendo guardados). O dono e os admins também recebem e-mails ao chegar a 80%, 90% e 100% do limite.

contacts.limit é o limite que vale: os contatos do plano mais os dos pacotes do Adicional de contatos, quando o time os tem; plan_limit é só o do plano. contacts.packs traz contacts (o que os pacotes somam; 0 sem pacotes), effective (igual a limit), scheduled (null, ou {"effective_at", "pack_contacts", "effective_limit"} quando uma redução espera a renovação: effective_limit é o limite depois dela) e, nas chaves de acesso total, items (os pacotes do time, com pack_id, name, contacts, quantity, scheduled_quantity, contacts_total, max_quantity, amount, currency e interval). As chaves sending_access veem os totais, mas não items. O bloco audience e os avisos de uso usam o mesmo limite.

marketing_recipients conta os contatos diferentes que receberam campanhas ou e-mails de automação no ciclo, que não podem passar do mesmo limite de contatos: used, limit (null: sem limite), remaining, percent (inteiro; null sem limite), billed_above_limit (true com o excedente de contatos valendo: os que passam do limite são cobrados, não recusados), cycle_start e resets_at (quando o ciclo renova e o contador volta a zero). Quem já recebeu campanha no ciclo continua contando até resets_at, mesmo se for apagado. Em contacts.overage, recipients repete used: o excedente de contatos é medido pelo maior entre peak e recipients.

emails.credits é a reserva do Adicional de envios, à parte da cota: emails.monthly.used e limit continuam sendo os do plano, e os créditos nunca são somados ao limite. Ela só é usada depois que a cota mensal acaba. Traz reserve (sempre true), balance (os créditos que dá para usar agora), used_this_month (os que os envios tiraram da reserva no mês), in_use (true quando a cota mensal acabou e há saldo, então os envios saem da reserva), next_expires_at (a data em que vence o primeiro pacote com validade, ou null) e, nas chaves de acesso total, grants: os pacotes e bônus com saldo, na ordem em que são usados (os que vencem antes primeiro, os sem validade por último), cada um com id, source (purchase ou staff), name, emails, remaining e expires_at (null: sem validade). As chaves sending_access veem os totais, mas não grants. Em email_verifications.grants, expires_at também é null num pacote sem validade.

GET /usage

cURL

curl https://api.postal.so/usage \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/usage', {
  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/usage",
    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('usage', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "usage",
  "plan": {
    "id": "pro",
    "name": "Pro",
    "marketing_id": "free",
    "marketing_name": "Free"
  },
  "emails": {
    "daily": {
      "used": 1840,
      "limit": 5000,
      "plan_limit": null,
      "limited_by": "reputation",
      "sent": 1840,
      "received": 0,
      "resets_at": "2026-10-25T00:00:00Z"
    },
    "monthly": {
      "used": 31207,
      "limit": 50000,
      "sent": 31207,
      "received": 0,
      "resets_at": "2026-11-01T00:00:00Z",
      "overage": {
        "enabled": false,
        "active": false,
        "unit": "emails",
        "extra": 0,
        "packs": 0
      }
    },
    "credits": {
      "reserve": true,
      "balance": 20000,
      "used_this_month": 0,
      "in_use": false,
      "next_expires_at": "2027-01-15T12:00:00Z",
      "grants": [
        {
          "id": "019a3f20-6c7d-7e8f-9a01-2b3c4d5e6f70",
          "source": "purchase",
          "name": "Pacote A",
          "emails": 20000,
          "remaining": 20000,
          "expires_at": "2027-01-15T12:00:00Z"
        }
      ]
    }
  },
  "contacts": {
    "used": 3120,
    "limit": 5000,
    "plan_limit": 5000,
    "packs": {
      "contacts": 0,
      "effective": 5000,
      "scheduled": null,
      "items": []
    },
    "overage": {
      "enabled": false,
      "active": false,
      "unit": "contacts",
      "extra": 0,
      "packs": 0,
      "peak": 3120,
      "recipients": 2870
    }
  },
  "marketing_recipients": {
    "used": 2870,
    "limit": 5000,
    "remaining": 2130,
    "percent": 57,
    "billed_above_limit": false,
    "cycle_start": "2026-10-25T14:00:00Z",
    "resets_at": "2026-11-25T14:00:00Z"
  },
  "audience": {
    "used": 3120,
    "limit": 5000,
    "percent": 62,
    "capture_paused": false,
    "capture_enabled": true
  },
  "domains": {
    "used": 2,
    "limit": 10
  },
  "team_members": {
    "used": 4,
    "limit": 10
  },
  "inboxes": {
    "used": 1,
    "limit": 10
  },
  "features": {
    "custom_inbound_domains": true,
    "postal_branding": false,
    "ai_assistant": true,
    "email_verification": true
  },
  "broadcasts": {
    "used": 3,
    "limit": null
  },
  "automation_runs": {
    "used": 318,
    "limit": 10000
  },
  "ai_credits": {
    "used": 12,
    "limit": 100,
    "remaining": 88,
    "resets_at": "2026-11-01T00:00:00Z"
  },
  "email_verifications": {
    "used": 120,
    "limit": 5000,
    "remaining": 5880,
    "monthly_remaining": 4880,
    "grant_credits": 1000,
    "grants": [
      {
        "id": "019a1d40-5b6c-7d7e-8f90-1a2b3c4d5e6f",
        "source": "purchase",
        "name": "Pacote de 1.000 créditos",
        "credits": 1000,
        "remaining": 1000,
        "expires_at": "2027-10-20T00:00:00Z"
      }
    ],
    "resets_at": "2026-11-01T00:00:00Z",
    "free_preview_remaining": 880
  },
  "paused": [],
  "sending": {
    "paused": false,
    "paused_at": null,
    "reason": null,
    "reason_code": null,
    "reason_details": null,
    "review_requested_at": null
  },
  "reputation": {
    "score": 23,
    "max_score": 100,
    "level": 3,
    "max_level": 5,
    "daily_limit": 5000,
    "next": {
      "level": 4,
      "score": 30,
      "daily_limit": 10000
    },
    "levels": [
      {
        "level": 1,
        "score": 0,
        "daily_limit": 500,
        "max_bounce_rate": 0.03
      },
      {
        "level": 2,
        "score": 5,
        "daily_limit": 2000,
        "max_bounce_rate": 0.04
      },
      {
        "level": 3,
        "score": 15,
        "daily_limit": 5000,
        "max_bounce_rate": 0.05
      },
      {
        "level": 4,
        "score": 30,
        "daily_limit": 10000,
        "max_bounce_rate": 0.05
      },
      {
        "level": 5,
        "score": 60,
        "daily_limit": null,
        "max_bounce_rate": 0.05
      }
    ],
    "rules": {
      "gain": [
        {
          "sent": 10,
          "points": 3,
          "max_level": 3
        },
        {
          "sent": 100,
          "points": 5,
          "max_level": 4
        },
        {
          "sent": 1000,
          "points": 6,
          "max_level": 5
        }
      ],
      "clean": {
        "bounce_rate": 0.02,
        "complaint_rate": 0.001,
        "content_rejected_rate": 0.01,
        "all_bounce_rate": 0.1
      },
      "severe": {
        "bounce_rate": 0.05,
        "complaint_rate": 0.003,
        "content_rejected_rate": 0.05,
        "all_bounce_rate": 0.2
      },
      "warning_penalty": 10,
      "severe_penalty": 25,
      "pause_penalty": 40
    },
    "history": [
      {
        "day": "2026-10-23",
        "kind": "day",
        "outcome": "clean",
        "delta": 5,
        "score": 23,
        "sent": 340,
        "bounce_rate": 0.0058,
        "complaint_rate": 0,
        "content_rejected_rate": 0,
        "all_bounce_rate": 0.0117,
        "created_at": "2026-10-24T01:00:12Z"
      },
      {
        "day": "2026-10-22",
        "kind": "day",
        "outcome": "quiet",
        "delta": 0,
        "score": 18,
        "sent": 6,
        "bounce_rate": 0,
        "complaint_rate": 0,
        "content_rejected_rate": 0,
        "all_bounce_rate": 0,
        "created_at": "2026-10-23T01:00:09Z"
      },
      {
        "day": "2026-10-21",
        "kind": "staff",
        "outcome": null,
        "delta": 3,
        "score": 18,
        "created_at": "2026-10-21T14:32:40Z"
      }
    ]
  },
  "rate_limit": {
    "limit": 10,
    "duration": "1s"
  }
}
200Só o campo "sending", com os envios pausados
{
  "sending": {
    "paused": true,
    "paused_at": "2026-10-24T15:20:02Z",
    "reason": "Taxa de bounce de 6,40% nos últimos 7 dias (limite: 5,00%).",
    "reason_code": "bounce_rate",
    "reason_details": {
      "bounce_rate": 0.064,
      "limit": 0.05,
      "window_days": 7
    },
    "review_requested_at": null
  }
}
200Só o campo "sending", numa pausa pela janela das últimas 24 horas (nível 1 a 3; texto de "reason" ilustrativo)
{
  "sending": {
    "paused": true,
    "paused_at": "2026-10-24T15:20:02Z",
    "reason": "Taxa de bounces de todos os tipos de 17,20% nas últimas 24 horas (limite: 15,00%).",
    "reason_code": "all_bounce_rate",
    "reason_details": {
      "all_bounce_rate": 0.172,
      "limit": 0.15,
      "window_hours": 24
    },
    "review_requested_at": null
  }
}
200Só o campo "emails", com a cota mensal esgotada e a reserva do Adicional de envios em uso (valores ilustrativos)
{
  "emails": {
    "monthly": {
      "used": 50210,
      "limit": 50000,
      "sent": 50210,
      "received": 0,
      "resets_at": "2026-11-01T00:00:00Z",
      "overage": {
        "enabled": false,
        "active": false,
        "unit": "emails",
        "extra": 0,
        "packs": 0
      }
    },
    "credits": {
      "reserve": true,
      "balance": 24790,
      "used_this_month": 210,
      "in_use": true,
      "next_expires_at": "2027-01-15T12:00:00Z",
      "grants": [
        {
          "id": "019a3f20-6c7d-7e8f-9a01-2b3c4d5e6f70",
          "source": "purchase",
          "name": "Pacote A",
          "emails": 20000,
          "remaining": 19790,
          "expires_at": "2027-01-15T12:00:00Z"
        },
        {
          "id": "019a3f21-7d8e-7f90-8b12-3c4d5e6f7081",
          "source": "purchase",
          "name": "Pacote B",
          "emails": 5000,
          "remaining": 5000,
          "expires_at": null
        }
      ]
    }
  }
}
200Só o campo "contacts", num time com pacotes do Adicional de contatos e uma redução agendada (valores ilustrativos)
{
  "contacts": {
    "used": 3120,
    "limit": 25000,
    "plan_limit": 5000,
    "packs": {
      "contacts": 20000,
      "effective": 25000,
      "scheduled": {
        "effective_at": "2026-11-20T12:00:00+00:00",
        "pack_contacts": 10000,
        "effective_limit": 15000
      },
      "items": [
        {
          "pack_id": "019a2e10-4b5c-7d6e-8f70-1a2b3c4d5e6f",
          "name": "Pacote A",
          "contacts": 10000,
          "quantity": 2,
          "scheduled_quantity": 1,
          "contacts_total": 20000,
          "max_quantity": 10,
          "amount": 4900,
          "currency": "brl",
          "interval": "month"
        }
      ]
    },
    "overage": {
      "enabled": false,
      "active": false,
      "unit": "contacts",
      "extra": 0,
      "packs": 0,
      "peak": 3120
    }
  }
}

#Métricas de e-mail

GET/emails/metrics

Chave de acesso total

Contagens e taxas calculadas a partir dos eventos no período. Sem dimensions, só vêm os totais; com period, vem uma linha por período (inclusive os vazios). Com domain ou broadcast (campanha), cada linha traz também o nome (domain_name, broadcast_name). Os resultados ficam em cache por até 15 minutos.

Contagens: sent, delivered, delivery_delayed, bounced, bounced_permanent, bounced_transient, bounced_undetermined, complained, failed, suppressed, opened, unique_opened, clicked, unique_clicked, received, unsubscribed. Taxas (de 0 a 1): delivery_rate (entregues / enviados), open_rate e click_rate (únicos / entregues), bounce_rate (bounces / enviados), complaint_rate e unsubscribe_rate (sobre entregues).

Parâmetros de consulta

  • start_datestring
    Início, em ISO 8601. Uma data sem hora vale 00:00 no timezone. Padrão: 6 dias antes do fim, à meia-noite.
  • end_datestring
    Fim, em ISO 8601. Uma data sem hora vale 00:00 no timezone: para incluir o último dia inteiro, mande 2026-10-22T23:59:59. Padrão (e máximo): agora. Se vier antes de start_date, a resposta é 422.
  • timezonestring
    Fuso IANA para datas sem fuso e para os períodos, como America/Sao_Paulo. Padrão: UTC.
  • granularitystring
    hourly, daily (padrão), weekly ou monthly. No máximo 10.000 períodos.
  • metricsstring
    Métricas separadas por vírgula (ou o parâmetro repetido). Padrão: todas.
  • dimensionsstring
    Agrupamentos: period, domain, email e/ou broadcast.
  • domain_idstring
    Até 100 IDs de domínio, separados por vírgula.
  • email_idstring
    Até 100 IDs de e-mail, separados por vírgula.
  • broadcast_idstring
    Até 100 IDs de campanha, separados por vírgula.

Erros

  • 422validation_error
    Data, fuso, granularidade, métrica ou dimensão inválida, ou período longo demais para a granularidade.
GET /emails/metrics

cURL

curl 'https://api.postal.so/emails/metrics?start_date=2026-10-20&end_date=2026-10-22T23:59:59&timezone=America/Sao_Paulo&metrics=sent,delivered,delivery_rate&dimensions=period' \
  -H "Authorization: Bearer $POSTAL_API_KEY"

Node.js

const response = await fetch('https://api.postal.so/emails/metrics?start_date=2026-10-20&end_date=2026-10-22T23:59:59&timezone=America/Sao_Paulo&metrics=sent,delivered,delivery_rate&dimensions=period', {
  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/emails/metrics",
    headers={"Authorization": f"Bearer {os.environ['POSTAL_API_KEY']}"},
    params={
        "start_date": "2026-10-20",
        "end_date": "2026-10-22T23:59:59",
        "timezone": "America/Sao_Paulo",
        "metrics": "sent,delivered,delivery_rate",
        "dimensions": "period",
    },
    timeout=10,
)

data = response.json()

PHP

$client = new \GuzzleHttp\Client(['base_uri' => 'https://api.postal.so']);

$response = $client->get('emails/metrics', [
    'headers' => ['Authorization' => 'Bearer '.getenv('POSTAL_API_KEY')],
    'query' => [
        'start_date' => '2026-10-20',
        'end_date' => '2026-10-22T23:59:59',
        'timezone' => 'America/Sao_Paulo',
        'metrics' => 'sent,delivered,delivery_rate',
        'dimensions' => 'period',
    ],
]);

$data = json_decode($response->getBody(), true);
200Resposta
{
  "object": "metrics",
  "start_date": "2026-10-20T03:00:00.000Z",
  "end_date": "2026-10-23T02:59:59.000Z",
  "metrics": ["sent", "delivered", "delivery_rate"],
  "dimensions": ["period"],
  "granularity": "daily",
  "totals": {
    "sent": 3120,
    "delivered": 3087,
    "delivery_rate": 0.9894
  },
  "data": [
    {
      "period": "2026-10-20T00:00:00-03:00",
      "sent": 1004,
      "delivered": 995,
      "delivery_rate": 0.991
    },
    {
      "period": "2026-10-21T00:00:00-03:00",
      "sent": 1130,
      "delivered": 1116,
      "delivery_rate": 0.9876
    },
    {
      "period": "2026-10-22T00:00:00-03:00",
      "sent": 986,
      "delivered": 976,
      "delivery_rate": 0.9899
    }
  ]
}