# Errors
Error response format, status codes, rate limits, and retry guidance
Source: https://www.klarefi.com/docs/api/errors

Every API error response uses this envelope:

```json
{
  "error": {
    "type": "validation_error",
    "code": "missing_document_url",
    "message": "document_url is required and must be a string",
    "request_id": "req_abc123def456"
  }
}
```

## Error types

| Type                   | Status | Meaning                                                 |
| ---------------------- | ------ | ------------------------------------------------------- |
| `authentication_error` | 401    | Missing, invalid, expired, or revoked key               |
| `authorization_error`  | 403    | Key is valid but lacks the required scope               |
| `validation_error`     | 400    | Invalid body, path, query, or idempotency use           |
| `not_found`            | 404    | Resource does not exist for the organization            |
| `billing_error`        | 402    | Live billing or live usage gate blocked                 |
| `precondition_error`   | 428    | Required legal or setup precondition missing            |
| `rate_limit_error`     | 429    | Per-key rate limit or monthly test-session cap exceeded |
| `internal_error`       | 500    | Unexpected Klarefi server error                         |

## Error codes

| Code                                    | HTTP status | Meaning                                                                         | What to do                                                   |
| --------------------------------------- | ----------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `invalid_api_key`                       | 401         | The API key is missing, invalid, revoked, expired, or for the wrong environment | Replace an expired/rotated key or send a valid key           |
| `forbidden`                             | 403         | The key does not have the required scope                                        | Add the scope or use a key with the right access             |
| `billing_required`                      | 402         | Live API access requires active billing                                         | Enable billing or use a test key                             |
| `live_usage_cap_exceeded`               | 402         | The workspace reached its live usage cap                                        | Wait for the cap to reset or increase the cap                |
| `precondition_required`                 | 428         | A required account precondition is missing                                      | Complete the setup step described in the message             |
| `legal_acceptance_required`             | 428         | Current self-serve legal terms must be accepted                                 | Accept the current terms before live API access              |
| `self_serve_webhooks_disabled`          | 428         | Self-serve webhook delivery is disabled for this deployment                     | Enable self-serve webhooks before creating intake work       |
| `rate_limit_exceeded`                   | 429         | The key exceeded its per-minute rate limit                                      | Retry after `Retry-After` or `X-RateLimit-Reset`             |
| `test_usage_cap_exceeded`               | 429         | The workspace created 50 test API sessions in the current UTC month             | Wait for the next month before creating another test session |
| `invalid_request`                       | 400         | The request is malformed                                                        | Fix the body, path, query, or headers                        |
| `invalid_json`                          | 400         | The JSON body could not be parsed                                               | Send valid JSON with `Content-Type: application/json`        |
| `invalid_connector_payload`             | 400         | Connector manifest validation failed                                            | Fix the connector fields in the response message             |
| `missing_connector_key`                 | 400         | A connector key was required but missing                                        | Provide `connector_key` or the path connector key            |
| `openapi_fetch_failed`                  | 400         | The OpenAPI URL could not be fetched                                            | Confirm the URL is public HTTPS and returns JSON             |
| `missing_openapi_spec`                  | 400         | No OpenAPI source was provided                                                  | Send `openapi_url`, `openapi_json`, or `openapi`             |
| `openapi_yaml_not_supported`            | 400         | YAML OpenAPI specs are not accepted                                             | Convert the spec to JSON before import                       |
| `invalid_openapi_spec`                  | 400         | The OpenAPI document could not be parsed                                        | Send a valid OpenAPI JSON document                           |
| `invalid_openapi_connector`             | 400         | A connector could not be generated from the spec                                | Fix unsupported or incomplete connector metadata             |
| `missing_document_url`                  | 400         | `document_url` is missing from `POST /process`                                  | Send a public HTTPS document URL                             |
| `invalid_document_url`                  | 400         | `document_url` is not an allowed public HTTPS URL                               | Use a public HTTPS URL, not private or local network         |
| `per_request_webhook_url_not_supported` | 400         | Per-request webhook URLs are not supported                                      | Register webhook endpoints in the dashboard                  |
| `missing_case_type_id`                  | 400         | `case_type_id` is required                                                      | Send a configured case type ID                               |
| `invalid_integration_identity`          | 400         | Integration identity fields are invalid                                         | Send non-empty string identity fields                        |
| `missing_idempotency_key`               | 400         | An idempotency key is required                                                  | Send `idempotency_key` or `Idempotency-Key`                  |
| `idempotency_key_conflict`              | 400         | The idempotency key was reused with different parameters                        | Generate a new key for different work                        |
| `external_case_id_conflict`             | 400         | The external case ID already exists for the organization                        | Use the existing case or a different external ID             |
| `missing_case_id`                       | 400         | A case ID path segment is missing                                               | Include the case ID in the URL                               |
| `invalid_after_cursor`                  | 400         | `after_cursor` is not an integer                                                | Send an integer cursor, usually the previous `next_cursor`   |
| `invalid_limit`                         | 400         | `limit` is outside the allowed event page size range                            | Send an integer from 1 to 500                                |
| `missing_doc_id`                        | 400         | A document ID path segment is missing                                           | Include the document ID in the URL                           |
| `invalid_acknowledgement_payload`       | 400         | Webhook acknowledgement payload validation failed                               | Send a valid `acknowledgement_id` or omit it                 |
| `webhook_delivery_not_delivered`        | 400         | The delivery cannot be acknowledged before a successful delivery                | Wait until the delivery status is delivered                  |
| `missing_endpoint_url`                  | 400         | `endpoint_url` is missing from webhook test                                     | Send a public HTTPS receiver URL                             |
| `missing_signing_secret`                | 400         | `signing_secret` is missing from webhook test                                   | Send the endpoint signing secret                             |
| `invalid_endpoint_url`                  | 400         | `endpoint_url` is not an allowed public HTTPS URL                               | Use a public HTTPS URL, not private or local network         |
| `not_found`                             | 404         | The requested resource was not found for the organization                       | Check the ID and environment                                 |
| `internal_error`                        | 500         | Klarefi hit an unexpected server error                                          | Retry if safe and contact support with `request_id`          |

## Rate limits

Authenticated success responses include:

| Header                  | Description                          |
| ----------------------- | ------------------------------------ |
| `X-RateLimit-Limit`     | Maximum requests per minute          |
| `X-RateLimit-Remaining` | Remaining requests in the window     |
| `X-RateLimit-Reset`     | Epoch seconds when the window resets |

When the limit is exceeded, Klarefi returns `429 rate_limit_error` and may
include `Retry-After`. The 429 response also includes the same
`X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers.

## Retry guidance

Retry `429` responses after the rate-limit reset. Retry network failures with
the same idempotency key. Do not blindly retry `400`, `401`, `403`, `404`,
`402`, or `428` responses; those require a request or account-state change.

The test-session monthly cap resets at the start of each UTC calendar month.
Idempotent replays do not consume another session from the cap.
