Ocriva Logo

Documents

Error Code Reference

Complete reference of all API error codes with causes, solutions, and examples.

errorsreferenceapitroubleshootingstatus-codes

Published: 4/4/2026

Error Code Reference

Every non-2xx response from the Ocriva API returns a consistent JSON error object. This page lists all status codes, their causes, and how to resolve them.

Error Response Format

All API errors share the same JSON envelope:

{
  "statusCode": 400,
  "message": "Validation failed: templateId must be a non-empty string",
  "error": "Bad Request"
}
FieldTypeDescription
statusCodenumberHTTP status code (mirrors the response status)
messagestringHuman-readable description of what went wrong
errorstringShort error classification matching the HTTP reason phrase

Some endpoints that return field-level validation errors extend message into an array:

{
  "statusCode": 400,
  "message": [
    "templateId must be a non-empty string",
    "projectId must be a UUID"
  ],
  "error": "Bad Request"
}

Quick Reference

Status CodeNameOne-liner
400Bad RequestMissing field, wrong type, or failed validation
401UnauthorizedAPI key absent, invalid, or expired
403ForbiddenValid key but insufficient permissions or IP not allowed
404Not FoundResource does not exist or belongs to a different project
409ConflictDuplicate resource or concurrent modification detected
413Payload Too LargeFile exceeds the size limit for your plan
429Too Many RequestsRate limit exceeded; back off and retry
500Internal Server ErrorUnexpected server-side failure

400 Bad Request

The request was malformed — a required field is missing, a value has the wrong type, or a parameter failed a format check.

Common triggers:

  • Missing templateId or projectId in an upload request
  • Sending pageRange as a string instead of an object
  • Providing an organizationId that is not a valid ObjectId

Example — missing required field:

POST /api/upload
{
  "projectId": "proj_abc123"
  # templateId omitted
}

Response:

{
  "statusCode": 400,
  "message": "Validation failed: templateId must be a non-empty string",
  "error": "Bad Request"
}

Fix: Check the request body against the API Reference. All required parameters must be present and correctly typed. Use the message field — it names the exact field that failed.


401 Unauthorized

The request could not be authenticated. This means the API key is missing, malformed, revoked, or does not have access to the resource being requested.

Common triggers:

  • X-API-Key header is absent
  • The token has been deleted or regenerated since the request was built
  • Using an organization-level token against a project that belongs to a different organization

Example:

GET /api/processing-history
# X-API-Key header missing

Response:

{
  "statusCode": 401,
  "message": "Invalid or missing API key",
  "error": "Unauthorized"
}

Fix: Ensure every request includes the X-API-Key header with a valid token. Tokens are created under Organization → API Tokens or Project → API Tokens and are shown only once at creation time. If the token is lost, create a new one.

NOTE

For SDK users, a 401 maps to AuthenticationError. See SDK Error Handling for typed catching.


403 Forbidden

The API key is valid but does not have permission to perform the requested action.

Common triggers:

  • Using a project-scoped token to access a different project's resources
  • Your organization's source IP is not in the webhook endpoint's allowlist
  • Attempting an admin action (for example, deleting an organization) with a standard member token

Example:

DELETE /api/organizations/org_xyz
# Token belongs to a member role, not an owner

Response:

{
  "statusCode": 403,
  "message": "You do not have permission to delete this organization",
  "error": "Forbidden"
}

Fix: Use a token that has the required scope. For organization-level operations use an organization token from an owner account. For project isolation, ensure the token's project matches the resource you are querying.


404 Not Found

The requested resource does not exist, or it exists but belongs to a different project or organization than the one the token is scoped to.

Common triggers:

  • Typo in the record ID (e.g., hist_ prefix for processing history records)
  • Querying a resource with a project-scoped token when the resource belongs to a different project
  • The resource was deleted before the request arrived

Example:

GET /api/processing-history/hist_does_not_exist?projectId=proj_abc123

Response:

{
  "statusCode": 404,
  "message": "Processing history record not found",
  "error": "Not Found"
}

Fix: Verify the ID against Processing History in the dashboard. If using the API, confirm the projectId query parameter matches the project the record belongs to.


409 Conflict

The request conflicts with existing data or with a concurrent operation.

Common triggers:

  • Creating a template with a name that already exists in the project
  • Two simultaneous requests attempting to deduct credits from the same balance (optimistic locking violation)

Example — duplicate template name:

{
  "statusCode": 409,
  "message": "A template named 'Invoice Extractor' already exists in this project",
  "error": "Conflict"
}

Example — concurrent credit update:

{
  "statusCode": 409,
  "message": "Credit was modified by another process. Please retry.",
  "error": "Conflict"
}

Fix: For duplicate name conflicts, choose a unique name or update the existing resource. For credit concurrency conflicts, the system retries automatically up to three times — if the error surfaces persistently, reduce concurrent processing requests or contact support.


413 Payload Too Large

The uploaded file exceeds the size limit enforced for your organization's subscription plan.

Response:

{
  "statusCode": 413,
  "message": "File size exceeds the maximum allowed limit of 20 MB",
  "error": "Payload Too Large"
}

Fix: Compress or split the file before uploading. Current per-file limits are visible at Organization → Limits. As a general guideline, files up to 20 MB are supported on standard plans. Upgrading your subscription increases the limit.


429 Too Many Requests

Your API key has exceeded the rate limit for the current time window.

Response:

{
  "statusCode": 429,
  "message": "Rate limit exceeded. Retry after 32 seconds.",
  "error": "Too Many Requests"
}

The response includes a Retry-After header with the number of seconds to wait:

Retry-After: 32

Fix: Wait for the window to reset before sending additional requests. The SDK handles this automatically — it reads the Retry-After header and pauses before retrying (up to maxRetries times). For bulk workloads, use the Batch Processing endpoint to group many files into a single API call rather than uploading them one by one.

See SDK Error Handling — Rate Limiting for retry configuration options.


500 Internal Server Error

An unexpected error occurred on the server. This is not caused by your request.

Response:

{
  "statusCode": 500,
  "message": "An unexpected error occurred. Please try again later.",
  "error": "Internal Server Error"
}

When to retry: Transient 500 errors (for example, a momentary database hiccup) often resolve on their own. The SDK automatically retries 5xx responses with exponential backoff.

When to contact support: If the error recurs across multiple retries or persists over several minutes, open a support ticket at Support → Tickets. Include:

  • The requestId or eventId from the response headers (see Debugging Tips below)
  • The endpoint and request body (with secrets redacted)
  • The timestamp of the failing request

SDK Error Mapping

The @ocriva/sdk maps HTTP status codes to typed error classes so you can use instanceof checks instead of comparing raw status numbers:

Status CodeSDK Error ClassNotes
401AuthenticationErrorExtends ApiError
404NotFoundErrorExtends ApiError
429RateLimitErrorHas retryAfter property; auto-retried
400, 403, 409, 413, 500ApiErrorCheck error.statusCode for the specific code
Network / timeoutOcrivaErrorBase class; not an HTTP error

See SDK Error Handling for the full error hierarchy, property reference, and code examples.


Webhook Error Codes

Webhook delivery and signature verification have their own failure modes that appear in the Webhooks → Delivery Logs section of the dashboard.

Delivery Failures

FailureDescription
DELIVERY_TIMEOUTYour endpoint did not respond within 10 seconds
DELIVERY_HTTP_ERRORYour endpoint returned a non-2xx status code
DELIVERY_CONNECTION_REFUSEDThe endpoint URL was unreachable
MAX_RETRIES_EXCEEDEDAll automatic retry attempts exhausted (up to 5 retries with backoff)

Ocriva retries failed deliveries automatically. Each retry is logged with its own status. If all retries fail, the event is marked as permanently failed and you can manually trigger a replay from the delivery log.

Signature Verification Failures

If your endpoint rejects the X-OCR-Signature header, verify:

  1. You are using the signing secret shown at endpoint creation time (it is only displayed once).
  2. You are computing the HMAC-SHA256 over the raw request body bytes — not a parsed/re-serialized JSON string.
  3. The Content-Type header on incoming requests is application/json.

See Webhooks Guide for the full verification code sample.


Tips for Debugging

Use requestId and eventId

Every API response includes a requestId header. Every webhook payload includes an eventId field. Include these identifiers when opening a support ticket — they allow the Ocriva team to trace the exact request through server logs.

# Extract requestId from a curl response
curl -si https://api.ocriva.com/api/processing-history \
  -H "X-API-Key: $OCRIVA_API_KEY" \
  | grep -i x-request-id

Check Processing History

The Processing History page logs the outcome of every document — including failures. Click any record to expand it and read the exact error message returned by the AI provider or the internal processing pipeline. Use the ID filter to jump directly to a specific record by its hist_ ID.

Reproduce with a Minimal Request

Strip your request down to the minimum required fields and add fields back one at a time. This isolates which parameter is triggering a 400 validation error.