waiaconnect

Documentation / Complete

The full error catalog

Markdown

Every code /v1 emits, with its HTTP status and what to do. They are stable: from the first integrator they are NOT renamed (that would break your switch). English only, on purpose (the code is the contract, the message is for pasting into a log and googling).

⚠ There are two separate catalogs. These are the HTTP errors (the { error: { code } } envelope, the immediate response). A message WhatsApp rejects AFTER the 202 does not show up here: its reason travels in lastErrorCode when you check the message status (WINDOW_24H_EXPIRED, RECIPIENT_OPTED_OUT, …). They live in the openapi under Message failure codes.

codeHTTPmessageaction
API_KEY_MISSING401The Authorization header is missing or malformedBug in your integration — send Authorization: Bearer wc_live_…
API_KEY_INVALID401The API key is invalid or has been revokedCheck / rotate the key in the panel
ACCOUNT_SUSPENDED403Account is suspended or cancelledResolve billing / contact support
RATE_LIMITED429Per-key rate limit exceededBack off and retry (limit 600/min per key)
IDEMPOTENCY_KEY_REQUIRED400The Idempotency-Key header is requiredSend a unique UUID in Idempotency-Key
INVALID_TYPE400type must be text, template, image, document, audio or videoFix type
INVALID_BODY400text.body (or template.name) is requiredFix the message body
INVALID_RECIPIENT400to must be a plausible E.164 number (8–15 digits)Fix to
AUDIO_CAPTION_NOT_ALLOWED400type audio does not accept a captionRemove audio.caption
CONNECTION_REQUIRED400Provide connectionId (conn_…) or from (phoneNumberId)Send one of them
CONNECTION_NOT_FOUND404No connection matches connectionId/from for this accountCheck the connection id (a number of ANOTHER account is also reported as not found)
CONNECTION_NOT_READY409The number exists but is not connected yet (details.status = its real state)Wait for it to become connected, or refresh its status in the panel — do NOT change your payload
MESSAGE_NOT_FOUND404No message with that id for this accountCheck the msg_… id
QUOTA_EXCEEDED429Plan message quota exceeded (policy block)Upgrade plan or wait for the period to renew
MEDIA_ID_REQUIRED400A media id is requiredInclude the media id in the path
MEDIA_NOT_FOUND404No media with that id for this account (or expired at Meta)Only fetch media ids from your own inbound events
MEDIA_TOO_LARGE413Media exceeds the size limitDo not proxy files above the limit
MEDIA_UPSTREAM502Could not resolve/download the media from MetaRetry; the media may have expired
TEMPLATE_NOT_APPROVED422The template you tried to send is known and NOT APPROVED (details.status = its state)Only send approved templates; check status in the panel or wait for Meta
TEMPLATE_HEADER_MEDIA_REQUIRED422The template has an IMAGE/DOCUMENT/VIDEO header and the send carries no header component. Caught before Meta (which answers an opaque 132000). details.example is the exact component to addAdd the header component with the file — link (public https) or id
TEMPLATE_HEADER_MEDIA_NOT_SUPPORTED422The send carries a media header parameter but the template has no media headerDrop the header component (a TEXT header takes text parameters, not a file)
TEMPLATE_HEADER_MEDIA_TYPE_MISMATCH422The header parameter type doesn't match the approved header format (details.expectedParameterType)Use the type the template declares — not the file's mime. A JPG on a DOCUMENT-header template still goes as document
TEMPLATE_PRECHECK_FAILED400The template would be rejected by Meta (details.issues[] lists each blocker + how to fix)Fix the issues and retry — the pre-checker caught them before Meta did
TEMPLATE_META_REJECTED400Meta rejected the template at creation (message = Meta's reason)Adjust per Meta's message and create again (an approved template can't be edited)
TEMPLATE_NOT_FOUND404No template with that id for this accountCheck the tpl_… id
TEMPLATE_NAME_TAKEN409A template with that name+language already exists on this numberUse a different name (Meta forbids duplicate names)
TEMPLATE_CATEGORY_INVALID400category must be UTILITY or MARKETING (draft approve/edit). AUTHENTICATION is not creatable — Meta wants a shape this builder doesn't produceSend UTILITY or MARKETING; for an auth template, create it in Meta Business Manager and sync it
TEMPLATE_RUBRO_INVALID400suggestedRubro is not a known catalog rubroOmit it or use a valid rubro
TEMPLATE_DRAFT_LIMIT_INVALID400draftLimit must be an integer between 1 and 100Send a value in range or omit it
TEMPLATE_DRAFT_NOT_FOUND404No pending draft with that id for this accountCheck the tpl_… id
REQUEST_BODY_TOO_LARGE413The request body is larger than the limit (1 MB; 5 MB on /webhook)Do not put a file inside the JSON. WAIA Connect stores no files: media travels by link and Meta downloads it. Host the file on a public https URL and send {"type":"document","document":{"link":"https://…"}}. ⚠ A Google Drive or Dropbox share URL returns an HTML page, not the file — Meta rejects it (MEDIA_DOWNLOAD_FAILED). If the body really is a large JSON, split the request
REQUEST_BODY_INVALID_JSON400The request body is not valid JSONCheck for a trailing comma, single quotes instead of double, or an empty body sent with Content-Type: application/json
REQUEST_BODY_UNSUPPORTED_ENCODING415The body uses an encoding or charset we cannot readSend UTF-8 JSON with Content-Type: application/json
INTERNAL500Internal server errorRetry; if it persists, contact support
APIKEY_NAME_REQUIRED400A non-empty name is required to create an API keySend a name
APIKEY_NOT_FOUND404No API key with that id for this accountCheck the key id
WEBHOOK_URL_REQUIRED400A url string is requiredSend a url
WEBHOOK_URL_UNSAFE400URL must be https to a public host (private/loopback/link-local rejected)Use a public https URL
WEBHOOK_EVENTS_INVALID400events must be known event typesUse message.received / message.status / message.echo / connection.status_changed / connection.created / usage.threshold_reached / connection.usage_threshold_reached / history.synced / template.status_changed
WEBHOOK_NOT_FOUND404No webhook endpoint with that id for this accountCheck the wh_… id
WEBHOOK_STATIC_HEADER_INVALID400The static header name is invalid or reservedUse a valid header name; never Authorization/Cookie/Host/Content-*
WEBHOOK_CREATE_FAILED500Could not create the webhook endpointRetry
ALERT_NOT_FOUND404No alert with that id for this accountCheck the alert id
CONNECTION_QUOTA_EXCEEDED429This number's monthly message limit is exhaustedRaise the limit for THIS connection (≠ upgrading the plan)
CONNECTION_EXTERNAL_ID_TAKEN409Another connection in this account already uses that externalIdPick a different externalId (unique within an account)
CONNECTION_LIMIT_INVALID400monthlyMessageLimit must be a non-negative integer or nullFix the value
INVALID_DATE400from/to must be YYYY-MM-DDFix the date
INVALID_PERIOD400period must be YYYY-MMFix the period
WEBHOOK_CONNECTION_INVALID400connectionId is not a valid connection idSend a numeric connection id or omit for the account default
WEBHOOK_CONNECTION_NOT_FOUND404No connection with that id for this accountCheck the connection id
ONBOARDING_MODE_INVALID400mode must be cloud_api, coexistence, or omittedFix mode
ONBOARDING_ATTEMPT_STATUS_INVALID400Unsupported signup-attempt status (abandoned is written by the server only)Send one of popup_returned, preflight_ok, completed, cancelled, failed
ONBOARDING_LANG_INVALID400lang must be es, it, en, pt, or omittedFix lang
ONBOARDING_EXPIRY_INVALID400expiresIn/expiresAt must be a single value between 5 minutes and 30 daysSend one of them, in range
ONBOARDING_RETURN_ORIGIN_INVALID400returnOrigin must be an exact https origin (public, no path)Send https://host (SSRF-guarded)
ONBOARDING_REDIRECT_URL_INVALID400redirectUrl must be a public https URLSend an https URL (SSRF-guarded)
BRAND_LOGO_URL_INVALID400brandLogoUrl must be a public https URLUse a public https image URL (SSRF-guarded)
BRAND_COLOR_INVALID400brandColor must be a #RRGGBB hex colorFix the color
BRAND_EMAIL_INVALID400brandSupportEmail must be a valid emailFix the email
BRAND_WEBSITE_INVALID400brandWebsite must be an https URLFix the URL