Reference

Errors

Every error the API returns has an HTTP status and a stable code. General codes can come from any call; the others belong to one product.

General error codes

Every error is a flat JSON object: code, message (follows Accept-Language), messageEn, messageFr, statusCode, and an optional details field with more about what failed. A malformed request, such as a missing field or a value outside its documented bounds, returns 422 VALIDATION_ERROR with details naming the field. A request the framework itself rejects before your code runs, such as invalid JSON (400), a body over the size limit (413) or an unsupported content type (415), returns a Fastify FST_ERR_* code with an English-only message instead.

HTTPCodeMeaning
401UNAUTHORIZEDMissing or invalid API key
401API_KEY_REVOKEDThis API key has been revoked. Use a different key.
402INSUFFICIENT_BALANCEAccount balance too low
402PAYMENT_REQUIREDThe account has not completed its first top-up. Live keys are blocked until then except a few account and pricing reads; test keys are unaffected.
403FORBIDDENThe API key lacks the permission this action needs, skip_consent_check was sent with a live key, the account is suspended or closed (see details.reason), or the id in the path belongs to another account
403LIVE_KEY_REQUIREDA test key was used for something only a live key can do.
403PERMISSION_ESCALATIONA new or rotated key asked for permissions broader than the caller's own, without a password step-up.
403KEY_FENCEDThis key is restricted by its own allow or deny lists or by default-deny, so it cannot change those lists or the groups and contacts they include, change any key’s list settings, create keys, or rotate any key but itself.
403ACCOUNT_NOT_VERIFIEDThe account has not verified an owner phone number yet, required before a live send.
403SENDING_PAUSEDLive sending is paused on this account (details show when it resumes and why)
404NOT_FOUNDNo resource matches the given id.
409DEAD_LETTER_ALREADY_REPLAYEDThis event was already replayed, or a replay of it is in progress. Nothing was sent, and retrying won't help.
409CONFLICTA resource with that identifier already exists, or a key rotation failed because the key was already revoked, is a session key, or another request rotated it first
422VALIDATION_ERRORRequest body or query failed validation (see details)
422WEBHOOK_LIMIT_REACHEDReached the limit of 10 webhook endpoints per account. Delete one before registering another
429RATE_LIMITEDToo many requests. Slow down
500INTERNAL_ERRORAn unexpected server error occurred. Retry
502WEBHOOK_REPLAY_FAILEDThe endpoint did not accept the replay. The event stays in the dead-letter queue
503SERVICE_UNAVAILABLENew registrations are temporarily disabled (POST /v1/accounts), or phone verification is temporarily unavailable (POST /v1/accounts/:id/phone-verification). Retry later

Codes that belong to one product have their own sections below: SMS error codes and email error codes.

SMS error codes

The codes below are specific to SMS, phone numbers, verification and CASL. Any call can also answer with the codes in the general section above, such as VALIDATION_ERROR, INSUFFICIENT_BALANCE and NOT_FOUND.

HTTPCodeMeaning
403NUMBER_LIMIT_REACHEDAccount has reached its phone number limit
403PHONE_NUMBER_NOT_OWNEDThe from number is not provisioned on this account.
403ALLOW_LIST_BLOCKEDRecipient is not on the API key's ALLOW list
403DENY_LIST_BLOCKEDRecipient is on the API key's DENY list
403SEND_LIMIT_REQUEST_TOO_EARLYVolume requests open once the account's probation period is over.
404VERIFICATION_NOT_FOUNDVerification ID not found or not owned by this account
404CONTACT_NOT_FOUNDContact not found
404CONTACT_GROUP_NOT_FOUNDContact group not found
404CONTACT_GROUP_MEMBER_NOT_FOUNDThat contact is not a member of this group
404CONTACT_LIST_NOT_FOUNDContact list not found
404CONTACT_LIST_ENTRY_NOT_FOUNDContact list entry not found
409VERIFICATION_ALREADY_VERIFIEDThis number has already been verified
409PURCHASE_IN_PROGRESSAnother number purchase is in flight. Retry shortly
409ALLOWANCE_REQUEST_PENDINGAn allowance request is already awaiting review
409PHONE_NUMBER_SUSPENDEDThis number's monthly charge could not be collected. Top up to reactivate it.
409SEND_LIMIT_REQUEST_PENDINGA volume request is already awaiting review.
409IDEMPOTENCY_KEY_REUSEDThe same Idempotency-Key was sent with a different to, from or body.
409CONTACT_ALREADY_EXISTSA contact with that phone number or email already exists
409CONTACT_IN_USERemove the contact from its groups and lists before clearing its phone number
409CONTACT_GROUP_ALREADY_EXISTSA contact group with that name already exists
409CONTACT_GROUP_MEMBER_EXISTSContact is already a member of this group
409CONTACT_LIST_ALREADY_EXISTSA contact list with that name already exists
409CONTACT_LIST_ENTRY_EXISTSThis entry already exists in the list
410VERIFICATION_EXPIREDThe verification code has expired
422NON_CANADIAN_NUMBERNot a valid Canadian E.164 number
422UNDELIVERABLE_NUMBERThe number failed at the carrier three times running (for any customer); refused without charge for 90 days.
422NOT_A_MOBILE_NUMBERThe destination is a landline or VoIP number. The carrier refuses it before sending; nothing is charged.
422RESERVED_DESTINATIONThe destination is in a reserved exchange (555-XXXX, N11, carrier test codes). Refused before anything is sent; nothing is charged.
422MESSAGE_TOO_LONGBody would exceed the carrier limit of 10 SMS parts (≈1,530 GSM-7 or 670 Unicode characters). Nothing is charged
422VERIFICATION_INVALID_CODEIncorrect code. attempts_remaining shows how many tries are left
422INVALID_ALLOWANCE_REQUESTRequested allowance must exceed your current limit
422LINK_SHORTENER_BLOCKEDLink shorteners are refused because carriers filter them. Use the full URL
422BROADCAST_TOO_LARGEContact group too large for one broadcast (250 members by default). Split it and send in batches
422CANNOT_ERASE_OWN_NUMBERThat number belongs to your account. Erasure is only for a subscriber's number
422TOO_MANY_AREA_CODESSearch at most 25 area codes at a time
422INVALID_PHONE_NUMBERNot a valid E.164 phone number
422CONTACT_LIST_ENTRY_INVALIDEach entry must specify exactly one of phone_number, contact_id or contact_group_id
422CONTACT_HAS_NO_PHONEThe contact has no phone number, so it cannot join an SMS group or list
429RECIPIENT_RATE_LIMITEDMore than 30 messages to one recipient in an hour or 100 in a day; retry after the Retry-After header.
429VERIFICATION_MAX_ATTEMPTSToo many wrong attempts. This verification is locked
429DAILY_LIMIT_REACHEDDaily sending limit reached (details show your limit and count). Request a higher volume once eligible
429FANOUT_LIMIT_REACHEDThis exact message already reached the maximum number of distinct recipients allowed in 24 hours
429NUMBER_RATE_LIMITEDThis sending number reached its per-minute limit. Retry shortly
429BROADCAST_LIMIT_REACHEDBroadcast limit reached for this account in the last 24 hours
451OPT_OUT_BLOCKEDRecipient has opted out, so the send is legally blocked
451NO_CONSENTNo valid CASL consent on file
451CONSENT_EXPIREDImplied consent expired (2-year CASL limit)
451DNCL_BLOCKEDNumber on the CRTC DNCL with no exemption (coming soon; not currently returned)
501DNCL_COMING_SOONCRTC Do Not Call List checking is not available yet.
501TOLLFREE_800_COMING_SOON1-800 numbers are not available yet. Choose another toll-free prefix or a local number.
502CARRIER_ERRORThe carrier returned an error while sending.
502PROVISIONING_FAILEDThe carrier could not complete this number purchase. Nothing was charged.
502NUMBER_SEARCH_FAILEDNumber search is temporarily unavailable.
502RELEASE_FAILEDThe carrier did not accept the release. The number is still yours; retry shortly
503CARRIER_UNAVAILABLEThe carrier could not be reached; nothing was sent or charged. Retry shortly.
503CARRIER_TIMEOUTThe carrier did not answer in time, so the message may or may not have been sent. Nothing is charged. Check the message status before sending again: a retry with the same Idempotency-Key returns the failed message instead of sending it again.

Email error codes

Email calls can also answer with the codes in the general section above, such as VALIDATION_ERROR, INSUFFICIENT_BALANCE and NOT_FOUND.

HTTPCodeMeaning
403EMAIL_DOMAIN_NOT_ALLOWEDThe API key is restricted to certain sending domains, and this one isn't in its list.
403TEST_KEY_REQUIREDOnly a test key can call this endpoint.
404RECEIVED_EMAIL_NOT_FOUNDNo received email with that id.
409EMAIL_DOMAIN_ALREADY_EXISTSThe domain is already on this account.
409EMAIL_DOMAIN_IN_USEAnother account holds this domain. details.retry_after says when an unverified claim lapses; a verified domain stays with its owner.
409EMAIL_DOMAIN_HAS_INFLIGHTThe domain still has queued, scheduled or sending email.
409EMAIL_IDEMPOTENCY_IN_PROGRESSA request with this Idempotency-Key is still being processed. Retry the same key shortly rather than using a new one.
409EMAIL_TEMPLATE_ALIAS_TAKENAnother template on this account already uses this alias.
409EMAIL_TEMPLATE_IN_USEA scheduled email uses this template. Cancel it, or wait until it's sent, then delete the template.
409RECEIVING_REQUIRES_VERIFIED_DOMAINThe domain must be verified for sending before receiving can be turned on.
410ATTACHMENT_EXPIREDThe attachment or raw message is past its 40 day retention window.
413EMAIL_ATTACHMENT_TOO_LARGEAttachments exceed 25 MB.
422EMAIL_INVALID_ADDRESSAn address is not a valid email address.
422EMAIL_DOMAIN_NOT_VERIFIEDThe from domain is not a verified sending domain on this account.
422EMAIL_DOMAIN_INVALIDNot a valid domain name.
422EMAIL_DOMAIN_LIMIT_REACHEDThis account has reached its sending-domain limit (5 by default; failed domains do not count). Answered to adding a domain, or to verifying a failed domain that would take a slot back. Remove one or ask support to raise it.
422EMAIL_TEST_ADDRESS_LIVE_KEYA live key can't send to an address on test.honkio.ca; those addresses are for test keys only.
422EMAIL_HEADER_INVALIDThe from address or a header is malformed, or is one honkio sets itself.
422EMAIL_ATTACHMENT_FETCH_FAILEDAn attachment given by path could not be fetched. details.reason says why: blocked_address, http_status, timeout, too_large or network.
422EMAIL_ATTACHMENT_TYPE_BLOCKEDThe attachment is an executable or script type (.exe, .js, .bat, .jar and the like) that receiving mail servers reject. details.filename names it. Nothing is charged.
422EMAIL_RENDER_FAILEDThe content could not be rendered.
422EMAIL_BATCH_TOO_LARGEToo many recipients in one call.
422EMAIL_COMMERCIAL_MULTI_RECIPIENTA commercial email goes to exactly one recipient. Use a batch to reach several.
422EMAIL_NOT_SCHEDULEDOnly a scheduled email can be moved or cancelled.
422EMAIL_TEMPLATE_NOT_PUBLISHEDThe template has no published version yet. Publish it before sending with it.
422EMAIL_TEMPLATE_VARIABLE_MISSINGA template variable has no value and no fallback. details.keys lists the missing ones.
422EMAIL_TEMPLATE_UNDECLARED_VARIABLEThe template body uses a variable it doesn't declare. Add it to variables; details.keys lists them.
422EMAIL_TEMPLATE_LIMIT_REACHEDThis account has reached the limit of 200 email templates. Delete one to create another.
422SIMULATE_RECIPIENT_NOT_OWNEDEvery simulated recipient must be your test address or a domain this account owns in test mode.
422INBOUND_ADDRESS_DISABLEDYour managed inbound address is switched off. Turn it on before sending to it.
451EMAIL_SUPPRESSEDThe recipient is on your suppression list.
451EMAIL_NO_CONSENTCommercial email needs CASL consent on file for the recipient.
451EMAIL_OPT_OUT_BLOCKEDThe recipient unsubscribed from this sender.
503EMAIL_ATTACHMENTS_UNCONFIGUREDAttachment storage isn't configured, so emails with attachments can't be sent right now.

Delivery failure codes

These never come back as an HTTP response: the call already answered 201 before SES tried to send. If delivery still fails, one of these appears as failure_code on the email.failed or email.rejected webhook, and the charge is refunded.

CodeMeaning
SES_THROTTLINGSES throttled the send; the email failed and was refunded; send it again.
SES_MESSAGE_REJECTEDSES rejected the message outright, for example malformed content; the email failed and was refunded; fix the content and send it again.
SES_DOMAIN_NOT_VERIFIEDSES had not finished verifying the from domain, even though honkio's own check passed; the email failed and was refunded; wait for verification to finish, then send it again.
SES_ERRORAn SES error that doesn't fit the other codes; the email failed and was refunded; send it again.
EMAIL_ATTACHMENTS_UNAVAILABLEThe stored attachment bytes could not be read at send time; the email failed and was refunded; send it again.