# Errors and Rate Limits

Handle authentication, authorization, publication, rate-limit, and service errors by HTTP status.

## Error response

```json
{
  "code": 403,
  "message": "The application is not authorized to access this endpoint",
  "data": []
}
```

External responses guarantee only `code`, `message`, and `data`. Internal audit error codes are not exposed as an `error_code` JSON field, so clients must not assume that field exists.

## HTTP status codes

| Status | Common scenarios                                                                                 | Recommended action                                                |
| ------ | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| `401`  | Missing, invalid, or expired Access Token; disabled application; invalid application credentials | Refresh once; stop and contact the administrator if refresh fails |
| `403`  | The application has not been granted this endpoint                                               | Do not retry; ask the administrator to review the endpoint grant  |
| `404`  | The route does not exist or is not published through OpenAPI                                     | Check the path and endpoint publication status                    |
| `405`  | The path exists but the HTTP method is wrong                                                     | Use a method listed in the `Allow` response header                |
| `422`  | Required JSON fields are missing or have invalid types or lengths                                | Correct the request before retrying                               |
| `429`  | Authentication limit, failed-authentication lock, QPS limit, or exhausted 30-day quota           | Wait for the duration specified by `Retry-After`                  |
| `500`  | Unrecognized internal exception                                                                  | Record `X-Request-Id` and use a bounded backoff retry             |
| `503`  | Rate-limit Redis unavailable or missing endpoint rate-limit configuration                        | Record the request ID, back off, and notify the administrator     |

A `401` response includes `WWW-Authenticate: Bearer`. Every OpenAPI response includes `X-Request-Id`, which can be used to correlate the request with platform audit logs.

## Business endpoint rate limits

Rate limits are counted independently by `application ID + endpoint ID`.

- QPS uses a fixed one-second window.
- The 30-day quota starts on the first request in the current counter cycle and lasts exactly 2,592,000 seconds; it is not aligned to a calendar month.
- New endpoints enable rate limiting by default with a QPS limit of `10` and a 30-day quota of `100000`; administrators can change or disable these values.
- When rate limiting is enabled, a Redis outage returns `503` instead of allowing unlimited traffic.

Successful responses can include:

| Header                      | Description                                         |
| --------------------------- | --------------------------------------------------- |
| `X-RateLimit-Status`        | `enabled` or `disabled`                             |
| `X-RateLimit-QPS-Limit`     | Requests allowed per second                         |
| `X-RateLimit-QPS-Remaining` | Requests remaining in the current one-second window |
| `X-RateLimit-30d-Limit`     | Total quota for the current 30-day cycle            |
| `X-RateLimit-30d-Remaining` | Remaining quota in the current cycle                |
| `X-RateLimit-30d-Reset`     | Unix timestamp when the current cycle resets        |

A rate-limit rejection also includes `Retry-After` in seconds.

## Default authentication limits

These are plugin defaults and can be overridden by the deployment environment:

| Endpoint or dimension                     | Default limit          |
| ----------------------------------------- | ---------------------- |
| Issue tokens, source IP                   | 10 requests per minute |
| Issue tokens, App Key and source IP       | 5 requests per minute  |
| Refresh tokens, source IP                 | 30 requests per minute |
| Refresh tokens, Refresh Token fingerprint | 10 requests per minute |
| Revoke tokens, source IP                  | 30 requests per minute |

After five consecutive token-issue failures for the same credential, the server applies an exponential lock starting at 60 seconds and capped at 15 minutes. A successful authentication clears the corresponding failure state.

## Retry guidance

- `401`: Refresh and replay at most once. Require credential reconfiguration if refresh fails.
- `403`, `404`, `405`, `422`: Fix the configuration or request; do not automatically retry.
- `429`: Respect `Retry-After` and add a small amount of random jitter.
- `500`, `503`: Use bounded exponential backoff and retain `X-Request-Id`.
- Do not automatically replay non-idempotent business requests without a business idempotency key.

## Log security

Client logs should include the method, path, HTTP status, business `code`, duration, and `X-Request-Id`. Do not log:

- App Secrets
- Full Access Tokens or Refresh Tokens
- `Authorization` or Cookie headers
- Complete request or response bodies containing sensitive data
