Your software runs the workflow — ESXPress turns insurance scopes into Xactimate ESX files. PDF uploads or structured XML (Xactimate's or any other system's), whatever your customers have. A real REST API, real webhooks, and real numbers: every endpoint and limit on this page is live in the code, not a roadmap.
Four building blocks, all live in the product today — no roadmap items, no vaporware.
6 endpoints · API-key auth
Upload one or more scope PDFs (up to 100 per request) or POST structured scope XML to /convert/structured (no OCR in the path) — then poll the conversion, download the validated ESX file, or fetch the original PDF back. Auth is a simple X-API-Key header or Bearer token.
conversion.completed · HMAC-signed
When a conversion finishes, ESXPress POSTs the result to your HTTPS endpoint. Up to 3 delivery attempts (5s / 15s / 45s backoff), an optional HMAC signature to verify the payload, and a delivery log you can replay.
Create · list · revoke
Keys are scoped to one account, revocable any time, and shown in full exactly once. Up to 10 active keys per account. Included from the 100 plan up — or the $49/mo API & Integrations add-on on the 25 and 75 plans.
Public · no key required
The API reference lives at /api/v1/docs — a styled page with every endpoint, request shape, and error code. You can read it before you sign up.
Three patterns software vendors actually wire up — each one mapped to real endpoints.
Send a whole job's scope PDFs in one request — up to 100 files. Each valid file is queued immediately and returns its own conversion ID; invalid files are reported in an errors list without aborting the batch.
Push the scope PDF with an optional carrier hint, then read back the extracted claim number, insured name, property address, and carrier from the status endpoint — the fields your workflow needs to file the job.
The status response carries every line item with its replacement cost (rcv), depreciation (dep), and ACV, plus totals — so your software can show or export the numbers before the ESX file is even downloaded.
Every number below is read from the code — including the things we don't have yet.
Rate limit
60 requests / minute / API key
Sliding window per key, Redis-backed. Over the limit returns HTTP 429.
File size
50 MB max per PDF
Checked before the file is buffered — oversized uploads are rejected with 413.
Batch size
100 PDFs max per request
More than 100 files returns 413. Partial batches are allowed: valid files queue, invalid ones land in errors[].
API keys per account
10 active keys
Full key shown exactly once, SHA-256 hashed at rest, revocable any time. At the cap, creating another returns 409.
Monthly conversion quota
25 / 75 / 100 / 250 / 500 / 1,000 / 2,500 by plan · custom quotes beyond
Quota is reserved per file at queue time — at the cap the API returns 402 with your used/limit before anything is queued.
Access
100 plan or above, or the $49/mo API & Integrations add-on
API keys and webhooks are gated from the 100 plan up; the add-on unlocks both on the 25 and 75 plans. Plans from the 100 tier up include them.
Webhook targets
HTTPS only, SSRF-guarded
Payloads contain claim PII, so cleartext http:// is rejected and internal/private addresses are blocked.
Webhook delivery
3 attempts · 5s / 15s / 45s backoff
Optional HMAC signature (X-Webhook-Signature) plus event headers so receivers can verify who sent the payload.
Docs
/api/v1/docs is public
No API key needed to read the reference. The raw OpenAPI schema is restricted to admin accounts — the docs page is the public contract.
Sandbox
None yet — and we're upfront about it
There is no separate sandbox environment in the codebase today. You develop against the same API: create a key, test with any carrier scope — a PDF upload (batch up to 100 files, 50MB each) or structured scope XML — and revoke the key when you're done.
Send a scope — PDF upload or structured XML — then poll and download. That's the whole flow; the same contract works from Python, Node, or any HTTP client.
Upload → status → download (curl)
# Preferred for accuracy: structured XML intake — scope XML (Xactimate's or any other system's), no OCR in the path.
# ?build=1 returns the finished .esx; poll and download by conversion_id like any job.
curl -X POST "https://esxpress.org/api/v1/public/convert/structured?build=1" \
-H "X-API-Key: esx_xx...xxx" \
-H "Content-Type: application/xml" \
--data-binary @scope.xml
# 1 · Upload a scope PDF (batch up to 100; 50MB each)
curl -X POST https://esxpress.org/api/v1/public/convert/upload \
-H "X-API-Key: esx_xx...xxx" \
-F "files=@scope.pdf" \
-F "carrier=StateFarm"
# → { "ok": true, "jobs": [{ "filename": "scope.pdf", "conversion_id": 42 }] }
# 2 · Poll until status is "ready"
curl -H "X-API-Key: esx_xx...xxx" \
https://esxpress.org/api/v1/public/convert/42/status
# 3 · Download the validated ESX file
curl -OJ -H "X-API-Key: esx_xx...xxx" \
https://esxpress.org/api/v1/public/convert/42/downloadErrors: 401 missing / invalid / revoked key · 400 bad file or payload · 413 too large · 402 plan quota reached (includes used/limit) · 404 conversion not found · 429 rate limit (60 req/min/key). Full reference: /api/v1/docs.
Software vendors: we'd rather answer questions than have you guess. Talk to us before you write the first request.