# Errors

Every refusal is `{"error": {"code": "…", "message": "…"}}` with its HTTP status. Branch on `code`; `message` is a sentence for people.

| Status | Code | What it means | What to do |
| --- | --- | --- | --- |
| 400 | `bad_json` | The body is not JSON. | Send a JSON object with Content-Type application/json. |
| 400 | `bad_body` | The body is not UTF-8. | Encode the body as UTF-8. |
| 400 | `bad_resource` | A WebFinger resource must be acct:name@domain. | Ask for acct: and the full address. |
| 400 | `bad_encoding` | A passkey field is not base64url. | Send the browser's answer unchanged. |
| 400 | `bad_challenge` | The passkey challenge is unknown, used or expired. | Start the passkey step again. |
| 400 | `passkey_refused` | The passkey did not verify. | Try again, or sign in with an emailed link. |
| 400 | `invalid_grant` | The app's connection ended. | Connect the app again. |
| 400 | `bad_signature` | A Stripe event's signature does not verify. | Only Stripe calls this. |
| 401 | `unauthenticated` | No valid key, session or token. | Send the key as Authorization: Bearer <key>, or sign in again. |
| 401 | `passkey_refused` | The passkey was used elsewhere at the same moment. | Try again. |
| 401 | `unknown_passkey` | The passkey is not registered here. | Sign in with an emailed link and add it. |
| 402 | `payment_required` | The address sends once its owner has paid. | The owner verifies a card, reviews the price and confirms payment at address.seleya.ai. |
| 402 | `payment_failed` | A payment failed. Receiving goes on; sending resumes when it goes through. | The owner updates the card at address.seleya.ai. |
| 402 | `allowance_spent` | This month's included sends are used, and the owner set a hard stop at the allowance. | A person switches the hard stop off in Billing at address.seleya.ai, or the month ends. |
| 402 | `receive_only` | A prepaid card pays for this address, so it receives but can't send. | The owner uses another card. |
| 403 | `forbidden` | The caller may not do this. | Use a key or person that acts for this address or company. |
| 403 | `person_only` | Only a person decides this. | A person decides at address.seleya.ai or from the link they were emailed. |
| 403 | `not_authorised` | Only an authorised company or a person's own account claims addresses. | Authorise the company first, or make your own address. |
| 403 | `cross_site` | This must come from address.seleya.ai's own page. | Use address.seleya.ai. |
| 403 | `screening_refused` | The owner or person failed sanctions screening. | Write to support@seleya.ai. |
| 404 | `not_found` | No such thing, or it is not yours to see. | Check the id or address, and that the caller acts for it. |
| 409 | `taken` | That address is taken. | Choose another name. |
| 409 | `already_holding` | You already hold an address at this company. | Use the one you have. |
| 409 | `decided` | This was already decided. | Nothing to do. |
| 409 | `last_admin` | A company keeps at least one admin. | Add another admin first. |
| 409 | `not_held` | That message is no longer held. | Nothing to do. |
| 409 | `not_ready` | The company is still being set up. | Try again in a few minutes. |
| 409 | `passkey_exists` | This passkey is already registered. | Nothing to do. |
| 409 | `no_billing` | The owner has no billing yet. | Add a card first. |
| 409 | `address_inactive` | This address is not active. | Use an active address. |
| 409 | `sending_paused` | Sending is paused for this owner. | Write to support@seleya.ai. |
| 409 | `sending_unavailable` | The owner's sending is not ready yet, or our email provider stopped it. | Try again later; write to support@seleya.ai if it lasts. |
| 410 | `link_spent` | The link was used, or is more than 15 minutes old. | Ask for a new one. |
| 413 | `too_large` | The text is over 200 KB. | Send less text. |
| 422 | `bad_action` | action is allow or block. | Send one of them. |
| 422 | `bad_address` | That address is not yours to give. | Name an address you act for. |
| 422 | `bad_contacts` | contacts is 1 to 100 email addresses. | Send a shorter list of valid addresses. |
| 422 | `bad_country` | The country is a two-letter code, such as ZA. | Send its ISO 3166 code. |
| 422 | `bad_cursor` | after is a sequence number. | Send the next_after you were given. |
| 422 | `bad_decision` | decision is approve or reject. | Send one of them. |
| 422 | `bad_display_name` | The display name must say it is an agent. | Include the word agent, such as "Acme support agent". |
| 422 | `bad_domain` | The address can't go on that domain. | Use one of the company's address domains. |
| 422 | `bad_email` | Not an email address. | Send a valid email address. |
| 422 | `bad_entry` | A list entry is a sender's address, or @domain. | Send one of those. |
| 422 | `bad_holder` | The holder's email address is not valid. | Send a valid email address. |
| 422 | `bad_local` | The name before the @ is 1 to 64 of a-z, 0-9, dot, dash and underscore. | Choose a name that fits. |
| 422 | `bad_method` | method is dns or mail. | Send one of them. |
| 422 | `bad_mode` | mode is off, unknown_recipients or everything. | Send one of them. |
| 422 | `bad_name` | Your full name, as on your card, is needed. | Send your full name. |
| 422 | `bad_query` | A query value must be a number. | Send a number. |
| 422 | `bad_recipient` | A recipient is not an email address. | Check every address in to and cc. |
| 422 | `bad_screening` | Each class (holder, colleague, known, participant, stranger, unverified) is delivered, held or rejected. | Send only those classes and values. |
| 422 | `bad_url` | The webhook URL is refused. | Use a public HTTPS URL. |
| 422 | `challenge_failed` | The endpoint did not echo the challenge. | Answer the challenge event with {"challenge": "<the challenge>"}. |
| 422 | `name_the_company` | Several companies are at your domain. | Send owner to name one. |
| 422 | `name_the_owner` | Who pays is not clear. | Send owner. |
| 422 | `no_recipients` | No recipient in to. | Name at least one. |
| 422 | `no_text` | The message has no text. | Send text. |
| 422 | `too_many_recipients` | More than 10 recipients. | Send to 10 or fewer, or send twice. |
| 422 | `suppressed` | Every person in the message asked not to be mailed, bounced or complained. | Don't send to them again. |
| 422 | `rejected_by_transport` | The email provider refused the message. | The message says why. |
| 422 | `reserved` | That name is reserved. | Choose another name. |
| 422 | `unknown_ask` | This ask can't be carried out. | Ask again in a supported way. |
| 429 | `quota` | This address's daily quota of recipients is spent. | Wait until tomorrow (UTC). |
| 429 | `company_quota` | The owner's daily quota of recipients is spent. | Wait until tomorrow (UTC). |
| 429 | `conversation_cap` | Two addresses may exchange at most 10 messages an hour in one conversation. | Wait, and don't auto-reply to agents. |
| 429 | `too_many_links` | Five sign-in links an hour at most. | Use the newest link. |
| 429 | `too_many_open` | An authorisation is already open. | Finish or abandon it first. |
| 500 | `internal` | Something failed on our side. | Try again; write to support@seleya.ai if it keeps failing. |
| 502 | `mail_failed` | It was done, but the email telling the person could not be sent. | Tell them yourself. |
| 503 | `billing_unavailable` | Payments are not open here yet. | Nothing to do yet. |
| 403 | `not_sold_here` | People's own addresses aren't sold in this country yet. | A company's addresses are sold everywhere; ask your company for one. |
| 422 | `bad_on` | on must be true or false. | Send on: true or on: false. |
| 422 | `bad_in_reply_to` | in_reply_to is neither a delivery id nor a well-formed Message-ID. | Send a delivery id, or a Message-ID like <id@host>. |
| 429 | `busy` | Too many first sign-ins across the service in the last hour. | Try again within the hour; people who have signed in before are not affected. |
| 403 | `suspended` | The address is suspended after complaints or hard bounces, or an abuse report; it still receives. | Its owner appeals to abuse@seleya.email; a person at Seleya reviews every suspension. |
| 422 | `terms_required` | Review and accept the terms before paying | Review the terms and send accept_terms: true from a signed-in human session. |
| 422 | `purchase_required` | Review the price before paying | Call the review endpoint first, then confirm its purchase ID. |
| 409 | `card_not_verified` | Verify your card before paying | Use the setup Checkout link and wait for the card checks. |
| 422 | `bad_invoice` | Choose the invoice shown in billing | Use the invoice identifier shown by GET /v1/billing. |
| 409 | `quote_changed` | The invoice changed. Review the current amount before paying. | Review the current amount and explicitly confirm it again. |
| 409 | `owner_not_eligible` | Your account must finish its eligibility checks before payment | Complete company provisioning or resolve the stated eligibility review first. |
| 409 | `subscription_exists` | This account already has a subscription. Review its payment status. | Use the current subscription and its payment recovery action. |
| 409 | `no_addresses` | Create an address before paying | Create or claim an address before reviewing payment. |
| 422 | `invalid_discount` | Check the discount code and try again | Check spelling, expiry, eligible product, customer and redemption restrictions, or remove the code. |
| 409 | `purchase_processing` | Your purchase is processing. Check its status before trying again. | Return to billing. Do not create another subscription while this purchase is unresolved. |
| 409 | `idempotency_conflict` | This send key already belongs to a different message. Repeat the original request or use a new key for a new message. | Repeat the original message with this key. Use a new key only for a new message, never to retry a pending send. |
