Errors
The error response format and every status and code the API can return.
Every error response is JSON with an error code. Some errors add message (a sentence for a human) or details (what was wrong, sometimes a list of strings). Branch your code on the HTTP status and the error code, never on the message text: the wording can change.
Example (400)
{
"error": "invalid_request",
"details": "body must be JSON"
}Every error
| Status | Code | When | Retry? |
|---|---|---|---|
| 400 | invalid_request |
The request body is not JSON, a field fails validation, the webhook_url is refused, or (on list orders) a query parameter is wrong. details says exactly what was wrong. |
Fix the request; do not retry as is. |
| 400 | invalid_payment_account |
payment_account_id is malformed, unknown, removed, or belongs to a different business. Create returns the same code and message for every one of these cases, so nothing leaks about which account ids exist. |
Fix the request; do not retry as is. |
| 401 | missing_api_key |
No API key was sent. | Fix the request; do not retry as is. |
| 401 | invalid_api_key |
The key is unknown, or it has been revoked. | Fix the request; do not retry as is. |
| 402 | payment_account_paused |
The UPI account you asked for (or your default account) is paused because your plan's UPI account limit was reached. See below. | Upgrade, choose a different account, or make the paused account your default; do not retry as is. |
| 402 | plan_limit_reached |
This month's collections reached your plan's limit. See below. | Upgrade, or wait for the reset date; do not retry as is. |
| 403 | merchant_disabled |
The business is disabled, including a business that is inside its 7-day account deletion window. Returned by create, get and list. | Do not retry. |
| 404 | order_not_found |
No order with this id belongs to your key's business. | Do not retry; check the id. |
| 409 | upi_not_configured |
The merchant has not added a UPI ID yet. | Add a UPI ID in Settings, then retry. |
| 500 | db_error |
A database error while handling the request. | Safe to retry after a short wait. |
| 500 | internal_error |
An unexpected error. | Safe to retry after a short wait. |
| 503 | all_payment_slots_busy |
Too many open orders share this amount right now. | Retry after a few minutes. |
| 429 | rate_limited |
Too many requests: 600 a minute per address, or 1200 a minute per API key. retry_after gives the seconds to wait, and the response also carries a Retry-After header. |
Wait retry_after seconds, then retry. |
The plan limit error
402 plan_limit_reached adds usage fields so you can show your merchant why:
{
"error": "plan_limit_reached",
"message": "You have reached this month's collection limit for your plan. Upgrade to keep creating payment links. Links you already shared still confirm.",
"upgrade_url": "https://app.upinow.in/app/billing",
"plan": "dukaan",
"limit_paise": 10000000,
"collected_paise": 10000000,
"resets_on": "2026-10-01"
}limit_paise and collected_paise are in paise, not rupees. Links you already shared before hitting the limit keep confirming; only creating a new one is blocked.
The paused account error
402 payment_account_paused means the UPI account you asked for (or your default account, if you did not pass payment_account_id) is beyond your plan's UPI account limit and paused: it takes no new orders, but any link already shared on it still confirms as normal.
{
"error": "payment_account_paused",
"message": "This UPI account is paused because your plan includes fewer UPI accounts. Upgrade, or make it your default account, to create links on it. Links you already shared still confirm.",
"upgrade_url": "https://app.upinow.in/app/billing"
}Choose a different, active account with payment_account_id, make the paused account your default in Settings (which switches it on and pauses another account instead), or upgrade your plan.