Oligon Receipts is in private beta — request access.
API reference
Errors

Errors

All errors return a JSON body with this shape:

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Per-minute limit exceeded.",
    "details": { ... }
  }
}

The HTTP status code is the source of truth; code is a stable machine-readable identifier you can switch on.

Status code map

StatusMeaningRetry?
400Bad request (malformed body, missing field)No — fix client.
401Missing / invalid API keyNo.
403Authenticated but lacking scopeNo.
404Resource not found, or not in your orgNo.
409Duplicate resource / version conflictNo (or after refetching).
422Validation failedNo — inspect details.
425Too early (key not active yet)After expires_at.
429Rate limit exceededYes, honour Retry-After.
500Server errorYes, with backoff.
502/503/504Upstream unavailableYes, with backoff.

The SDKs retry the "Yes" rows automatically (max_retries=5 by default, exponential backoff with jitter, capped at 8 s).

Error codes

codeMeaning
unauthorizedAPI key missing or wrong.
expired_api_keyKey past expires_at.
insufficient_scopeKey lacks the scope this endpoint requires.
unsupported_formatUploaded file is not an image or PDF.
file_too_large>15 MB.
low_confidenceExtraction succeeded but confidence under threshold.
rate_limit_exceededSee retry_after.
quota_exhaustedMonthly plan quota fully consumed (HTTP 402).
idempotency_conflictSame Idempotency-Key reused with different body.
validation_errorRequest body failed validation; see details.
server_errorGeneric 5xx — already retried.

Request IDs

Every response (success or error) carries X-Request-Id. Forward it to support — we can pull the full trace from logs in under 30 s.

Programmatic handling

from oligon_receipts import RateLimitError, AuthError, ValidationError
 
try:
    client.extract(file=path)
except RateLimitError as e:
    print("slow down:", e.retry_after)
except AuthError:
    rotate_key()
except ValidationError as e:
    print("server says:", e.body["error"]["details"])