Skip to content

Errors

A request that fails gets a 4xx or 5xx status and one error object. Act on its code: codes never change meaning, though new ones may be added. Handle a code you don’t know by its status.

The error object

FieldAlways thereWhat it is
codeYesWhat went wrong, as one of the codes in the table below.
messageYesWhat went wrong, in plain English for a developer.
fieldSometimesA JSON path to the field at fault, for example template.name. Left out when no single field is at fault.
detailsSometimesMore about the error, for the codes whose row below lists details keys.
request_idYesThe X-Request-ID of the response.

What each status means, and whether to send the request again.

400Bad request

The body or a query value is wrong. Fix it before you send it again.

invalid_request

401Unauthorized

The key is missing, unknown, revoked or expired.

unauthorized

403Forbidden

The key, your plan or the workspace doesn’t allow this.

ip_not_allowedscope_missingfeature_not_in_planworkspace_closed

404Not found

No such path, or no such object in your workspace.

not_found

405Method not allowed

The path exists, but not for this method. The Allow header lists the methods it takes.

method_not_allowed

409ConflictRetry

A duplicate, the wrong state, or the same key still running.

conflictinvalid_stateidempotency_in_progress

413Too large

A file or an upload is over its size limit, or the request is over 15 MB. A JSON body over its endpoint’s limit is a 400.

too_large

415Unsupported media type

The file type isn’t accepted, or the request body is compressed.

unsupported_media_type

429Too many requestsRetry

Over a rate limit. Wait the Retry-After seconds, then retry.

rate_limited

500Internal errorRetry

Something went wrong on Soosh’s side. Retry with the same Idempotency-Key.

internal_error

503UnavailableRetry

A service Soosh depends on is down. Retry after the Retry-After seconds.

unavailable

Every code, the status it comes with, and what to do. Each has its own link, such as #window_closed.

CodeStatusWhat happened and what to doRetry
invalid_request400The request is malformed: bad JSON or multipart, an unknown field, a wrong type, a bad cursor, an Idempotency-Key that isn’t 1 to 255 printable ASCII characters, or a JSON body over 1 MB (4 MB for POST /v1/broadcasts). Fix the request.No
unauthorized401The key is missing, malformed, unknown, revoked or expired. The reason isn’t revealed.No
ip_not_allowed403The client IP isn’t in the key’s allowed IPs. Call from an allowed address.No
scope_missing403The key lacks the scope this endpoint needs. The detail names it. Comes with details.scope.No
feature_not_in_plan403Your plan doesn’t include the feature this endpoint needs. The detail names it. Comes with details.feature.No
workspace_closed403The workspace is closed, so its API doesn’t work.No
not_found404There is no such path or object. It is also returned for an object in another workspace.No
method_not_allowed405The path exists, but not for this method. The Allow header lists the methods it does accept.No
conflict409The object is a duplicate. The detail is the ID of the existing object. Comes with details.id.No
invalid_state409The object’s state doesn’t allow this, for example cancelling a completed broadcast.No
idempotency_in_progress409A request with the same Idempotency-Key is still running. Wait, then retry with the same key.Retry
too_large413A file is over the size for its type, an upload is over the upload limit, or the whole request is over 15 MB. A JSON body over its endpoint’s limit is invalid_request instead.No
unsupported_media_type415The file isn’t a type the API accepts, or the request body is compressed. Request bodies can’t have a Content-Encoding: send them as they are.No
invalid_field422A field broke a rule. field names it. The detail is set only when WhatsApp refuses a template: see Create a template. Comes with details.id.No
invalid_phone422The phone number isn’t valid. Check the number and send it again.No
idempotency_mismatch422The Idempotency-Key was used before for a different request, or by another of your API keys. Use a new key. A key rotated from the first one counts as the same key.No
window_closed422The contact hasn’t written to this number in the last 24 hours. Send a template instead. See The 24-hour window. A retry with the same Idempotency-Key replays this error, so use a new key once the customer has written.No
template_not_approved422The template isn’t approved by WhatsApp yet. Use an approved template.No
template_params422The template’s variables are missing or extra, and the details say which. For a broadcast, rows lists the bad rows. Comes with details.missing, details.unexpected, details.rows.No
template_ambiguous422Two of your numbers have a template with that name and language. Add number_id, or send the template’s id.No
contact_opted_out422The contact opted out of marketing messages. Don’t send them a marketing template.No
number_unavailable422The number isn’t active. Use an active number.No
limit_reached422You’ve reached a limit on your workspace. The details name it, give its value and say how much you’ve used. Comes with details.limit, details.limit_value, details.used.No
rate_limited429Too many requests. Wait Retry-After seconds, then try again.Retry
internal_error500Something went wrong on Soosh’s side. Retry. For a POST, use the same Idempotency-Key.Retry
unavailable503A service Soosh depends on is down. Try again after Retry-After seconds.Retry

Send a message answers 201 once the message is checked and queued. WhatsApp can still turn it down after that, for example when the number isn’t on WhatsApp.

Those failures come as a message.status webhook with status: failed, and an error whose code is WhatsApp’s number (such as 131026), not one of the codes above: the request itself worked. Message statuses lists the common reasons.

A message still pending after 15 minutes fails the same way, with the error.message “Not sent in time” if it was never sent, or “WhatsApp didn’t confirm this message in time” if WhatsApp never said what became of it.

message.statusdata
{
  "message_id": "8c2e4f6a-1d3b-4a5c-9e7f-2b4d6f8a0c1e",
  "status": "failed",
  "at": "2026-10-14T09:30:15.902Z",
  "error": {
    "code": 131026,
    "message": "Message undeliverable"
  }
}