Developer API
API reference

Errors & limits

One error shape everywhere, a fixed set of codes, and clear limits. Every response carries a request_id — quote it and we can find your exact request in seconds.

Error envelope

Every error response has the same body:

Error body
{ "error": { "code": "...", "message": "...", "request_id": "..." } }

The same value is also on the X-Request-Id response header. Always log request_id when reporting an issue.

Error-code reference

codeHTTPMeaning
missing_api_key401No X-API-Key header sent.
invalid_api_key401Key unknown, revoked, or partner suspended.
invalid_file_type400Uploaded file isn't a PDF.
file_too_large413PDF exceeds the 50 MB limit.
empty_file400Uploaded file has zero bytes.
unsupported_price_list400price_list isn't a currently-loaded list. The message includes the supported set.
unsupported_output_format400output_formats contains something other than esx or json.
feature_not_enabled400Requested "json" output while it's disabled (current production state).
too_many_active_jobs429You already have 3 jobs queued/processing. Wait for one to finish.
daily_limit_exceeded429You've hit 200 conversions today.
not_found404Job doesn't exist, or belongs to another partner.
timeoutjob error.codeJob stuck in processing past 20 minutes; force-failed.
unsupported_estimatejob error.codePDF parsed to zero line items — unsupported layout (abbreviated, rough-draft-only, XactView, statement-of-loss).
conversion_failedjob error.codeGeneric unexpected failure. Check error.message and quote job_id.

Codes marked "job error.code" appear inside a job's error object (from GET /v1/conversions/{id}), not as an HTTP status — the request itself succeeded, the conversion didn't.

Rate limits

Per API key:

  • 3 concurrent jobs (queued or processing). A 4th POST returns 429 too_many_active_jobs.
  • 200 conversions per day (UTC calendar day). Exceeding returns 429 daily_limit_exceeded.

Need different limits? Tell us about your integration.

Retention

  • Source PDFs and generated ESX files are retained 30 days from job completion, then deleted.
  • After that, GET /v1/conversions/{id} still returns the job record — summary stays available indefinitely — but esx_url is null and esx_expired is true. Download your ESX before the window closes if you need to keep it.

Idempotency

Pass Idempotency-Key: <your-key> on POST /v1/conversions. A second POST with the same key from the same partner, within the retention window, returns the same job_id instead of creating a new job or re-uploading the PDF. Use it to make retries after a network timeout safe.

Debugging with request_id

Every response under /v1/* — success or error — carries X-Request-Id, and error bodies repeat it inline as error.request_id. When something looks wrong, include that ID (and the job_id if you have one) in your report. It points straight to your request in our logs.

Also

The service exposes an interactive Swagger UI at /docs and the raw OpenAPI schema at /api/v1/openapi.json on the same host — handy for generating a typed client.