Errors and limits
ParsedMail API errors return a JSON body with an error type and a readable message, plus a matching HTTP status. Usage counts parsed emails and attachment pages per monthly period. Duplicates, blocked senders, forwarding confirmations and replays of counted emails are free, and deleting never gives usage back.
Error format
Errors raised by the API have one shape:
HTTP/1.1 404 Not Found
Content-Type: application/json
{"error": {"type": "not_found", "message": "No inbox with this id."}}Branch on type, show message to people. API errors use this shape, also for a missing key, an unknown endpoint and the rate limit, with or without an Accept header, and a wrong HTTP method returns 405 with type method_not_allowed. A request that fails validation adds a fields object with the messages per parameter:
HTTP/1.1 422 Unprocessable Content
{"error": {"type": "invalid_request", "message": "The name field is required.", "fields": {"name": ["The name field is required."]}}}Over the rate limit the answer is 429 with type rate_limited and a Retry-After header in seconds.
Error types and HTTP statuses
| HTTP | Type | When | What to do |
|---|---|---|---|
| 401 | unauthenticated | No key, wrong key, revoked key | Check the Authorization: Bearer header |
| 402 | plan_limit | Inbox count of the plan reached on POST /inboxes; monthly, page or daily limit reached on POST /parse | Wait for the next period or move to a higher plan |
| 403 | forbidden | The key lacks the scope, for example This API key lacks the "write" permission. | Create a key with the scope |
| 403 | forbidden | The person who created the key no longer belongs to its workspace: This API key no longer has access to its workspace. | Create a new key from a current member |
| 404 | not_found | Inbox, schema or email id not in this workspace, or an unknown endpoint | Check the id, the path and the workspace of the key |
| 409 | inbox_paused | Email posted to a paused inbox | Resume the inbox in the dashboard and send the email again |
| 410 | purged | Replay of an email whose raw content was deleted under retention | The JSON result stays available; resubmit the original if you still have it |
| 413 | too_large | Raw MIME over 25 MB, or a JSON body over about 33.4 MB (25 MB of files after base64) | Send fewer or smaller attachments |
| 422 | invalid_schema | Unknown type, duplicate key, enum with fewer than 2 options, table without columns, more than 60 fields, or a description with no recognizable fields | Fix the field definitions; the message names the field |
| 422 | empty_email | No body text and no attachments | Check how the message is encoded in the request |
| 422 | invalid_request | A required parameter is missing or too long, since is not an ISO 8601 date-time, starting_after is not an email of this workspace, or attachment content is not base64 | Read message and fields |
| 429 | rate_limited | More than 120 requests per minute for the workspace | Wait Retry-After seconds |
| 503 | parser_unavailable | The parser could not answer during POST /parse; nothing was counted | Retry after a short pause with backoff |
Asynchronous problems do not become HTTP errors. An email submitted to an inbox is accepted with 202 and its later status, such as over_limit or failed, shows in the log and in GET /v1/emails/{id}, with the reason in the dashboard. The statuses are listed in sending emails.
Plan limits
| Limit | Sandbox | Starter | Growth | Scale |
|---|---|---|---|---|
| Price | Free, once | $49/mo or $24/mo billed yearly | $149/mo or $74/mo billed yearly | $499/mo or $249/mo billed yearly |
| Emails | 10 in total | 1,000 a month | 5,000 a month | 25,000 a month |
| Attachment pages | Attachments of 1 page, no scans | 300 a month | 2,000 a month | 10,000 a month |
| Inboxes | 1 | 5 | 25 | Unlimited |
| Seats | 1 | 1 | 5 | 20 |
| Raw email retention | 7 days | 30 days | 90 days | 365 days, configurable, or zero |
| Webhooks with retries | No | Yes | Yes | Yes |
| Review queue, classification, failure alerts | No | No | Yes | Yes |
| Custom inbound domain, SSO, audit log, priority queue | No | No | No | Yes |
Limits are monthly, also on yearly billing, in periods that start on the day your subscription started. The sandbox allowance is one-time and never renews. Moving to a higher plan takes effect at once and the difference is charged pro rata immediately. Seats count the owner, the members and pending invitations; an invitation beyond the plan's seats is refused until you move to a higher plan or remove someone. Other fixed limits:
- One email up to 25 MB: raw MIME up to 25 MB, JSON up to 25 MB of files after base64 (about 33.4 MB of request body); up to 20 attachments stored and 8 files read per email
- Schemas up to 60 fields, tables up to 20 columns, enums up to 30 options
- Up to 20 webhook endpoints per workspace; 15 second timeout per attempt
- API rate limit 120 requests per minute per workspace; list pages up to 100 emails
What counts toward usage
One email is counted when it is parsed, that is when the model has read it and a result exists. Its attachment pages are counted at the same moment on paid plans: a PDF page is one page, a text, CSV or similar file is one page per about 3,000 characters, an image is one page.
| Counted | Not counted |
|---|---|
| Every parsed email, also when it later goes to review or is rejected there | Duplicates (same Message-ID or same sender, subject and body within 30 days) |
Every POST /v1/parse call that returns a result | Emails from senders not on the allowed list |
| Every Test run in the schema editor | Gmail and Outlook forwarding confirmation emails |
The first parse of a replayed email that was never parsed, for example one stored as over_limit | Replays of emails that were already counted |
Emails stored as over_limit, and emails that failed before parsing (paused inbox, no schema, parser error) | |
| Webhook deliveries, retries and test events |
Usage is consumption, not a count of what you keep. Deleting an email, a schema or an inbox never gives emails or pages back. Check usage any time with GET /v1/usage from the API reference.
At the limit, the 80 percent alert and the daily safety brake
When the workspace reaches 80 percent of its monthly emails, the owner gets one email for that period. When the email or page limit is reached, parsing pauses: new emails are still received and stored with status over_limit, nothing is lost, and the owner gets an email that parsing has paused (at most once a day). After the next period starts or after an upgrade, replay those emails from the log or with POST /v1/emails/{id}/replay. An email that needs more pages than are left is stored as over_limit as a whole.
A forwarding loop, for example two mailboxes forwarding to each other, can burn a month of emails in an hour. Paid plans therefore have a daily safety brake at 30 percent of the monthly email limit in one day, far above a normal busy day:
| Plan | Emails per day before the brake |
|---|---|
| Starter | 300 |
| Growth | 1,500 |
| Scale | 7,500 |
Past the brake, emails are stored as over_limit with the reason "Daily safety limit reached (a forwarding loop protection)" and parsing resumes the next day at 00:00 UTC. Allowed senders on each inbox, described in inboxes and forwarding, are the best protection against loops.
Retention of raw email
ParsedMail keeps the raw message (body, headers and attachment files) for the retention period of your plan, then deletes it in an hourly cleanup. The parsed JSON, the confidence scores, the subject, the sender and the attachment names stay, so the log and the API keep working.
| Plan | Raw email kept |
|---|---|
| Sandbox | 7 days |
| Starter | 30 days |
| Growth | 90 days |
| Scale | 365 days by default, any value from 1 to 365 days, or zero retention |
With zero retention on Scale, the raw message is deleted at the first cleanup after processing, once it is at least 10 minutes old. Whatever the setting, the cleanup never touches an email that is still received, processing or needs_review, so reviewers always see the original next to the values; it is deleted after the review. After deletion an email cannot be replayed (410 purged). Email content is never used to train models. More on data handling is on the security page.
Frequently asked questions
Do I get usage back when I delete emails?
What happens to emails that arrive over my limit?
over_limit and not parsed. Replay them after an upgrade or when the next period starts; each one counts once when it is parsed.
Is a duplicate email charged?
duplicate, links to the original with duplicate_of and is not counted.
Why did parsing stop before my monthly limit?
over_limit and can be replayed.
Should I retry a 503 from the parse endpoint?
parser_unavailable is temporary and the failed call is not counted. Retry with a growing pause, for example after 2, 10 and 30 seconds.