{"errors":[{"code":"missing_api_key","status":401,"description":"No credential was presented. Send `Authorization: Bearer sonia_sk_<env>_<prefix>_<secret>`."},{"code":"invalid_api_key","status":401,"description":"The credential is not usable. Returned identically for a malformed key, an unknown key and a revoked key — the API never reveals which, so a caller cannot probe for valid prefixes."},{"code":"insufficient_scope","status":403,"description":"The key is valid but was not granted a scope this endpoint requires. The response names the missing scope(s); mint a new key with them."},{"code":"browser_credential_use","status":403,"description":"The request carried an `Origin` header, so it came from a browser page. API keys are server-to-server credentials: a key shipped to a browser is a key published to every visitor. Call /v1 from your backend."},{"code":"tenant_suspended","status":403,"description":"The credential is valid but its account is suspended, so the API answers nothing for it. Deliberately distinct from `invalid_api_key`: the key is not the problem and rotating it will not help — contact support. Suspending an account therefore takes effect on the very next API call, exactly as it does in the console."},{"code":"api_unavailable","status":503,"description":"The public API is not fully configured on this deployment (for example its credential store is unreachable). Retry, then contact support."},{"code":"not_found","status":404,"description":"No such resource, or it belongs to a different account."},{"code":"rate_limited","status":429,"description":"The key exceeded its budget. See the `RateLimit-*` response headers for the limit, what is left and when it resets."},{"code":"invalid_request","status":400,"description":"The request was rejected by validation; the message says why."},{"code":"channel_not_configured","status":403,"description":"WhatsApp is not activated for this account, or it has no usable sender credentials. Nothing the caller can fix in the request — an administrator connects the channel in the console."},{"code":"human_replies_disabled","status":403,"description":"The account has human intervention switched OFF, so a free-form message cannot be written into a conversation — the same refusal a console agent gets. An administrator enables it in the WhatsApp settings; an approved template is unaffected and can still be sent."},{"code":"invalid_recipient","status":422,"description":"The recipient could not be resolved to a real phone number. A number without an international prefix is only resolvable when the account states a country, so send E.164 (`+34600111222`) and it always works."},{"code":"session_window_closed","status":409,"description":"WhatsApp only allows a free-form message within 24 hours of the contact's last message, and that window is shut. Send an approved template instead — `GET /v1/templates` lists the usable ones, and `GET /v1/conversations/{id}/window` says when the window closed."},{"code":"template_not_usable","status":409,"description":"The named template does not exist for this account, or it is not APPROVED with a provider content id yet. Only an approved template can open a conversation; approval is WhatsApp's, not ours."},{"code":"missing_template_variables","status":422,"description":"The template declares placeholders the request did not fill. The message names them; every placeholder needs a non-empty value."},{"code":"idempotency_conflict","status":409,"description":"This `Idempotency-Key` cannot be replayed: it is in flight, it was first used with a different body, or it already produced a delivery attempt that then failed. The API will not re-send under a key that may already have reached the customer — use a NEW key to try again."},{"code":"send_failed","status":502,"description":"The WhatsApp provider refused the message. The message says why in operator language. Treat it as possibly-delivered: retry with a NEW idempotency key only when you can tolerate a duplicate."},{"code":"invalid_recipients","status":422,"description":"One or more recipients of a bulk send failed validation and `on_invalid` was `reject`, so NO run was created and nothing was sent. `error.recipients` lists each offending row by its 0-based `index` with the reason — fix them and resend, or set `on_invalid: \"skip\"` to accept the run without them."},{"code":"bulk_send_not_cancellable","status":409,"description":"The bulk send has already finished (`completed` or `failed`), so there is nothing left to stop. Cancelling an already-cancelled run is NOT an error — it answers 200 with the run, so a retried cancel is safe."},{"code":"internal_error","status":500,"description":"An unexpected server error. The `request_id` identifies it in our logs — quote it to support."}]}