Skip to the tool
MoveAheadPayments Toolbox

Razorpay error code: BAD_REQUEST_ERROR

The request was malformed, unauthorised, or referred to something that does not exist. It is the broadest of Razorpay's three error codes and covers most client-side faults, so the useful detail is in the `description` and `reason` fields rather than in the code itself.

BAD_REQUEST_ERRORHard declineHTTP 400

Retrying the same request will fail the same way.

What it means

Razorpay groups a wide range of client-side problems under this one code: invalid or missing parameters, an invalid API key, an ID that does not exist or that your account may not access, IP allowlisting refusals, and rate limiting. That breadth is why looking the code up rarely helps on its own — two requests failing for completely different reasons both return BAD_REQUEST_ERROR, and only `error.description` distinguishes them.

Common causes

  • A required parameter missing, or one with an invalid value — amount below the minimum, a malformed currency, a bad email.
  • An invalid API key, or test keys used against a live endpoint and the reverse.
  • An entity ID that does not exist, or belongs to a different account: "The id provided does not exist or access is unauthorised".
  • IP allowlisting blocking the caller, reported as "Access Denied".
  • Rate limiting, reported as "Too many requests".
  • An amount sent in rupees rather than paise. Razorpay amounts are in the smallest currency unit, so ₹100 is 10000.

How to fix it

  1. Read `error.description` first. It names the specific problem, which the code does not — logging only the code throws away everything useful about the failure.
  2. Check `error.field` where present; it names the parameter at fault directly.
  3. Confirm the key pair matches the environment. An `rzp_test_` key against live data produces this, as does the reverse.
  4. Send amounts in paise as integers. Passing 100 for ₹100 is one of the most common causes of a rejected order.
  5. Handle rate limiting as a distinct case with backoff, rather than as a permanent failure — it shares the code but not the remedy.

Tools that help

Frequently asked questions

Why does Razorpay use one code for so many different failures?
Because `code` is a coarse class and the detail is carried elsewhere. Razorpay's error object has `code`, `description`, `source`, `step`, `reason`, `field` and `metadata` — the code tells you the category, `source` and `step` tell you where in the flow it broke, and `reason` is the machine-readable specific. Branching on `code` alone gives you three buckets; branching on `reason` gives you something you can act on.
Is a signature verification failure a BAD_REQUEST_ERROR?
Not usually — a webhook signature mismatch is something you detect in your own handler, not something Razorpay returns to you. If you are verifying a `razorpay_signature` from Checkout and it will not match, the cause is almost always that you used the webhook secret where the flow signs with your API key secret. They are different secrets for different signatures.