waiaconnect

Documentación / Completo

El catálogo completo de errores

Markdown

¿Programás con IA? Conectala a tu cuenta por MCP: revisa tu configuración, crea webhooks y plantillas con tu confirmación y te escribe el código. Ver cómo →

Todos los code que emite /v1, con su HTTP y qué hacer. Son estables: desde el primer integrador NO se renombran (romperían tu switch). Inglés solamente, a propósito (el code es el contrato, el message es para pegar en un log y buscar en Google).

⚠ Hay dos catálogos distintos. Este son los errores HTTP (el sobre { error: { code } }, la respuesta inmediata). Un mensaje que WhatsApp rechaza DESPUÉS del 202 no aparece acá: su motivo viaja en lastErrorCode cuando consultás el estado del mensaje (WINDOW_24H_EXPIRED, RECIPIENT_OPTED_OUT, …). Están en el openapi bajo Message failure codes.

🔴 Cuenta bloqueada por cobro: 402, no lo reintentes. Con la prueba vencida, /v1 contesta 402 TRIAL_EXPIRED; con un pago vencido, 402 BILLING_PAST_DUE. Sin Retry-After: reintentar no sirve. El cuerpo trae hasta cuándo seguís recibiendo (details.receivingUntil), el enlace a Cobro (details.billingUrl) y el mensaje en tu idioma (details.localizedMessage). Frená tu cola y elegí un plan; el envío vuelve en el momento. Hasta el 19/10/2026 era 403 ACCOUNT_SUSPENDED, que hoy queda sólo para una suspensión manual o una baja.

codeHTTPmessageacción
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
TRIAL_EXPIRED402Your free trial ended on <date>. Sending is paused; receiving continues until <date>. Add a plan: <link> (details: trialEndedAt, receivingUntil, receivingStopped, billingUrl, localizedMessage). No Retry-AfterDo NOT retry: stop your queue and pick a plan in Billing (details.billingUrl); sending comes back right away
BILLING_PAST_DUE402Your payment is overdue and sending is paused since <date>; receiving continues until <date>. Pay your plan: <link> (details: sendingPausedAt, receivingUntil, receivingStopped, billingUrl, localizedMessage). No Retry-AfterDo NOT retry: pay in Billing (details.billingUrl); sending comes back right away
ACCOUNT_SUSPENDED403Account is suspended or cancelled (a manual suspension or a cancelled account — paying does not restore it)Contact support
RATE_LIMITED429A rate limit was exceeded: error.limit says which (connection, account, key)Wait Retry-After (= error.retryAfterSeconds) and retry with the same Idempotency-Key; see Rate limits
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
STICKER_CAPTION_NOT_ALLOWED400type sticker does not accept a captionRemove sticker.caption
TEMPLATE_SEND_INVALID400The header/body/buttons shorthand has mistakes; all of them are in details.errors[] (field = JSON path, code, message in your language). Nothing was sent to MetaFix each field. GET /v1/templates/{id} shows the approved template (how many {{n}}, which buttons)
CONNECTION_REQUIRED400Provide connectionId (conn_…) or from (phoneNumberId)Send one of them
CONNECTION_NOT_FOUND404No connection matches connectionId/from (or the {id} of /v1/connections/{id}: conn_… or externalId) 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
CONNECTION_BANNED409WhatsApp (Meta) blocked this number (details.status = banned). Not queuedRetrying does not help: the business appeals the block from its own Meta account (WhatsApp Manager). When Meta lifts it the number goes back to connected by itself (connection.status_changed)
MESSAGE_NOT_FOUND404No message with that id for this accountCheck the msg_… id
INVALID_MESSAGE_ID400messageId is not a WhatsApp message id (a wamid.…) — e.g. a msg_… of a message you sentSend data.message.id of message.received as messageId in the body
INVALID_TYPING400typing must be true, false or omittedFix the body
INBOUND_MESSAGE_NOT_FOUND404No received message with that id for this account (unknown, of another account, or older than 30 days)Check the id; a message of ANOTHER account is also reported as not found
MESSAGE_NOT_INBOUND409The id is a message sent FROM your number (by the API or the phone)Only received messages can be marked as read
MESSAGE_TOO_OLD410The message was received more than 30 days ago — Meta does not mark itNothing to do; mark messages when you read them
MESSAGE_READ_REJECTED422Meta did not accept the read (details.metaCode)Check the id came from this number's message.received; do not retry unchanged
META_UNAVAILABLE502Meta did not answer (network or 5xx)Retry in a few seconds
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_PARAM_INVALID_CHARS400A text parameter (body or header, type: text) contains a line break (\n), a carriage return (\r), a tab (\t) or 5+ consecutive spaces. Caught before Meta (which answers 132018). details = component, parameter ({{n}}), character — never the value. ⚠ Enabled per deployment (TEMPLATE_PARAM_GUARD_ENABLED); off, the send goes to Meta as beforeReplace line breaks with · or commas and collapse repeated spaces
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; since 0.22.0 also details.errors[] = field (JSON path, e.g. buttons[1].url), code, message in your language)Fix the issues and retry — the pre-checker caught them before Meta did
TEMPLATE_META_REJECTED400Meta rejected the template at creation or edit (message = Meta's reason)Adjust per Meta's message and try again
TEMPLATE_NOT_EDITABLE409Meta only allows editing APPROVED, REJECTED or PAUSED templates (details.status)Wait for Meta's review, or create a new template
TEMPLATE_FIELD_NOT_EDITABLE400name or language can't change on an edit (details.field)Create a new template for another name or language
TEMPLATE_CATEGORY_LOCKED409Meta doesn't allow changing the category of an approved templateSend the same category, or create a new template
TEMPLATE_EDIT_LIMIT429An approved template can be edited once per 24 h and 10 times per 30 days (details.window, details.retryAt)Retry after retryAt
TEMPLATE_NOT_IN_META409The template has no Meta id yet (draft or never synced)POST /v1/templates/sync and retry
TEMPLATE_SAMPLE_TYPE_UNSUPPORTED415The sample file isn't a PDF, JPG/PNG or MP4 (details.detected) — the only types Meta's upload acceptsConvert the file and upload again
TEMPLATE_SAMPLE_UPLOAD_FAILED502Meta didn't accept the sample (details.metaCode if Meta gave one). Nothing was storedRetry
MEDIA_FILE_REQUIRED400The upload carries no file (file part or base64 file)Send the file
MEDIA_TYPE_MISMATCH422The type you asked for doesn't match the file's bytesDrop type or send the right file
MEDIA_BUSY503Uploads are momentarily busyRetry in a few seconds
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 the 26 subscribable types of DeliveryEventType (message.received … onboarding.help_requested). webhook.test is not subscribable
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
WEBHOOK_LIMIT_REACHED422No room for one more webhook there (details.scope: connection = 2 per number, connections_total = 2 × your numbers, account = 5 account-wide; details.used, details.limit)Delete or reuse one (PATCH its url) — webhooks you already have above the limit keep working
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
CONNECTION_EMAIL_NOTICES_INVALID400emailNotices on a connection must be inherit, on or off. Since 0.36.0Send one of the three
SETTINGS_INVALID400emailNotices on PATCH /v1/account/settings must be a boolean. Since 0.36.0Send true or false
NOTICES_QUERY_INVALID400A GET /v1/notices parameter is invalid (limit 1–100, before a positive integer, unread true/false, lang es/en/pt/it, connectionId a string). Since 0.36.0Fix the parameter
NOTICE_NOT_FOUND404No notice with that id for this account. Since 0.36.0Check the id (GET /v1/notices) — a notice of ANOTHER account is also reported as not found
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 id (on /v1/webhooks: not a conn_…/externalId string, or both filters at once)On /v1, send conn_… or your externalId (omit for the account default); on the panel surface, the numeric id
WEBHOOK_CONNECTION_NOT_FOUND404No connection with that id (or externalId) for this accountCheck the connection id — a number of ANOTHER account is also reported as not found
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)
ONBOARDING_CASE_STATUS_INVALID400status must be open, acked, all or omittedFix status
ONBOARDING_CASE_NOT_FOUND404No onboarding case with that idCheck the A-<n> id (GET /v1/onboarding-cases)
ONBOARDING_HISTORY_INVALID400historyDelivery must be true, false, or omittedSend a boolean, or omit it so the hosted page asks
ONBOARDING_PREVIOUS_PROVIDER_INVALID400previousProvider must be 360dialog, twilio, gupshup, wati, other, none, unknown, or omittedSend one of the seven, or omit it so the hosted page asks
ONBOARDING_INTRO_INVALID400intro / linkIntro must be full, minimal, or nullSend one of the two, or null to inherit
ONBOARDING_SIGNUP_HELP_INVALID400signupHelp must be off, brand, neutral, or nullSend one of the three, or null to inherit
HISTORY_LIMIT_INVALID400limit must be an integer between 1 and 5Fix limit (default 1)
HISTORY_CURSOR_INVALID400after is not a cursor this endpoint returnedSend the nextCursor of the previous page, or omit it to start over
HISTORY_BATCH_NOT_FOUND404No history batch with that id for this connectionCheck the hb_… id (it comes in data[].batchId)
HISTORY_BATCH_GONE410The batch is no longer available: it expired after 7 days, or it could never be storedNothing to confirm; history.completed tells you how many expired
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