# Errors and rate limits

> Docs index: https://wahasend.com/llms.txt · Everything in one file: https://wahasend.com/docs.md · API base URL: https://app.wahasend.com/api/v1

Every error answers with the same envelope and an `X-Request-Id` header:

400 VALIDATION_ERROR:

```json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed. Check the details for specific field errors.",
    "details": { "phone": ["Invalid recipient. Use an international phone number (e.g. +22212345678) or a WhatsApp id ending in @lid."] },
    "issues": [{ "field": "phone", "code": "custom", "message": "Invalid recipient. …" }],
    "requestId": "7c9e2f4a-1b3d-4e5f-8a6b-0c1d2e3f4a5b"
  }
}
```

- `code` is stable: match on it, never on `message` (the wording may change).
- `details` adds facts when there are some (`retryAfterSeconds`, `attemptsRemaining`, `products`…). `issues` lists each bad field of a `VALIDATION_ERROR` with a code such as `required`, `too_big` (with `maximum`) or `invalid_uuid`.
- `requestId` (same as the `X-Request-Id` header): quote it when you contact support, it lets us find your request.
- 429 and 503 answers carry `Retry-After` (seconds) when the wait is known. Wait that long before trying again.
- 5xx: safe to retry a read. Before retrying a send, check `GET /messages`: a timeout may have gone out.

<a id="rate-limits"></a>

### Rate limits

| Limit | Value | When exceeded |
| --- | --- | --- |
| Changes per organization (POST, PUT, PATCH, DELETE; reads are free), shared by every key and person | 300 a minute (bursts up to 300) | 429 `RATE_LIMITED`, `details.scope: "organization"`, `retryAfterSeconds`, `limitPerMinute`, `Retry-After` |
| Text sends per number | 60 a minute (`high` priority: no cap) | Queued, sent later; never refused |
| Campaign messages | 20 a minute per number, 60 a minute per organization, 3–7 s apart | Queued, sent later |
| Verification codes ([OTP](https://wahasend.com/docs/errors.md#otp-limits)) | Per phone: 1 every 30 s, 3 per 10 min, 10 per 24 h; 60 a minute per organization | 429 `OTP_RATE_LIMITED`, `Retry-After` |
| AI sends through Connect (MCP) | See [sending limits](https://wahasend.com/docs/connect.md#connect-limits) | The tool answers "not sent" with the reason |
| Messages during the [free trial](https://wahasend.com/docs/errors.md#trial-limits) | 100 a day per organization (UTC day), every kind of send counted | 429 `TRIAL_LIMIT_REACHED`, `details.limit`, `used`, `resetsAt`, `Retry-After` |
| Sign-in | 20 attempts per 15 min per IP address; 10 wrong passwords lock the email for 15 min | 429 `RATE_LIMIT` / `TOO_MANY_LOGIN_ATTEMPTS` |
| Claude sign-in (OAuth) | Register 60/h per IP; token 120 per 15 min per app; authorize and revoke 60 per 15 min | 429 `RATE_LIMIT` |

<a id="otp-limits"></a>

### OTP limits

So that nobody can use your sign-up form to flood a phone with codes (and get your number reported), `POST /otp/send` is limited per destination phone within your organization: one code every 30 seconds, 3 per 10 minutes and 10 per 24 hours; and 60 codes a minute for the whole organization. The windows slide (they are not calendar minutes or days). Over a limit the answer is 429 `OTP_RATE_LIMITED` with `Retry-After` and `details`: `scope` (`phone` or `organization`), `reason` (`cooldown`, `window`, `day` or `organization`), `limit` and `retryAfterSeconds`. Show the person when they can ask again; don't retry automatically.

<a id="trial-limits"></a>

### Free trial limits

A new account gets the products it asked for free for 7 days (one trial per person and per product). While every product of the organization is on its trial, it can send 100 messages a day through WahaSend — single sends, batches (every recipient counts), campaigns (counted when you start them), reminders, OTP codes, media sends, assistant replies and Connect sends together — and its AI allowance is $2 for the whole trial. The count starts again at 00:00 UTC. A send that doesn't fit is refused, nothing is queued: 429 `TRIAL_LIMIT_REACHED` with `Retry-After` (seconds until midnight UTC) and `details`: `limit`, `used`, `requested`, `retryAfterSeconds`, `resetsAt`. A batch or campaign larger than what is left is refused whole. Once a product is paid, the limit is gone. When the trial ends, the product pauses (403 `PRODUCT_REQUIRED`) until it is paid; nothing is deleted.

<a id="error-codes"></a>

### Every error code

Generated from the server's error catalogue. Codes are never renamed or removed; new ones may appear.

#### VALIDATION_ERROR

HTTP 400 · Validation failed. Check the details for specific field errors.

#### INVALID_JSON

HTTP 400 · Request body contains invalid JSON.

#### INVALID_ID

HTTP 400 · Invalid identifier.

#### PAYLOAD_TOO_LARGE

HTTP 413 · The request is too large.

#### FILE_TOO_LARGE

HTTP 413 · The file is too large.

#### ROUTE_NOT_FOUND

HTTP 404 · This API route does not exist. Check /api for available endpoints.

#### NOT_FOUND

HTTP 404 · Not found.

#### CONFLICT

HTTP 409 · This resource already exists.

#### REFERENCE_ERROR

HTTP 400 · Referenced resource does not exist.

#### IN_USE

HTTP 409 · This is still used elsewhere and cannot be removed.

#### CONSTRAINT_VIOLATION

HTTP 400 · Operation violates a data constraint.

#### FORBIDDEN_ACTION

HTTP 400 · This action is not allowed.

#### RATE_LIMIT

HTTP 429 · Too many requests. Slow down and try again.

#### RATE_LIMITED

HTTP 429 · Your organization is sending too many requests. Wait a moment and try again.

#### AUTH_ERROR

HTTP 401 · Authentication required.

#### TOO_MANY_LOGIN_ATTEMPTS

HTTP 429 · Too many wrong passwords for this account. Try again in 15 minutes.

#### ACCOUNT_DEACTIVATED

HTTP 403 · Account is deactivated. Contact support.

#### OAUTH_TOKEN_SCOPE

HTTP 403 · This Claude connection can only be used by Claude (MCP endpoint).

#### OAUTH_REQUEST_INVALID

HTTP 400 · This request from Claude has expired or was already answered. Start again from Claude.

#### NUMBER_KEY_SCOPE

HTTP 403 · This API key belongs to one WhatsApp number and can only send and read through it.

#### USER_REQUIRED

HTTP 403 · Sign in to the dashboard to do this; API keys cannot.

#### WRONG_PASSWORD

HTTP 400 · The password is not correct.

#### NO_PASSWORD_SET

HTTP 400 · No password set. Ask the admin to reset your password.

#### INVALID_LINK

HTTP 400 · This link has expired or was already used. Ask for a new one.

#### SIGNUP_DISABLED

HTTP 403 · Sign-up is currently closed.

#### TWO_FACTOR_REQUIRED

HTTP 403 · This organization requires two-step sign-in. Turn it on in your account first.

#### TWO_FACTOR_CODE_INVALID

HTTP 400 · The code is not correct. Check your authenticator app and try again.

#### TWO_FACTOR_CHALLENGE_EXPIRED

HTTP 400 · This sign-in has expired. Enter your email and password again.

#### TWO_FACTOR_SETUP_EXPIRED

HTTP 400 · The set-up has expired. Start again.

#### TWO_FACTOR_ALREADY_ENABLED

HTTP 409 · Two-step sign-in is already on.

#### TWO_FACTOR_NOT_ENABLED

HTTP 409 · Two-step sign-in is not on.

#### TWO_FACTOR_OWNER_FIRST

HTTP 409 · Turn on two-step sign-in for your own account first.

#### TWO_FACTOR_UNAVAILABLE

HTTP 503 · Two-step sign-in is not available on this server yet.

#### COUNTRY_LOCKED

HTTP 409 · Your country can no longer be changed here once you have paid. Write to us to change it.

#### PRODUCT_REQUIRED

HTTP 403 · This feature is not included in your products.

#### NO_ACTIVE_PRODUCT

HTTP 403 · Your account has no active product yet. Contact us to activate one.

#### ADMIN_ONLY

HTTP 403 · This action is restricted to the platform admin.

#### ROLE_FORBIDDEN

HTTP 403 · Your role in this organization does not allow this. Ask an owner or admin.

#### ADMIN_CANNOT_DELETE

HTTP 403 · The platform admin organization cannot be deleted.

#### INVITE_INVALID

HTTP 400 · This invitation has expired, was cancelled or was already used. Ask for a new one.

#### INVITE_EMAIL_MISMATCH

HTTP 403 · This invitation was sent to another email address. Sign in with that address.

#### ALREADY_MEMBER

HTTP 409 · This person is already in your team.

#### TEAM_FULL

HTTP 409 · The team is full.

#### OWNER_ROLE_FIXED

HTTP 409 · The owner stays owner. Transfer the ownership first.

#### CANNOT_REMOVE_OWNER

HTTP 409 · The owner cannot be removed. Transfer the ownership first.

#### OWNER_CANNOT_LEAVE

HTTP 409 · You own this organization. Transfer the ownership before leaving.

#### LAST_ORGANIZATION

HTTP 409 · This is your only organization. Delete your account instead.

#### NOT_OWNER

HTTP 403 · Only the owner can do this.

#### ALREADY_OWNER

HTTP 409 · You already own this organization.

#### OWNS_ORGANIZATION

HTTP 409 · You own an organization. Transfer it to someone else first.

#### USE_LEAVE

HTTP 400 · Use "Leave this organization" to remove yourself.

#### TOO_MANY_ORGANIZATIONS

HTTP 409 · You can own up to 10 organizations.

#### NO_SESSION_CONFIGURED

HTTP 400 · This account has no connected WhatsApp number.

#### SESSION_NOT_CONNECTED

HTTP 409 · WhatsApp is not connected. Reconnect the number.

#### CONTAINER_NOT_FOUND

HTTP 404 · WhatsApp number not found.

#### NUMBER_LIMIT_REACHED

HTTP 403 · This account uses all the WhatsApp numbers it may have (Developer and Connect include 3). Add extra numbers, or remove a number.

#### PORT_EXHAUSTED

HTTP 503 · No room for a new WhatsApp number right now. Contact support.

#### NUMBER_NOT_ON_WHATSAPP

HTTP 400 · This number is not on WhatsApp.

#### NO_VALID_NUMBERS

HTTP 400 · None of these numbers are on WhatsApp.

#### NUMBER_ON_OTHER_ASSISTANT

HTTP 409 · This WhatsApp number already answers for another assistant that is on. Remove it there first, or turn that assistant off.

#### SECRETS_KEY_MISSING

HTTP 503 · SECRETS_ENCRYPTION_KEY must be set to give WhatsApp servers their own keys.

#### NUMBER_VALIDATION_UNAVAILABLE

HTTP 503 · Numbers cannot be checked right now. Try again shortly.

#### OTP_EXPIRED

HTTP 410 · OTP has expired. Request a new code.

#### OTP_ALREADY_VERIFIED

HTTP 400 · OTP has already been verified.

#### OTP_MAX_ATTEMPTS

HTTP 429 · Maximum verification attempts exceeded. Request a new code.

#### OTP_INVALID_CODE

HTTP 400 · Invalid code.

#### OTP_RATE_LIMITED

HTTP 429 · Too many verification codes for this number or this account. Wait before sending another one.

#### OTP_TEMPLATE_MISSING_CODE

HTTP 400 · The message template must contain {{code}}, where the code goes.

#### MESSAGE_NOT_FOUND

HTTP 404 · No message with this id was sent by this account.

#### MESSAGE_NOT_SENT

HTTP 409 · This message has not been sent yet (or it failed). Only sent messages can be edited or deleted.

#### MESSAGE_WRONG_NUMBER

HTTP 403 · This message was sent from another WhatsApp number than the one this request uses.

#### CAMPAIGN_INVALID_STATE

HTTP 400 · The campaign cannot do this in its current state.

#### STAFF_PHONE_LIMIT

HTTP 409 · You can add up to 10 phones for orders.

#### STAFF_PHONE_IS_BUSINESS

HTTP 400 · This is your business WhatsApp number. Add another phone: yours or a staff member's.

#### WEBHOOK_SIGNING_UNAVAILABLE

HTTP 503 · Webhook signing is not available on this server yet (SECRETS_ENCRYPTION_KEY is not set).

#### ATTACHMENT_NOT_FOUND

HTTP 404 · This message was not found in this chat, or it has no attachment.

#### ATTACHMENT_EXPIRED

HTTP 410 · This file is no longer on WhatsApp (older attachments expire). Ask the contact to send it again.

#### ATTACHMENT_TOO_LARGE

HTTP 413 · This file is too large to open here.

#### ATTACHMENT_UNSUPPORTED

HTTP 415 · This kind of file cannot be opened here.

#### TRANSCRIPTION_UNAVAILABLE

HTTP 503 · Voice notes cannot be read because speech-to-text is not enabled on this server.

#### SEND_FILE_TOO_LARGE

HTTP 413 · This file is too large to send on WhatsApp from here.

#### SEND_FILE_TYPE_NOT_ALLOWED

HTTP 415 · This kind of file cannot be sent. Photos, PDFs, Office files, text and CSV files, voice notes, audio and MP4 videos can.

#### SEND_FILE_URL_UNREACHABLE

HTTP 422 · The file at this link cannot be fetched. Use a public https link to the file itself.

#### WAHA_ERROR

HTTP 502 · WhatsApp could not complete the request. Try again.

#### WAHA_SESSION_ERROR

HTTP 503 · WhatsApp is not connected.

#### WAHA_UNREACHABLE

HTTP 503 · WhatsApp service is unreachable. Please try again later.

#### UPSTREAM_TIMEOUT

HTTP 504 · A service we depend on took too long to answer. Try again.

#### AI_UNAVAILABLE

HTTP 503 · The AI service is not available right now. Try again shortly.

#### AI_BUSY

HTTP 503 · The AI service is busy. Try again in a moment.

#### SERVICE_BUSY

HTTP 503 · The service is busy. Try again in a moment.

#### AI_QUOTA_EXCEEDED

HTTP 402 · This month's AI allowance is used up. It renews on the 1st, or contact us to raise it.

#### TRIAL_LIMIT_REACHED

HTTP 429 · Free trial: 100 messages a day. Activate your product to remove this limit.

#### PADDLE_NOT_CONFIGURED

HTTP 503 · Card payment is not available on this server. Use another way to pay.

#### PADDLE_NO_SUBSCRIPTION

HTTP 404 · This organization has no card payment to manage.

#### PADDLE_UNAVAILABLE

HTTP 502 · The card payment service did not answer. Try again in a moment.

#### PADDLE_SIGNATURE_INVALID

HTTP 401 · Invalid or expired Paddle signature.

#### PADDLE_CHANGE_REFUSED

HTTP 409 · This change could not be made. Check your card, or try again later.

#### PADDLE_NOTHING_TO_RESUME

HTTP 409 · This subscription is not set to stop: there is nothing to undo.

#### PADDLE_PERIOD_UNAVAILABLE

HTTP 409 · This billing period is not offered for this product.

#### PADDLE_SAME_PERIOD

HTTP 409 · This product is already billed this way.

#### INVOICE_NOT_AVAILABLE

HTTP 404 · No receipt to download for this payment.

#### INTERNAL_ERROR

HTTP 500 · An unexpected error occurred. Please try again or contact support.
