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

# Errors and limits

> Understand error responses, request IDs, rate-limit headers, and CORS behavior.

# Errors and limits

Errors use a stable JSON shape:

```json theme={null}
{
  "error": {
    "code": "invalid_subscription",
    "message": "Invalid option",
    "field": "period",
    "suggestedFix": "Use one of the supported billing periods: monthly, yearly, custom.",
    "allowedValues": ["monthly", "yearly", "custom"]
  },
  "requestId": "request-..."
}
```

`field`, `suggestedFix`, `allowedValues`, and `writableFields` are included when the server can provide a precise recovery hint. AI agents should use those fields to correct the payload instead of guessing.

## Common error codes

| Status | Code                         | Meaning                                                         |
| -----: | ---------------------------- | --------------------------------------------------------------- |
|  `400` | `invalid_json`               | Request body is not a JSON object                               |
|  `400` | `invalid_subscription`       | Subscription fields failed validation                           |
|  `400` | `invalid_subscription_field` | The request tried to write a server-managed field               |
|  `400` | `invalid_subscription_id`    | Subscription ID is not a valid UUID                             |
|  `400` | `invalid_pagination`         | `limit` or `offset` query parameter is out of range             |
|  `400` | `invalid_query`              | A filter or `sort` query parameter is invalid                   |
|  `400` | `empty_patch`                | PATCH body did not include any writable fields                  |
|  `401` | `authentication_required`    | Missing Bearer token                                            |
|  `401` | `invalid_api_key`            | API key is invalid or revoked                                   |
|  `403` | `insufficient_scope`         | The API key lacks the `write` scope required for this operation |
|  `404` | `subscription_not_found`     | Subscription does not exist for the API key owner               |
|  `405` | `method_not_allowed`         | HTTP method is not supported                                    |
|  `429` | `rate_limit_exceeded`        | User request limit or invalid-auth limit exceeded               |
|  `500` | `internal_error`             | Unexpected server error                                         |

## Recovery fields

| Field            | Meaning                                                     |
| ---------------- | ----------------------------------------------------------- |
| `field`          | The request field that caused the error                     |
| `suggestedFix`   | Human- and AI-readable correction guidance                  |
| `allowedValues`  | Valid enum values for fields such as `currency` or `period` |
| `writableFields` | Fields accepted by `POST` and `PATCH` subscription requests |

Example non-writable field error:

```json theme={null}
{
  "error": {
    "code": "invalid_subscription_field",
    "message": "Field is not writable: nextPaymentDate",
    "field": "nextPaymentDate",
    "suggestedFix": "Remove server-managed fields such as id, nextPaymentDate, createdAt, and updatedAt before retrying.",
    "writableFields": [
      "amount",
      "category",
      "currency",
      "customDate",
      "lastPaymentDate",
      "name",
      "notificationEnabled",
      "period",
      "status"
    ]
  },
  "requestId": "request-..."
}
```

## Scopes

API keys carry scopes. A `read` key can list and read subscriptions and call the analytics and audit endpoints. A `write` key additionally allows create, update, cancel, pause, resume, and delete. A write call made with a read-only key returns `403 insufficient_scope`; do not retry — request a write-scoped key. See [Authentication](/en/api/authentication#scopes).

## Rate-limit headers

Authenticated API responses include:

```text theme={null}
X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-Reset
```

`X-RateLimit-Reset` is a Unix timestamp in seconds.

Validation failures (`400`) are rejected before the hourly quota is consumed, so they do not count against your limit and do not carry rate-limit headers. Fixing the payload and retrying is free.

`429` responses also include a `Retry-After` header with the number of seconds to wait before retrying. This applies both to the per-user request limit and to the "too many invalid API key attempts" lockout.

```text theme={null}
Retry-After: 2700
```

## CORS

The subscription API supports browser preflight requests:

```text theme={null}
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS
```

Keep API keys out of browser apps unless you fully trust the browser context. CORS support is mainly for developer tooling, internal dashboards, or trusted local workflows.
