Every error response from the MiniMoth API has a stable code field you can use in your code to handle specific cases. Codes will not change — you can safely switch on them.
The API key is not recognised. Check the key in your project settings.
Validation
Code
Status
Description
INVALID_PHONE
422
Phone number is not a valid Indian mobile number (10 digits starting with 6–9, with or without +91), and not a number in a supported international market either. See International WhatsApp OTP for supported markets.
INVALID_OTP_CODE
422
The code field must be exactly 6 digits.
MISSING_ACCESS_TOKEN
422
The request body is missing the access_token field.
MISSING_REFRESH_TOKEN
422
The request body is missing the refresh_token field.
OTP
Code
Status
Description
OTP_RATE_LIMITED
429
Too many OTPs requested for this number. Limit is 3 per phone per 10 minutes.
OTP_NOT_FOUND
400
No active OTP exists for this phone number. It may have expired (10 min TTL) or already been used.
INVALID_OTP
400
The OTP code is incorrect.
VERIFY_RATE_LIMITED
429
Too many incorrect attempts for this OTP. The OTP is now locked — request a new one.
SMS_FAILED
500
Both WhatsApp and SMS fallback delivery failed. The charge was not applied. Retry after a moment.
OTP_REQUEST_NOT_FOUND
404
No OTP request found with that ID, or it does not belong to this project. Returned by GET /v1/otp/status/:otp_id.
International markets
Code
Status
Description
REGION_NOT_ENABLED
403
The phone number’s market exists, but this project hasn’t turned it on yet. Enable it from the project’s International WhatsApp OTP card in the dashboard, which shows the rate before you turn it on. See International WhatsApp OTP.
INTERNATIONAL_WHATSAPP_FAILED
502
A real WhatsApp delivery attempt to an international number failed. There is no SMS fallback for these numbers. The message states whether the charge was refunded — it always is unless the refund itself failed (rare; contact support if it persists).
INTERNATIONAL_WHATSAPP_BLOCKED
502
This number has had too many recent WhatsApp delivery failures and is temporarily blocked — no delivery was attempted and no charge was made for this call. The block clears on its own once the window passes without a new real failure.
Billing
Code
Status
Description
INSUFFICIENT_BALANCE
402
Wallet balance is too low to send an OTP. Top up from the dashboard. No OTP was sent and no charge was applied.
Session
Code
Status
Description
SESSION_EXPIRED
401
The refresh token has expired or is invalid. The user must re-authenticate.
INVALID_ACCESS_TOKEN
401
The access token is invalid or expired. Returned by session/logout when called with an expired token — refresh the session first, then retry the logout.
RATE_LIMITED
429
General rate limit exceeded — 1000 requests per minute per API key. Back off and retry.
Identity
Code
Status
Description
IDENTITY_DELETE_DISABLED
403
Identity deletion isn’t turned on for this project. Enable it from the project’s Identity settings card in the dashboard. See Identity.
IDENTITY_LOOKUP_DISABLED
403
Identity lookup isn’t turned on for this project. Enable it from the project’s Identity settings card in the dashboard. See Identity.
IDENTITY_NOT_FOUND
404
No identity with that id, or it belongs to a different project.
Node.js SDK
@minimoth/sdk-node surfaces every code above as-is via err.code — plus a few additional codes on top of the API’s, for conditions the SDK catches locally before or instead of a network call.
Code
Status
Description
INVALID_PHONE
—
SDK-only trigger, thrown client-side before any request is sent: an empty or non-string phone number. Spaces and hyphens are stripped, not rejected — +1-2025551234 and +12025551234 both work. Distinct from the API’s own INVALID_PHONE (422) above, which fires server-side on a malformed but well-formatted number.
NETWORK_ERROR
—
The underlying fetch() call threw — the network was unreachable or the request otherwise never completed.
UNKNOWN_ERROR
—
The API response had no error code at all — an unparseable body, or a response shape that never included one. Check err.statusCode for the raw HTTP status.
Try the full OTP flow interactively in the sandbox — no SMS sent, no credits consumed. The same Playground also has a live test to send a real OTP to your phone (uses your credits).