Error codes
The error codes the API returns, the send denial reasons, and what to do about each.
Error responses usually look like {"error": "...", "detail": "..."}. Only branch on error. A first 403 policy_denied response carries decision instead of detail.
HTTP errors
| Status | error | Meaning and what to do |
|---|---|---|
400 | invalid_request | The request is malformed. Fix it using detail. |
400 | invalid_recipient | An address can't receive mail in that form. Use plain local@domain addresses. |
400 | idempotency_key_required | Add an Idempotency-Key header. |
401 | unauthorized | The token is missing, wrong, revoked, or expired. |
403 | forbidden | The token lacks the scope, or you asked for another agent's data. |
403 | policy_denied | The policy blocked the send. Check decision.reasons (table below). |
404 | message_not_found · thread_not_found · approval_not_found · attachment_not_found · schedule_not_found · audit_not_found | Doesn't exist or can't be seen. Quarantined mail looks the same as missing mail. |
409 | idempotency_key_reused | The key was used for a different request. Use a new key. |
409 | policy_changing | The policy is being changed. Try again shortly. |
422 | forward_refused_injection_risk | Forwarding this email was refused. Write a new email in your own words. |
429 | cancel_rate_limited | Too many schedule cancellations. Tell the owner. |
502 | send_failed | Nothing went out. You can retry with a new idempotency key. |
Errors on every path
| Status | error | Meaning and what to do |
|---|---|---|
400 | invalid_json | The body isn't valid JSON. |
400 | invalid_request | A query parameter was given more than once. |
404 | route_not_found | No such path. Check the path and method. |
405 | method_not_allowed | This path doesn't take that method. The Allow response header lists the ones it takes. |
413 | payload_too_large | Request bodies can be up to 10 MiB (10,485,760 bytes). |
500 | internal_error | The server couldn't process the request. detail includes a request ID. |
503 | service_unavailable | Temporarily unavailable. detail includes a request ID. |
After a 500, a 503, a timeout, or a network error, wait a little and retry with the same Idempotency-Key. Mail that already went out won't go out twice. Under heavy load you may get a 429, whose body may not follow this shape; wait and retry with the same key too. If it keeps happening, contact support with the request ID.
Codes specific to schedules, verification codes, and webhooks are on their pages: Scheduled email, Verification codes, Webhooks.
Common denial reasons
These are the codes you'll see most often in decision.reasons of policy_denied and in MCP denied results. While the cause remains, retrying gives the same result. Retrying with the same idempotency key returns the same denial even after the cause is fixed, so after fixing it, or waiting retry_after_seconds, send with a new idempotency key.
| Reason | Meaning | What to do |
|---|---|---|
recipient_not_allowlisted | The recipient isn't on the outbound allowlist. | The owner adds them. |
recipient_blocklisted | The recipient is on the outbound blocklist. | The owner removes them. |
outbound_disabled | The outbound mode is Block all. | The owner changes the mode. |
recipient_is_self | The agent tried to email its own address. | It can't email itself. |
suppression_list | The address has a history of bounces or spam reports. | Check the address. |
rate_limit_per_minute · rate_limit_per_hour · rate_limit_per_day | A sending limit was reached. | Wait, then send. |
recipients_per_message · plan_recipients_per_message | Too many recipients in one message. | Split it up. |
daily_send_limit | The organization's daily sending limit was reached. For new organizations this limit rises over the first weeks after the first send. | Wait and send later. Upgrading doesn't lift it. |
plan_daily_cap | The plan's daily recipient limit for the organization was reached. | Send tomorrow. Upgrading lifts it, but payments aren't open during the beta. |
org_pending_review | The organization is under operator review. | Wait until review is done. |
org_review_rejected | Sign-up wasn't approved. | Contact support. |
org_owner_paused | Emergency stop is on for the whole organization. | The owner resumes it. |
org_abuse_freeze | Operators froze sending for the organization. | Contact support. |
org_billing_blocked | Sending is blocked by a billing problem. | The owner checks Settings › Plan. |
agent_not_active | The agent is stopped or not active. | The owner checks. |
from_forgery | from isn't this agent's address. | Use the agent's own address. |
evaluation_error | The send couldn't be evaluated, so it was blocked to be safe. | Try again later with a new idempotency key. If it keeps happening, contact support. |
All reason codes
These are the codes the public API currently returns in decision.reasons and in audit reasons. Older audit records may show earlier names. Allowed sends carry reasons too. "Old mode" means an old outbound mode (Approval required, Replies only) that Atmark operators set. See Approvals.
Denied
| Code | Meaning |
|---|---|
org_pending_review | The organization is under operator review. |
org_review_rejected | Sign-up wasn't approved. |
org_owner_paused | Emergency stop is on for the whole organization. |
org_abuse_freeze | Operators froze sending for the organization. |
org_billing_blocked | Sending is blocked by a billing problem. |
agent_not_active | The agent is stopped or not active. |
outbound_disabled | The outbound mode is Block all. |
from_forgery | from isn't this agent's address. |
recipient_is_self | The agent tried to email its own address. |
suppression_list | The address has a history of bounces or spam reports. |
recipient_blocklisted | A recipient is on the outbound blocklist. |
recipient_not_allowlisted | A recipient isn't on the outbound allowlist. |
rate_limit_per_minute · rate_limit_per_hour · rate_limit_per_day | The agent's per-minute, hourly, or daily sending limit was reached. |
recipients_per_message | Too many recipients for the agent's policy limit. |
plan_recipients_per_message | Too many recipients for the plan's limit. |
recipient_ceiling_exceeded | Too many recipients for the hard cap no plan can exceed. |
daily_send_limit | The organization's daily sending limit was reached. For new organizations it rises over the first weeks after the first send. |
plan_daily_cap | The plan's daily recipient limit for the organization was reached. |
budget_exhausted | The agent's sending budget was used up. Contact support. |
evaluation_error | The send couldn't be evaluated, so it was blocked to be safe. |
release_window_expired | It was approved but couldn't be sent within the allowed time, so it was closed (old mode). |
reply_only_no_inbound_thread | It tried to send outside a received thread (old mode "Replies only"). |
reply_only_inbound_quarantined | The received email being replied to is quarantined (old mode "Replies only"). |
Allowed
| Code | Meaning |
|---|---|
allowlist_match | Every recipient is on the outbound allowlist. |
unrestricted_mode | The outbound mode is All. |
not_blocklisted | In Blocklist mode, no recipient is on the blocklist. |
approval_granted | A person approved it. |
standing_approval | A recipient (or domain) approved before (old mode). |
seed_relationship | A recipient the owner listed when creating the agent (old mode). |
reply_within_thread · auto_approve_reply_within_thread | Allowed as a reply within the same thread (old mode). |
auto_approve_verification_sender | Allowed as a reply to a verification-mail sender (old mode). |
auto_approve_domain | A domain the owner allowed automatically (old mode). |
Awaiting approval
| Code | Meaning |
|---|---|
new_recipient | A first-time recipient needs a person's approval (old mode "Approval required"). |
bootstrap_grace | Marks a decision made during the starting period of the old mode "Replies only". |
Feedback on this page? Write to support@atmark.ai.