Errors
Error response format, status codes, rate limits, and retry guidance
Every API error response uses this envelope:
{
"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.