Start with the HTTP status and error code
A request failing does not always mean an SMS failed or a customer payment was declined. First identify which product and operation returned the error.
OTP responses use top-level code and message. Payment Solution API errors use error.code and error.message. Keep the HTTP status alongside the JSON. Do not treat every HTTP 200 or success: true as a paid transaction or verified person.
Example OTP error
{
"success": false,
"code": "INSUFFICIENT_BALANCE",
"message": "Wallet balance is too low.",
"data": {}
}Example Payment Solution error
{
"success": false,
"error": {
"code": "PAYMENT_TOOLS_SUBSCRIPTION_REQUIRED",
"message": "An active Payment Tools subscription is required."
}
}OTP errors and the safe next step
- 400 INVALID_JSON
- Send a JSON object and
Content-Type: application/json. Do not submit an HTML form to the JSON endpoint. - 401 MISSING_API_TOKEN / INVALID_API_TOKEN
- Send the complete account key as a Bearer token from your backend. Check for extra spaces or an old key after regeneration.
- 403 API_KEY_DISABLED / IP_BLOCKED
- Enable your account key if you disabled it. A security block is not a network setup task; contact support rather than attempting to bypass it.
- 402 INSUFFICIENT_BALANCE
- Add wallet credit before trying again. This is a local credit rejection, not proof that an SMS provider failed.
- 409 IDEMPOTENCY_CONFLICT
- The attempt key was already used for different data. Reuse the original payload for that attempt, or make a genuinely new user-requested attempt with a new key.
- 410 OTP_EXPIRED
- Ask the person to request a fresh code. Do not reuse the expired message ID for a new action.
- 422 OTP_MISMATCH / INVALID_OTP_LENGTH / INVALID_MOBILE
- Check the user's input. Use a valid Indian number and a supported 4, 5 or 6-digit length. Do not retry wrong codes in a loop.
- 429 RATE_LIMITED
- Pause and back off. Reduce per-user sends and polling frequency; avoid starting parallel retries.
- 202 pending reconciliation / unknown outcome
- Save any message ID and check the original attempt. Do not immediately generate another idempotency key and send another SMS.
- 503 provider error
- Keep the exact provider/error code and any message ID. Inspect the original status or retry cautiously with the same idempotency key and payload. A provider-configuration error needs platform support, not a changed recipient number.
Payment errors and the safe next step
- 403 PAYMENT_TOOLS_SUBSCRIPTION_REQUIRED
- Activate or renew a Payment Solution plan. OTP wallet credit alone does not activate this separate product.
- 409 PAYMENT_PROFILE_REQUIRED
- Send both
merchant_idandvpa, or save a matching business account in Setup. Supplying the complete API pair needs no saved profile. - 409 ORDER_ID_ALREADY_EXISTS
- Check the existing order. If recovering from a timeout, do not create another customer charge by automatically assigning a new ID. Only a genuinely different order should have a new ID.
- 422 INVALID_MERCHANT_ID / MERCHANT_VPA_REQUIRED / VPA_NOT_ALLOWED
- Use the exact case-sensitive MID and its matching business VPA. For an unsaved account send the complete pair. A lone MID or VPA selects only a matching account in your own saved list.
- 422 MERCHANT_ID_MISMATCH / AMOUNT_MISMATCH
- Do not fulfil. Compare your stored order and expected amount. An existing link's receiving account cannot be switched during verification.
- 422 INVALID_REDIRECT_URL
- Use your HTTPS completion URL without embedded credentials or a URL fragment. Query parameters are permitted.
- 429 PAYMENT_LINK_LIMIT_REACHED
- Your plan's link quota has been used. Review usage and upgrade or renew as appropriate.
- 503 PAYMENT_LINK_BUSY
- A link is being created for the same account. Wait briefly and retry with the same order ID.
- Pending, unknown, failed or expired with a claimed deduction
- Recheck the original order and exact amount. Keep it unfulfilled until payment is confirmed. Do not use a screenshot or browser redirect as proof, and do not ask for another payment before checking the first one.
Connection, QR and webhook problems
The response is HTML instead of JSON
Check that you called the full /api/v1/... endpoint rather than a login or dashboard URL. Record the HTTP status and content type. Do not disable HTTPS verification or forward a live key to an unrelated host to work around a proxy/hosting error.
A QR image does not appear on another website
Use the returned public qr_url or qr_png_url in an image element. An expired, cancelled or failed checkout may no longer serve a usable QR. Check your site's own image security policy too. An image URL is not the authenticated payment-status endpoint and does not need your API key in the browser.
A webhook did not arrive or failed signature validation
Confirm that the webhook is configured in Payment Solution Setup, uses reachable HTTPS and has the correct separate secret. Validate the original raw body before JSON parsing or reformatting it. Keep an authenticated status-check fallback for missed deliveries.
What to send support
Include the product, endpoint, HTTP status, error code, request time with timezone and a non-secret message/order reference. Add a redacted response if useful. Never include your API key, password, webhook secret, OTP or UPI PIN.
Continue with the OTP API reference, payment integration guide or wallet and plan guide.
Need a hand?
Send support the endpoint, request time, error code and a non-secret reference. Never send your API key, password, webhook secret or an OTP.
Contact developer support