Error codes
Every error has the same envelope. Read error.code in your code, show error.message to people, and quote error.request_id to support.
json
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"param": "amount",
"request_id": "6f1c0e8a-2d1b-4c5e-9f7a-3b2d1c0e8a6f",
"doc_url": "https://docs.watenga.africa/developers/errors#VALIDATION_ERROR",
"details": { "issues": [{ "path": "amount", "message": "Amount must be a decimal string" }] }
}
}request_idis also theX-Request-IDresponse header. The SDKs put it on their error object (requestId/request_id).paramnames the request field a validation error is about (snake_case in API version 2026-10-29); every issue is indetails.issues.doc_urllinks to the code's row below.
Retry only what is safe to retry:
429, 5xx and network errors, with the same Idempotency-Key. The SDKs do this for you. See Idempotency and Rate limits.Error reference
All 198 codes the API answers, generated from the API itself. HTTP statuses are the ones the code is answered with.
| Code | HTTP | Message and what to do |
|---|---|---|
| ACCOUNT_IN_USE | 409 | Account is referenced by a pending payout |
| ACCOUNT_LOCKED | 403 | Account temporarily locked after too many attempts |
| ACCOUNT_SUSPENDED | 403 | This account is suspendedContact Watenga support. |
| AI_NOT_CONFIGURED | 409 | The AI assistant is not available yet on this platform |
| ALREADY_INVITED | 409 | This email already has a pending invitation |
| ANOTHER_REVISION_ACCEPTED | 409 | The customer has already accepted another revision of this quotation |
| API_KEY_REQUIRED | 400 | Call this with an API key |
| ASSIGNEE_NOT_IN_TEAM | 400 | Assign the conversation to someone on your team |
| BACKPRESSURE | 503 | Admission store unavailable. Try again shortly. |
| BALANCE_IN_FLIGHT | 409 | A payment for this invoice is still being processed. Try again once it settles. |
| BRAND_NOT_ENABLED | 400 | This card brand is not enabled for your account |
| CHANNEL_REVOKED | 403 | Watenga switched this channel off for your business. Contact support. |
| CHARGEBACK_HOLD | 403 | A pending chargeback is on your account. Please resolve before requesting a payout. |
| CHECKOUT_DESIGN_INVALID | 400 | Checkout design failed validation |
| CHECKOUT_NOT_PENDING | 409 | This checkout is already complete |
| CHECKOUT_REQUIRED | 400 | This link is taxed; use Watenga.js checkout |
| CHECKOUT_SESSION_IN_PROGRESS | 409 | A payment for this checkout session is under way; it cannot be expired now.A payment for this session is under way: it cannot be expired now. |
| CHECKOUT_SESSION_NOT_OPEN | 409 | This checkout session is … and cannot be expired. |
| CLAWBACK_FAILED | 500 | Could not process balance adjustment. Contact support. |
| CLIENT_SECRET_REQUIRED | 403 | A publishable key pays a checkout session created by your server (POST /v1/checkout/sessions with a secret key): pass its clientSecret.Create a checkout session on your server (POST /v1/checkout/sessions) and pay it with its client secret. |
| CODE_TAKEN | 409 | A coupon with this code already exists |
| COMMERCE_MANAGEMENT_INVALID_RESPONSE | 502 | Shop management returned an invalid response |
| COMPLIANCE_RESTRICTED | 403 | Payments are restricted pending compliance review |
| CONCURRENCY_LIMIT_EXCEEDED | 429 | Too many in-flight requests |
| CONFIRMATION_REQUIRED | 400 | Sensitive scopes require explicit confirmation |
| CONFLICT | 409 | A saved invoice template already uses this name |
| CONTACT_REQUIRED | 409 | Verify an email or phone number first |
| CREATE_FAILED | 500 | Could not create quotation |
| CURRENCY_MISMATCH | 400 | Invoice currency does not match the payment currency |
| CURRENCY_NOT_OFFERED | 400 | This plan is not offered in that currency |
| CURRENCY_NOT_SUPPORTED | 400 | Provider … does not support … |
| CURRENCY_REQUIRED | 400 | Payment link is missing a currency |
| DELIVERY_UNAVAILABLE | 503 | We could not send a code right now. Try again later. |
| DEPRECATED_PAGINATION | 400 | Offset pagination is deprecated for payment methods; use starting_after cursor pagination |
| DESCRIPTOR_LOCKED | 403 | The statement descriptor cannot be changed after the first card transaction. Contact Watenga support. |
| DESCRIPTOR_TAKEN | 409 | That statement descriptor is already in use |
| DESTINATION_INVALID | 400 | Mobile money destination is missing a configured provider |
| DESTINATION_NOT_VERIFIED | 400 | Destination not verified |
| DESTINATION_REQUIRED | 400 | A verified settlement destination is required |
| DESTINATION_UNVERIFIED | 409 | Only a verified settlement destination can receive funds |
| DISBURSEMENTS_DISABLED | 403 | Disbursements are not enabled for this merchant |
| DOCUMENTS_INCOMPLETE | 400 | Required KYC documents are missing |
| DUPLICATE | 409 | This link already has that code |
| DUPLICATE_EMAIL | 409 | A customer with this email already exists |
| DUPLICATE_REQUEST | 409 | A request with this Idempotency-Key is already in progressThe first request with this Idempotency-Key is still running: wait and retry with the same key. |
| ELEMENTS_UNAVAILABLE | 503 | Watenga Elements is not configured on this platform |
| EMAIL_NOT_VERIFIED | 403 | Verify your email before signing in. Check your inbox for the activation link. |
| EMAIL_TAKEN | 409 | An account with this email already exists |
| EMAIL_UNAVAILABLE | 503 | Verification email is temporarily unavailable. Please try again later or contact support. |
| EMERGENCY_FREEZE | 503 | Disbursements are temporarily suspended |
| ENDPOINT_RETIRED | 410 | Use Watenga.js checkout (POST /v1/checkout/create) |
| EXPIRED | 409, 410 | Choose a future expiry date before issuing |
| EXPORT_TOO_LARGE | 400 | Export has … rows (limit …). Use POST /v1/merchant/reports/export with reportType "transactions" for async export. |
| FEATURE_DISABLED | 403 | The '…' feature is not enabledSwitch the product on for your API app (developer console) or your account. |
| FEE_RULE_NOT_FOUND | 400 | No fee rule configured for this payment method |
| FORBIDDEN | 403 | Metrics access denied |
| FX_RATE_STALE | 422 | The FX rate for this currency pair is out of date. Try again once it has been updated. |
| GATEWAY_ERROR | 502 | Could not start checkout with the payment providerThe payment provider failed: retry later with the same Idempotency-Key. |
| HANDOFF_EXPIRED | 401 | Handoff token expired or invalid |
| HANDOFF_USED | 401 | Handoff token already used |
| HOST_REJECTED | 404 | That hostname is not a public product host |
| IDEMPOTENCY_KEY_REQUIRED | 400 | Live API financial mutations require an Idempotency-Key headerSend an Idempotency-Key header on live money-moving writes. |
| IDEMPOTENCY_KEY_REUSED | 422 | This Idempotency-Key was already used for a different requestUse a new Idempotency-Key for a different request; reuse a key only to retry the same request. |
| IDEMPOTENCY_UNAVAILABLE | 503 | Idempotency storage is temporarily unavailable. Retry shortly with the same Idempotency-Key.Retry shortly with the same Idempotency-Key. |
| IMPERSONATION_READ_ONLY | 403 | Write operations are blocked during impersonation |
| INSUFFICIENT_FUNDS | 400, 409 | Insufficient balance for this conversionYour available balance cannot cover this refund now. |
| INTENT_MODE_MISMATCH | 400 | This checkout session was created in … mode; pay it with a … key.Pay a checkout session with a key of the same mode as the key that created it. |
| INTENT_NOT_FOUND | 404 | Checkout not found |
| INTERNAL_ERROR | 500 | An unexpected error occurredRetry with the same Idempotency-Key; if it persists, contact support with the request_id. |
| INVALID_AMOUNT | 400 | Amount must be greater than zeroSend the amount as a decimal string in the currency’s minor unit (USD "10.00", UGX "1500"), greater than zero. |
| INVALID_API_VERSION | 400 | Unknown Watenga-Version "…". Use one of: ….Send a Watenga-Version the API knows (see the changelog), or none to use your app’s pinned version. |
| INVALID_AUTHORITY | 400 | That tax authority is not available for … |
| INVALID_CLIENT | 400 | Unknown or inactive client |
| INVALID_CODE | 400 | Invalid or expired verification code |
| INVALID_COMMAND | 422 | Invalid payment session command |
| INVALID_CREDENTIALS | 401 | Invalid email or password |
| INVALID_DEPOSIT | 400 | Deposit cannot exceed the quotation total |
| INVALID_DOCUMENT_TYPE | 400 | Document type not required for your market |
| INVALID_GATEWAY | 400 | Specify ?gateway=ecocash|innbucks|onemoney or POST /:gateway |
| INVALID_GRANT | 400 | Invalid or expired authorization code |
| INVALID_JSON | 400 | Malformed JSON payload |
| INVALID_KEY | 401 | Invalid or expired API keyThe key is wrong, revoked or expired: copy it again from the developer console. |
| INVALID_LINK | 400 | This unsubscribe link is not valid |
| INVALID_PAGE | 400 | Add at least one active service before publishing |
| INVALID_QUANTITY | 400 | Quantity must be positive |
| INVALID_REDIRECT | 400 | redirect_uri not registered |
| INVALID_REQUEST | 400 | Canonical path without query parameters required |
| INVALID_SCOPE | 400 | Invalid scope request |
| INVALID_SEGMENT | 409 | This segment uses rules that are no longer supported; edit it |
| INVALID_STATE | 400, 409 | Drafts were never issued: cancel them instead of voiding |
| INVALID_STATUS | 409 | Only the sandbox provider runs in sandbox, outside production |
| INVALID_TOKEN | 400, 401 | Invalid or expired access tokenThe dashboard session ended: sign in again. |
| INVALID_TOTAL | 400 | Discount cannot exceed the invoice total |
| INVALID_URL | 400 | Use a public https address |
| INVITE_EXPIRED | 400 | This invitation has expired |
| INVITE_INVALID | 400 | This invitation is no longer valid |
| INVOICE_HAS_PAYMENTS | 409 | This invoice has payments made through Watenga. Refund them before voiding it. |
| JWT_REQUIRED | 403 | This action requires dashboard sign-in with two-factor authentication.This action is dashboard-only (for example payouts, bank accounts, keys): do it in the dashboard with two-step verification. |
| KYC_REJECTED | 403 | Your application could not be approved based on automated risk checks. Contact support@watenga.africa. |
| KYC_REQUIRED | 403 | KYC approval is required before processing paymentsFinish business verification in the dashboard before taking payments. |
| LIMIT_REACHED | 409 | You can keep up to 20 addresses |
| LINK_EXHAUSTED | 410 | This payment link has reached its maximum usesThe payment link reached its maximum uses. |
| LINK_EXPIRED | 410 | This payment link has expiredThe payment link has expired: create a new one. |
| LINK_INACTIVE | 403 | This payment link is no longer active |
| LINK_NOT_FOUND | 404 | Payment link not found |
| LINK_NOT_PAYABLE | 400 | This link starts a subscription; subscribe on its page |
| LINK_SOLD_OUT | 410 | Everything on this payment link has sold out |
| LISTEN_SESSION_EXPIRED | 410 | This listen session expired; start watenga listen again |
| MARKET_MISMATCH | 400 | Settlement destination is not valid for this merchant market |
| MARKET_NOT_LIVE | 403 | Payments are not yet available in your market. Complete onboarding to be ready when we launch. |
| MARKET_REQUIRED | 400 | Merchant market is not configuredSet the business’s market in the dashboard. |
| MCC_NOT_AVAILABLE | 400 | This business type is not offered in your market |
| MCC_PROHIBITED | 403 | This merchant category is not supported. |
| MERCHANT_NOT_FOUND | 404 | Unknown merchant |
| META_NOT_CONFIGURED | 503 | WhatsApp is not available yet on this platform |
| METER_EXISTS | 409 | A meter with this event name already exists |
| MISCONFIGURED | 503 | CAPACITY_HARNESS_MOBILE_HMAC_SECRET is not set |
| MISSING_AUTH | 401 | Authorization header is requiredSend Authorization: Bearer <your secret key>. |
| NO_CHANGES | 409 | This campaign has no unpublished changes |
| NO_FX_RATE | 422 | No FX rate is configured for this currency pair |
| NO_MERCHANT | 403 | No business is linked to this account. Register at /register or use the admin console for team access. |
| NOT_ALLOWED | 403 | Contact the business to cancel this subscription |
| NOT_CONNECTED | 409 | WhatsApp is not connected |
| NOT_FOUND | 404 | Resource not foundCheck the id, and that it belongs to this key’s mode (test keys see test objects only). |
| NOT_LINKED | 404 | This account no longer exists |
| NOT_MOBILE_MONEY | 400 | This transaction is not a mobile money payment |
| NOT_READY | 409 | Export is not ready for download |
| NOT_REGISTERED | 404 | Unknown or unregistered host |
| NOT_RETRYABLE | 409 | Only blocked, failed or rejected documents can be retried |
| NUMBER_IN_USE | 409 | This WhatsApp number is connected to another business |
| OFFER_EXPIRED | 400 | This offer has expired |
| OFFER_NOT_PENDING | 400, 409 | Only a pending offer can be accepted |
| ONBOARDING_STATE_INVALID | 400, 409 | Total UBO ownership across all owners cannot exceed 100% |
| PAGE_IN_USE | 409 | This Page or Instagram account is connected to another business |
| PAGE_UNAVAILABLE | 404 | This page is not available |
| PASSWORD_BREACHED | 400 | This password has appeared in a data breach. Choose a different password. |
| PASSWORD_REQUIRED | 400 | Password is required for new accounts |
| PAUSED | 409 | Resume the catalog sync first |
| PAYLOAD_TOO_LARGE | 413 | Request body must be 1 MiB or smaller |
| PAYMENT_FAILED | 402 | Subscription retry did not complete |
| PAYMENT_METHOD_NOT_AVAILABLE | 400 | This payment method is not offered in the merchant’s market |
| PAYOUT_NOT_CANCELLABLE | 400, 409 | This payout was cancelled before it was processed |
| PHONE_REQUIRED | 400 | customerPhone is required for mobile money payments |
| PKCE_REQUIRED | 400 | Public clients must send code_challenge (S256) |
| PLAN_HAS_SUBSCRIBERS | 400 | Deactivate subscribers before deactivating plan. |
| PLAN_IN_USE | 409 | Another membership already uses this plan |
| PROVIDER_UNAVAILABLE | 409, 503 | That fiscal provider is not available for your business |
| PROXY_ERROR | 502 | Failed to execute explorer request |
| PUBLISHABLE_KEY_WRITE_FORBIDDEN | 403 | Publishable keys cannot perform write operations. Use a secret key.Publishable keys only pay checkout sessions your server created: call this from your server with a secret key. |
| RATE_LIMIT_EXCEEDED | 429 | Too many requestsBack off: retry after the Retry-After seconds. |
| RATE_LIMIT_UNAVAILABLE | 503 | Rate limiting is temporarily unavailable. Try again shortly. |
| RATE_LIMITED | 429 | Too many explorer requests. Try again in a minute.Back off: retry after the Retry-After seconds. |
| RAW_CARD_DATA_REJECTED | 400 | Card details are entered only in Watenga secure fields or hosted checkout. Use watenga.mount() or secure Elements. |
| RECURRENCE_OFF | 409 | Repeat bookings are switched off for this service |
| RECURRING_DISABLED | 403 | Recurring giving is disabled for this merchant |
| REVIEW_REQUIRED | 403 | Campaign publication requires admin review |
| SAVED_DESIGN_LIMIT | 409 | You can keep up to … saved designs; delete one first |
| SCOPE_FORBIDDEN | 403 | Restricted key lacks … access to refundsThe restricted key lacks the scope this route needs (see the route’s restricted-key scope): use a key with that scope. |
| SEARCH_ERROR | 500 | Search failed |
| SECRET_KEY_REQUIRED | 403 | Read checkout sessions with a secret keyCall this with a secret key from your server. |
| SELF_APPROVAL_FORBIDDEN | 403 | Approver must differ from requester |
| SESSION_EXPIRED | 401 | This view-as session has ended |
| SESSION_IDLE_TIMEOUT | 401 | Session expired due to inactivity |
| SESSION_REFRESH_RACE | 409 | Your session was just refreshed; try again |
| SLUG_TAKEN | 409 | This slug is already used in the marketplace |
| STEP_UP_REQUIRED | 403 | Confirm it is you with a new code first |
| STORAGE_UNAVAILABLE | 503 | Profile photo storage is temporarily unavailableRetry shortly. |
| STORE_NOT_FOUND | 404 | Shop not found |
| SUBMERCHANT_INACTIVE | 403 | This sub-merchant cannot vault cards |
| TAX_UNAVAILABLE | 422, 503 | Tax for this payment link cannot be calculated right now |
| TEST_EVENTS_TEST_APPS_ONLY | 400 | Simulated events are sent to test apps only. Choose your test app. |
| TEST_MODE_LIVE_OBJECT | 400 | A test key cannot pay a live invoice, payment link or checkout. Use a live key.A test key cannot pay a live object: use a live key, or test objects. |
| TEST_MODE_ONLY | 400 | watenga listen and trigger work with test apps only |
| TICKET_INVALID | 400 | This sign-in link has expired. Go back to the shop and try again. |
| TOTP_ALREADY_ENABLED | 409 | 2FA is already enabled |
| TOTP_ENROLLMENT_REQUIRED | 403 | Enable two-factor authentication in Security settings before this action. |
| TOTP_INVALID | 400, 401, 403 | Invalid or expired 2FA codeThe 2FA code is wrong or expired: enter a fresh one. |
| TOTP_NOT_ENROLLED | 400 | Start enrolment first |
| TOTP_REQUIRED | 401, 403 | A 2FA code is required to change your webhook URLSend the 6-digit code from the authenticator app in X-TOTP-Code (dashboard actions). |
| TRUSTPAY_CHECKOUT_REQUIRED | 400 | Please use the TrustPay checkout for this protected payment |
| TRUSTPAY_NOT_ENABLED | 400 | TrustPay is not enabled for this link |
| UBO_NOT_FOUND | 404 | Beneficial owner not found |
| UNAUTHENTICATED | 401 | Authentication required |
| UNAUTHORIZED | 401 | Invalid service signature |
| UNSUPPORTED_GRANT | 400 | Unsupported grant_type |
| UNSUPPORTED_MEDIA_TYPE | 415 | application/json required |
| UPLOAD_MISSING | 400 | Upload was not found in storage |
| UPLOAD_NOT_FOUND | 400 | Uploaded profile photo was not found |
| VALIDATION_ERROR | 400 | A request identifier is not validFix the field named in error.param (all issues are in error.details.issues). |
| VERSION_EXISTS | 409 | Version … already exists for this app |
| VIRTUAL_ACCOUNT_CREATE_FAILED | 500 | Unable to create virtual account |
| WAITLIST_DISABLED | 409 | This service does not take a waitlist |
| WALLET_NOT_AVAILABLE | 503 | … is not enabled for live payments yet |
| WEBAUTHN_FAILED | 401 | Could not verify the security key |
| WEBAUTHN_REQUIRED | 401, 403 | Passkey enrollment is required for this admin role. Register a passkey under Security settings. |
| WEBHOOK_ENDPOINT_DISABLED | 409 | Switch the endpoint back on before replaying its events |
| WEBHOOK_ENDPOINT_LIMIT | 409 | An app can have at most … webhook endpoints |
| WEBHOOK_MISCONFIGURED | 503 | Mobile webhook secret is not configured |