> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paj.cash/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> What each status code means, and which failures are worth retrying.

Errors are returned with a conventional HTTP status and a JSON body:

```json theme={null}
{
  "statusCode": 400,
  "message": "Bank with code 000999 not found",
  "error": "Bad Request"
}
```

`message` is a string for most failures, but request validation returns an
**array** of messages — one per invalid field. Handle both shapes:

```ts theme={null}
const detail = Array.isArray(body.message)
  ? body.message.join(', ')
  : body.message;
```

## Status codes

<ResponseField name="400 Bad Request" type="permanent">
  The request itself is wrong. On registration this covers an unknown
  `bankCode` and an `accountNumber` the bank could not confirm; on search it
  means neither `address` nor `accountNumber` was supplied. Retrying identical
  input will fail identically.
</ResponseField>

<ResponseField name="401 Unauthorized" type="permanent">
  The `x-api-key` header is missing or does not match a business. See
  [Authentication](/authentication).
</ResponseField>

<ResponseField name="404 Not Found" type="permanent">
  Nothing matched. For a search, the bank account has not been registered with
  Paj. For rates, no active rate exists for that currency — read this as "not
  supported yet", not as a malformed request.
</ResponseField>

<ResponseField name="5xx" type="transient">
  A failure on Paj's side or on a rail it depends on. Safe to retry with backoff.
</ResponseField>

## Validation happens before your request is processed

Unknown fields are rejected rather than ignored: sending a body property that
is not part of the schema fails the request outright. Send exactly the
documented fields.

## Retrying safely

Registration is idempotent per bank account, so retrying a
`POST /pub/v2/bank-account` that timed out is safe — you get the existing record
back rather than a duplicate. The two `GET` endpoints are read-only and always
safe to retry.

<Warning>
  Do not retry a `400` or a `401`. Both indicate the request will never succeed
  as sent; a retry loop on a failing bank account confirmation puts avoidable
  load on the banking rail.
</Warning>

## Timeouts

Registration makes a live call to the banking rail to confirm the account and
performs on-chain work to assign the address, so it is meaningfully slower than
the other endpoints. Allow a generous client timeout — 30 seconds is
comfortable — and prefer registering accounts ahead of time rather than inside a
latency-sensitive flow.
