invalid_request
The request body or query parameters failed validation before Canopy attempted the operation.
HTTP 400
When this happens
Canopy validates every /api/v1/* request with a strict schema before touching any state, and returns invalid_request when that validation fails. Two examples: a POST /api/v1/intents body missing a required field or carrying a field of the wrong type, and a GET /api/v1/intents request whose cursor query parameter is not a non-negative integer.
Two other errors are also 400s, with a different code in the envelope below. invalid_json means the body is not parseable JSON at all. unsupported_version means the Canopy-Version header names a version Canopy does not serve.
The error envelope
Every /api/v1/* error shares one shape, and the keys always serialize in this order. param and detail are omitted entirely, never sent as null, when the error does not carry them.
{
"error": {
"code": "invalid_request",
"message": "The request body failed validation.",
"param": "priceUnits",
"request_id": "req_1a2b3c4d5e6f7a8b9c0d1e2f",
"docs": "https://canopypay.io/errors/invalid_request"
}
}param, when present, names the first field that failed validation, in dot-path notation (metadata.reference for a nested field). Validation stops at the first issue, so treat it as a hint for logging and debugging rather than a list of every violation.
What to do about it
Re-check the request against the operation's documented request schema, paying particular attention to the field named in param when one is present. This is always a client-side fix: retrying the identical request will fail identically. invalid_request is never retried automatically by Canopy's own SDK, because retrying a request that was rejected before any state changed would not change the outcome.
If the request looks correct and you still receive invalid_request, include the request_id from the error body when contacting support. It identifies this exact request in Canopy's logs.