---
updatedAt: 2026-08-12T18:03:14.000Z
---

Fetch the complete documentation index at: https://developer.benjipays.com/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Errors

RFC 7807 problem details, common status codes, and how to interpret error bodies.

All non-2xx responses are served as `application/problem+json` and follow [RFC 7807 Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc7807).

## Envelope

```json
{
  "type": "https://api.benjipays.com/problems/<slug>",
  "title": "<short title>",
  "status": 401,
  "detail": "<human-readable explanation>",
  "instance": "/v2/<path>",
  "requestId": "5e3e7c8e-1a04-4f7e-9c1f-9e0c5b9b1a23",
  "correlationId": "trace-abc-123"
}
```

| Field           | Type         | Description                                                              |
| --------------- | ------------ | ------------------------------------------------------------------------ |
| `type`          | string (URI) | Identifies the problem class. Stable per error category.                 |
| `title`         | string       | Short, human-readable summary of the class.                              |
| `status`        | integer      | HTTP status code.                                                        |
| `detail`        | string       | Explanation specific to this occurrence.                                 |
| `instance`      | string (URI) | URI identifying this specific failure.                                   |
| `requestId`     | string       | Echoed `X-Request-ID` — included whenever the middleware has set it.     |
| `correlationId` | string       | Echoed `X-Correlation-ID` — included whenever the middleware has set it. |

Both `requestId` and `correlationId` are always set by the middleware, so a single ID will identify a failure across your logs, the API's logs, and any support ticket. See [Request Tracing](./request-tracing.md).

## Common statuses

| Status                      | When                                                                                                                                                                                                                                             |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400 Bad Request`           | Validation error (`type` `…/validation-error`; may include an `errors[]` extension), or an invalid idempotency key (`type` `…/idempotency-key-invalid`).                                                                                         |
| `401 Unauthorized`          | Missing, invalid, or expired credentials; or organization API access is not active (disabled or missing). See [Authentication](./authentication.md).                                                                                             |
| `403 Forbidden`             | Wrong actor type, missing OAuth scope, insufficient mapping permission for the API key owner, or free trial ended without billing enabled.                                                                                                       |
| `404 Not Found`             | Unknown route or tenant-scoped resource not visible to the caller.                                                                                                                                                                               |
| `409 Conflict`              | Idempotency-key body conflict, or a domain conflict. See [Idempotency](./idempotency.md).                                                                                                                                                        |
| `429 Too Many Requests`     | Rate limit exceeded (`type` `…/rate-limit-exceeded`), or an in-flight idempotent request with the same key (`type` `…/idempotency-processing`). Includes `Retry-After`. See [Rate Limits](./rate-limits.md) and [Idempotency](./idempotency.md). |
| `500 Internal Server Error` | Unexpected failure. Safe to retry idempotent requests.                                                                                                                                                                                           |

## Examples

### 400 with field-level details

```json
{
  "type": "https://api.benjipays.com/problems/validation-error",
  "title": "Bad Request",
  "status": 400,
  "detail": "Request body failed validation",
  "instance": "/v2/partners",
  "errors": [
    {
      "field": "externalId",
      "message": "Required",
      "code": "invalid_type",
      "path": ["externalId"]
    }
  ],
  "requestId": "9c6d…",
  "correlationId": "trace-abc-123"
}
```

### 401 unauthorized

```http
HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
```

```json
{
  "type": "https://api.benjipays.com/problems/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid or missing authentication token",
  "instance": "/v2/whoami"
}
```

### 403 forbidden — wrong actor

```json
{
  "type": "https://api.benjipays.com/problems/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "Access denied. Required actor type: partner",
  "instance": "/v2/partners/accounts"
}
```

### 403 forbidden — missing scope

```json
{
  "type": "https://api.benjipays.com/problems/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "Insufficient scope",
  "instance": "/v2/partners/accounts"
}
```

### 403 forbidden — free trial ended without billing

Organization-scoped merchant routes (`/v2/invoices`, `/v2/gateways`, etc.) return this when the organization's free trial has ended and billing is not enabled:

```json
{
  "type": "https://api.benjipays.com/problems/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "Free trial has ended and billing is not enabled",
  "instance": "/v2/gateways"
}
```

### 429 too many requests (rate limit)

```http
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 1
```

```json
{
  "type": "https://api.benjipays.com/problems/rate-limit-exceeded",
  "title": "Too Many Requests",
  "status": 429,
  "detail": "Rate limit exceeded. Please retry after the specified time.",
  "instance": "/v2/whoami",
  "retryAfterSeconds": 1,
  "limit": 5
}
```

In-flight idempotency uses the same HTTP status but a different `type` (`…/idempotency-processing`). See [Idempotency](./idempotency.md).

## Best practices

* Parse `application/problem+json` responses by their `status` and `type` — don't string-match on `detail`.
* Distinguish 401 (re-authenticate) from 403 (you can't do this with these credentials).
* Use `requestId` / `correlationId` from the body when filing support tickets.
* Retry `429` only after honoring `Retry-After`. Retry `500` only on idempotent operations.
* Treat unknown problem `type` URIs as if they were just the HTTP `status` — the platform may add new categories.