Errors
Each mxgate API error is JSON with a code, a message and the next step. This page lists every code by HTTP status and says what to do.
Each error of the API is JSON with the same shape: a code for a program, a sentence for a person, and the next step. This page lists every code.
The shape
{
"error": "rate_limited",
"message": "Too many DNS checks",
"fix": "Wait 30 seconds, then retry.",
"retry_after_seconds": 30
}| Field | Meaning |
|---|---|
error | The code. Let your program switch on it. |
message | One sentence for a person. Do not parse it. |
fix | The next step. Most errors have it. |
retry_after_seconds | Only with rate_limited: how long to wait. |
upgrade_url | Only with plan_limit: the page with the plans. |
The CLI prints message, then fix, and has exit code 1. With --json it prints the error body and the HTTP status. An MCP tool returns the same fields and status.
The codes
400: the request is not correct
| Code | When | What to do |
|---|---|---|
invalid_json | The body is not a JSON object. | Send a JSON object with Content-Type: application/json. |
invalid_email | The address for a signup or a key recovery is not an email address. | Correct the address. |
invalid_domain | The domain name is not valid. | Give the domain only, for example example.com. |
invalid_alias | The alias name is not valid. | Use letters, digits and . _ + -, or * for the catch-all. |
invalid_destination | to is empty, or a destination is not an email address. | Send {"to":["you@example.org"]}. |
invalid_recovery_token | The recovery token is wrong, used, or older than 60 minutes. | Ask for a new token: POST /v1/keys/recover. |
invalid_login_grant | The grant of the sign-in with Google is not valid, was used, or is older than 2 minutes. | Start the sign-in again on the page. |
invalid_state | GET /v1/login/google has no state of 16 to 64 characters. | Start the sign-in from /login. |
invalid_oauth_request | The request of an app on the consent page is not valid: the app is not registered, the redirect address is not the registered one, or PKCE is missing. | Start the connection again from the app. |
invalid_login_code | The code of the web sign-in is wrong, used, older than 10 minutes, or had 5 wrong attempts. | Ask for a new code: POST /v1/login. |
not_a_session | POST /v1/logout was made with an API key, not with a session token. | A key has no sign-out. To make a key stop working: POST /v1/keys/rotate. |
invalid_interval | interval for the paid plan is not month or year. | Send {"interval":"month"} or {"interval":"year"}. |
invalid_status | The status filter of the log is not a status. | Use one of the six statuses. |
invalid_direction | The direction filter of the log is not in or out. | Use in or out. |
invalid_before | before is not an ISO 8601 time. | Use the value of next_before. |
invalid_setting | A notification setting has a wrong type or an event that does not exist. | See Notifications and webhooks. |
no_webhook | A webhook test, but no webhook is set. | Set one: PUT /v1/notifications. |
invalid_from | from of a message is not an address. | Send "Name <you@example.com>". |
invalid_recipient | to is empty, or an address in to, cc, bcc or reply_to is not valid. | Correct the address. |
too_many_recipients | One message has more than 50 addresses. | Divide it into more messages. |
invalid_subject | subject is empty or has more than 255 characters. | Give a subject of 1 to 255 characters. |
invalid_text | text is empty. | Give the body as plain text. |
invalid_message_id | in_reply_to or references is not a Message-ID, or there are more than 50. | Use the message_id from the log. |
invalid_idempotency_key | The idempotency key is empty or has more than 200 characters. | Give a key of 1 to 200 characters. |
invalid_signature, invalid_event | Only on POST /v1/stripe/webhook, the endpoint that Stripe calls. | Your program does not call this endpoint. |
invalid_report | Only on POST /v1/status/report, the endpoint that the monitor of mxgate calls. | Your program does not call this endpoint. |
401: no valid key
| Code | When | What to do |
|---|---|---|
missing_api_key | The request has no key. | Send Authorization: Bearer <key>. For a new account: POST /v1/signup. |
invalid_api_key | The key is not valid, or it was replaced. | Examine the key. For a lost key, see Keys and sign-in. |
invalid_token | The token of a connected app is not valid or was revoked. | Connect the app again. |
invalid_session | The session token of the web sign-in is not valid, or the session ended. | Sign in again: POST /v1/login mails a code. |
invalid_report_token | Only on POST /v1/status/report. | Your program does not call this endpoint. |
402: a plan limit
| Code | When | What to do |
|---|---|---|
plan_limit | One domain, alias or destination too many, or a message above the send limit. | Use less, or get the paid plan. See Plans and limits. |
403: not permitted
| Code | When | What to do |
|---|---|---|
not_for_apps | A connected app tried to make an API key, or to list, connect or remove apps. | The owner does it with the API key or in the dashboard. |
account_suspended | The account is suspended. Reads work, changes do not. | Write to abuse@mxgate.io. |
from_not_allowed | The From address of a message is not at a domain of the account. | Use an address at one of your domains. |
404: not found
| Code | When | What to do |
|---|---|---|
not_found | No endpoint has this path. | GET / lists the endpoints. |
domain_not_found | The domain is not a domain of the account. | Add it first: POST /v1/domains. |
alias_not_found | The alias to remove does not exist. | List the aliases of the domain. |
app_not_found | The app to remove is not connected to the account. | GET /v1/oauth/apps lists the connected apps. |
credential_not_found | The SMTP login to remove does not exist. | GET /v1/domains/{domain}/smtp lists the logins. |
405: wrong method
| Code | When | What to do |
|---|---|---|
method_not_allowed | The path exists, but not with this method. | fix names the methods that the path accepts. |
409: a conflict with the current state
| Code | When | What to do |
|---|---|---|
already_registered | The address has an account already. | Use its key. For a lost key: POST /v1/keys/recover. |
domain_taken | Another account holds the domain. | If that account did not verify it, try again after 24 hours. If you own the domain, write to hello@mxgate.io from an address at the domain. |
send_as_not_ready | The domain cannot send yet, or sending is paused. | Add the DKIM record and run the check. If sending is paused, write to abuse@mxgate.io. |
too_many_credentials | The domain has 5 SMTP logins already. | Remove a login that you do not use. |
idempotency_key_reused | The idempotency key was used for a different message. | Use a new key for a new message. |
send_in_progress | A call with this idempotency key is not complete. | Look for the message in the log before you send it again with a new key. |
already_subscribed | A payment link was asked for, but the account has the paid plan. | POST /v1/billing/portal gives the link to change or cancel. |
already_paid | A person at mxgate turned the paid plan on for the account. It needs no payment. | Write to hello@mxgate.io to change it. |
no_subscription | A billing link was asked for, but the account never opened a payment page. | POST /v1/billing/checkout gives a payment link. |
413: too large
| Code | When | What to do |
|---|---|---|
body_too_large | The body of the call is larger than 64 KB. | Send a smaller body. |
422: the content is refused
| Code | When | What to do |
|---|---|---|
disposable_email | A signup with a disposable address. | Use an address that you keep. |
reserved_domain | The domain is used by mxgate itself. | Add a domain that you own. |
forwarding_loop | A destination is on the domain of the alias, or on another domain that mxgate forwards. | Forward to a real mailbox on another domain. |
invalid_webhook_url | The webhook address is not a public https:// URL. | Use a public https:// URL with no user name or password. |
recipient_refused | mxgate did not accept a recipient of a message. Nothing was sent. | Correct the address or remove it, then send again. |
message_refused | mxgate did not accept the message, for example as spam. Nothing was sent. | Change the text, then send again. |
429: too many calls
| Code | When | What to do |
|---|---|---|
rate_limited | Too many calls of one type. See the rate limits. | Wait retry_after_seconds, then try again. |
too_many_signups | More than 3 signups in a day from one IP address. | Try again the next day. |
500, 502, 503: a failure on the side of mxgate
| Code | When | What to do |
|---|---|---|
internal (500) | Something failed in the API. | Try again. If it fails again, write to hello@mxgate.io. |
payment_provider_failed (502) | Stripe did not answer as expected. | Try again in a minute. |
google_sign_in_off (503) | The server has no sign-in with Google. | Sign in with a code: POST /v1/login. |
payments_not_configured (503) | The server takes no payments. | Write to hello@mxgate.io. |
send_unavailable (503) | The mail server did not take the message. Nothing was sent. | Try again in a minute. |
status_reports_off (503) | Only on POST /v1/status/report. | Your program does not call this endpoint. |
Errors of the OAuth endpoints
POST /oauth/register and POST /oauth/token answer in the form of RFC 6749: error and error_description, and also message with the same text. The codes are invalid_redirect_uri, invalid_client_metadata, invalid_request, unsupported_grant_type and invalid_grant. A code that fails one check is used up: the client must start again.
How an agent uses fix
- Switch on
error. Do not match the text ofmessage. - Read
fixand do the step, if the step is in the task that the person gave. Then make the first call again. - For
rate_limited, waitretry_after_seconds. Do not try again before that. - For a 5xx error, try again one time after a minute. Then stop and tell the person.
- For
plan_limit, showmessageto the person and ask before you get a payment link. An agent cannot pay. - Stop and ask the person when the step needs them: a confirmation link in a mailbox, a recovery token from a mail, a payment, or consent to replace an MX record.
With send_email, give an idempotency_key. A retry after an error then cannot send a second copy.