Sign in Create account
Concepts

API rate limits and sending quotas

Requests per second, sending quotas by plan and the maximum sizes of each resource.

#Requests per second

Each team has a limit of requests per second, summed across all its keys. The value depends on the plan:

PlanRequests per second
Free5
Pro10
Scale20
Enterprise50

The limit in effect for your team appears in GET /usage (rate_limit). Apps that hold only a sending key can see it too: GET /usage accepts sending_access keys, and the X-RateLimit-* headers come with every response, including sends. Every response carries these headers:

HeaderDescription
X-RateLimit-LimitRequests allowed per second.
X-RateLimit-RemainingHow many more fit in the current second.
Retry-AfterOnly on 429: seconds until you can try again.
X-RateLimit-ResetOnly on 429: when the limit resets (Unix timestamp).

Go over the limit and the response is 429 rate_limit_exceeded. To send many emails, use batch sending: 100 emails count as one request.

The limit belongs to the team, not to the key, and also applies to the MCP server. The SDKs read the headers for you: postal.rateLimit (Node.js) and $postal->rateLimit() (PHP) keep the limit of the last response, even with a sending-only key, and wait for Retry-After before retrying a 429.

#Sending quotas

Sends count when the email is created (including scheduled emails and template tests). Each broadcast recipient, each broadcast test and each automation email also counts. The day and the month are counted in UTC.

PlanPer dayPer month
Free1003,000
ProUnlimited50,000
ScaleUnlimited100,000
EnterpriseUnlimitedCustom

When you reach the quota, sends receive 429 daily_quota_exceeded or 429 monthly_quota_exceeded (over SMTP, 452 4.5.3). A broadcast that hits the quota midway is paused and resumes by itself when the quota renews; an automation send fails, and so does the run. On plans that allow it, you can turn on sending beyond the quota in the dashboard, under Billing: extra emails are charged per thousand, with no blocking. Your plan stays the same; you only pay for the extra packs, on the next invoice. Track your usage in GET /usage.

Account reputation. The daily limit in force is the lower of the plan's and the ceiling of the account reputation: a score from 0 to 100 that starts at 0 for new accounts and goes up with each day of sending without bounces or complaints. At levels 1 to 4 the ceiling is 500, 2,000, 5,000 and 10,000 emails a day; at level 5 only the plan's limit applies. The limit in force is in emails.daily.limit of GET /usage, with plan_limit (the plan's) and limited_by (plan or reputation), and the reputation block has the score, the level and the next level. When the reputation is what limits, the message of the 429 daily_quota_exceeded gives the level and the ceiling.

Sends add-on. When the team's plan has a monthly limit and offers the Sends add-on, the owner or an admin buys, with a one-time payment, a reserve of sends that is only used once the monthly quota runs out: first the plan's quota, then the reserve (one credit per email, the ones expiring soonest first), then sending beyond the quota, if the team turned it on, and only then the refusal. Broadcasts do not use the reserve, emails to test addresses take no credit, and the plan's daily limit still applies. The message of the 429 monthly_quota_exceeded says where to buy when that is possible. See Sends add-on and the API reference.

Sending reputation

To protect delivery for everyone, Postal pauses a team's sending when, over the last 7 days, permanent bounces exceed the limit of the account reputation level (3% at level 1, 4% at level 2 and 5% from level 3 up), spam complaints exceed 0.3% or content rejected by the providers exceeds 5% of the emails sent. The rates are judged from 100 sends in the period at levels 1 to 3 and from 1,000 at levels 4 and 5. At levels 1 to 3, Postal also looks at the last 24 hours, and bounces of every type above 15% also pause. In the first 24 hours after the team's first send, a pause for permanent bounces only happens above twice the limit. The test addresses are not counted. Each pause takes 40 points off the account reputation. The pause email lists up to 10 addresses with the most recent bounces (they are already suppressed). While sending is paused, sends receive 403 sending_paused. Request a review in the dashboard (there is no public endpoint for it) or through the contact form to have it lifted.

How to get a warning first and how to detect the pause: when permanent bounces reach the level's warning (2% at level 1, 2.5% at level 2 and 3% from level 3 up) or complaints reach 0.15%, the team owners and administrators get an email warning before the pause (one when a rate crosses its level; the next only if it worsens by 1 percentage point, or 0.1 for complaints, or after 7 days); when sending pauses, they get another. Through the API, subscribe to the webhook events sending.paused and sending.resumed to alert your team right away, or query GET /usage, which returns sending.paused, paused_at, the reason and review_requested_at (when a review was requested). A batch of invitations or emails with wrong addresses is the most common cause: validate addresses before sending and handle the bounces you receive in webhooks.

Suppressed addresses: a permanent bounce puts the address on the suppression list automatically. If the person has fixed their email, remove it with DELETE /suppressions/{id}, or in bulk with POST /suppressions/batch/remove, and sending works again.

#Features by plan

Plans and pricing: postal.so/precos or, through the API, GET /plans (public, no key needed).

FreeProScaleEnterprise
Domains3101,000Unlimited
Inboxes310100Unlimited
Inboxes on your own domainNoYesYesYes
Team members310UnlimitedUnlimited
AI credits per month101001,000Unlimited
Automation runs per month1,00010,000100,000Unlimited
Contacts (marketing plan)1,0005,00050,000Unlimited
Segments (marketing plan)3UnlimitedUnlimitedUnlimited
Broadcasts per month (marketing plan)UnlimitedUnlimitedUnlimitedUnlimited
Layouts10UnlimitedUnlimitedUnlimited
A/B tests in automationsNoYesYesYes
Email validation credits per month (marketing plan)1005,00050,000Unlimited
CRM connections (marketing plan)015Unlimited
App integrations (marketing plan)1310Unlimited

Teams can have their limits adjusted individually. The value that applies to you is always the one in GET /usage.

The volume scale is made of bands defined by Postal (for example 3,000, 50,000, 100,000 and 250,000 emails per month): each plan serves some of those bands, with the price of each, and above the last band only the custom plan serves. The list of bands and the ones each plan serves is in GET /plans (volume_bands and bands).

#Plan limits and features

Each plan sets, per team, how many things you can have and which features are included. Going over the limit for an item, or using a feature the plan does not include, answers 403 plan_limit_reached, with a message that says which one. The full list, with the text of each feature and whether the API already enforces it (enforced), comes in GET /plans (feature_catalog), and your team's values in GET /usage. For numbers, null means unlimited and 0 means not included; for on/off features, 1 means included and 0 not.

Quantity

They only block creating one more item. What already exists is never deleted.

Contacts above the limit. The contact limit of the marketing plan can also be exceeded, like the email one: under Billing, the team owner or an admin turns on Keep adding contacts above the plan limit (one switch per product, off by default). When it is on, imports, forms, the API and the CRM integrations stop refusing with 403 plan_limit_reached at the limit, and the extra contacts are charged per pack of 1,000 (rounded up) on the next invoice, without changing plans. What is charged is the most contacts the team had in the billing period (or the contacts that received campaigns in the cycle, if higher: see below), and deleting contacts afterwards does not lower what was already measured. Unsubscribed contacts and suppressed addresses count as contacts, as always. It only works with an active marketing subscription, on a plan that allows overage and has a price for extra contacts; otherwise the limit keeps refusing. The refusal message says how to turn it on when the option is available.

Contacts add-on. When the team's marketing plan offers the Contacts add-on, the owner or an admin adds contacts to the limit without changing plans: the pack's price goes on the subscription's invoice and the limit becomes the plan's plus the packs'. The limit the API checks (403 plan_limit_reached) and the one GET /usage shows already include the packs. They only apply to a paid, active marketing plan. See Contacts add-on and the API reference.

Contacts that receive campaigns in the cycle

The marketing plan's contact limit (with the Contacts add-on) also applies to who receives campaigns: in the team's usage cycle (the month that renews on your plan's day), campaigns and automation emails can go to up to that many different contacts. Each address counts once per cycle. Contacts that already received a campaign in the cycle keep counting until the renewal, even if deleted, and deleting and creating the same address again does not count twice. Deleting contacts that have not received a campaign yet frees room right away. Sending several campaigns to the same contacts does not use more. Transactional emails do not count.

Example, with a limit of 50,000 contacts: sending 5 campaigns to the same 50,000 contacts in the cycle is within the plan. Deleting the 50,000 that already received one and importing another 50,000 in the same cycle goes over the limit: the campaign to the new ones is refused until the renewal.

A campaign that would go over the limit is refused as a whole, without sending anything, with 422 cycle_recipients_limit, a message with the numbers, the renewal date and what to do, and the cycle_recipients block (new, used, limit, remaining and resets_at). Postal checks again when a scheduled campaign is about to go out: if it no longer fits, it is paused with the same reason. An automation email to a contact that has received nothing in the cycle, with the limit full, is skipped. The owner and admins get an email at 80% and at 100%. With contact overage turned on, nothing is refused and the contacts above the limit are billed as extra contacts. Without a contact limit, there is no recipient limit. The counter is in GET /usage (marketing_recipients) and in Settings › Usage, and what a campaign would do, before sending, in GET /broadcasts/audience.

KeyWhat countsWhere it blocks
domainsSending domainsPOST /domains and domain claims
inboxesInboxesPOST /inboxes
templatesTemplatesPOST /templates and duplicating
layoutsLayoutsPOST /layouts and duplicating
api_keysAPI keysPOST /api-keys
webhooksWebhook endpointsPOST /webhooks
team_membersTeam members (pending invitations count)Inviting people, in the dashboard
contactsContactsCreating contacts through the API, an import, a form or an integration
segmentsSegmentsPOST /segments and merging segments
topicsTopicsPOST /topics
formsFormsPOST /forms
automationsAutomations (active or not)POST /automations
broadcasts_per_monthBroadcasts sent or scheduled in the month (UTC)Sending or scheduling a broadcast
crm_connectionsCRM connectionsCreating the connection
app_integrationsApp integrations (Stripe, Supabase, Clerk, Firebase, Auth0)Creating the integration
attachments_mbTotal size of an email's attachments, in MB. 0 allows no attachments; empty (null) uses the platform limit of 40 MBSending emails with attachments

Other monthly limits do not give a 403: emails_per_day and emails_per_month give 429 (see sending quotas); ai_credits, 429 ai_credits_exhausted; email_verifications_per_month, 403 if the plan does not include email validation and 429 verification_credits_exhausted when the credits run out; and automation_runs: above the limit, new automation runs do not start (they are marked skipped).

On/off features

KeyWhat it unlocksWhere it blocks
batch_sendingBatch sendingPOST /emails/batch
scheduled_sendingScheduled sendingscheduled_at in POST /emails
test_addressesSimulated test addressesSending to @sandbox.postal.so
smtp_accessSMTP sendingSMTP refuses the message with 550 5.7.1
engagement_trackingOpen and click trackingTurning on open_tracking or click_tracking on a domain (domains already tracking keep tracking)
custom_domain_recordsCustom Return-Path and tracking subdomainNew or changed custom_return_path and tracking_subdomain
shared_email_linksShared email linksPOST /emails/{id}/share
custom_inbound_domainsInboxes and receiving on your own domainCreating inboxes and enabling capabilities.receiving on your own domains
inbox_agentInbox AI agentTurning the agent on in an inbox
exportsCSV exportsPOST /exports and the export of form submissions
mcp_accessMCP serverThe /mcp endpoint
restricted_api_keysSending-only or domain-restricted keysPOST /api-keys with permission: "sending_access" (keys already created keep working)
dynamic_segmentsDynamic segmentsCreating a dynamic segment (existing ones keep working)
form_analyticsForm analyticsGET /forms/overview and GET /forms/{id}/analytics, with the answers by question and the analytics export
automation_experimentsA/B tests in automationsA/B experiment steps
postal_branding“Sent with Postal” badge (inverted: 1 means it has the badge)Hiding the badge on a form

retention_days, priority_support, uptime_sla and dedicated_manager are informative: the API blocks nothing because of them (retention is 30 days for everyone, and support is arranged separately).

When the plan drops

When the plan changes, the amount the team already has can go over the new limit. Nothing is deleted: of domains, inboxes, templates, layouts, API keys, webhooks, automations, segments, topics and forms, the oldest ones up to the limit stay active and the newest ones get paused_by_plan: true. A paused item shows up in lists and can be read and deleted, but not changed or used: the domain does not send, the API key does not authenticate, the webhook receives no events, the template does not send, the form goes offline, the automation does not fire, the segment cannot be used as an audience and the inbox does not run the agent (it keeps receiving email). Any attempt to change it answers 403 paused_by_plan. Items come back on their own when the plan, the volume tier or the count allows it, and GET /usage lists what is paused in paused. Contacts, team members and connections are not paused: the limit only prevents adding more.

The monthly email quota and the number of contacts follow the volume tier you subscribed to (see Plans), and a team can have limits adjusted individually. The value that applies to you is always the one in GET /usage.

#Sizes and quantities

WhatLimit
Recipients in to50 per email
Emails per batch (POST /emails/batch)100
Attachments40 MB in total per email (less if the plan caps it: attachments_mb)
Attachments of inbox replies, messages and draftsUp to 10 files and 40 MB in total
Message over SMTP40 MB and 50 recipients
Scheduling (scheduled_at)Up to 30 days ahead
Test addresses ([email protected]…)They do not count toward the sending quota or toward the bounce and complaint rates used for reputation; the requests-per-second limit still applies
Tags50 per email; name and value up to 256 characters
Subject and header values998 characters
Items per page in lists100
Idempotency-Key256 characters, kept for 24 hours
Images (POST /assets)5 MB
Exports in progress3 per team
Public link of an email (POST /emails/{id}/share)Valid from 1 minute to 48 hours
Metrics (GET /emails/metrics)Up to 10,000 periods and 100 IDs in each filter
DNS instructions by email (POST /domains/{id}/instructions)Up to 5 recipients; 3 per minute and 10 per hour per team; 5 per day for each address
Replies forwarded per email with reply detection20
Sources to skip on a webhook (skip_sources)20
Contact importsCSV up to 20 MB; 3 in progress per team
Contacts per request in POST /contacts/batch10,000
Tags per contact request50
Contacts per bulk tag operation1,000
Email validationUp to 200,000 addresses per list; 2 lists in progress per team
Dynamic segment10 condition groups and 20 conditions in total
Segments in a merge20
Contact properties100 per team; text values up to 1,000 characters
Variables of a template50
Submissions to a public form5 per minute per IP
Broadcast schedulingUp to 30 days ahead
Broadcast test5 addresses
Events (POST /events)Name up to 100 characters; properties up to 16 KB
Automations100 steps; 10 filters on the trigger; 20 actions per update_contact; waits of up to 365 days
Automation webhook step3 attempts, 15 seconds each
Retention of emails, webhooks and logs30 days
Event retention90 days
Export files7 days; the download link is valid for 1 hour
Email validation results7 days for each address's result and the CSV; the validation itself is kept for 30 days