InvoRec API
Last updated
Invoice parsing, programmatically. A REST API for turning invoice PDFs and images into structured data — JSON in, JSON out, async by default, with signed webhooks for delivery.
Base URL
Every request must be made over HTTPS and authenticated with a bearer token. Browse the topics and endpoints in the sidebar; request and response examples appear on the right.
Conventions
- All timestamps are integer Unix seconds (UTC).
- Monetary amounts are integers in the smallest currency unit (e.g.
1250for €12.50). - Object IDs are type-prefixed: invoices
inv_…, schemassch_…, eventsevt_…. - Collections return at most
100items per page. See pagination.
Authentication
Authenticate every request with a bearer token issued from the dashboard. Treat live keys like passwords.
Provide the key in the Authorization header. Keys come in two flavors:
invr_live_…— production traffic against real data.invr_test_…— sandboxed traffic. Same surface, fixtures only, never billed.
Errors
InvoRec uses conventional HTTP status codes. Every error returns a JSON body
with a stable code string and a human-readable message.
Branch on code — it is stable across versions. The message is for
humans and may change.
Rate limits
API access requires the Business plan. Default limits are 60 requests/minute and 1,000 invoice uploads/hour per workspace, enforced per-key and per-IP.
Every response carries the current quota state in X-RateLimit-* headers; a
429 includes Retry-After.
Idempotency
All mutating endpoints accept an Idempotency-Key header. Replays
return the original response within a 24-hour window — safe to retry on timeout.
Choose a unique string per logical operation (UUIDs work well). Reusing the same key with a
different body returns 409 idempotency_conflict.
Pagination
List endpoints return cursor-paginated results. Cursors are opaque tokens; never construct them by hand.
Pass limit (default 25, max 100) and the
cursor from the previous response. Every list response includes
has_more and next_cursor.
Versioning
The current stable surface is v1. Versions are dated; the version
is part of the URL and backwards-incompatible changes ship as a new dated version.
Pin your client to a known version. The header InvoRec-Version: 2026-04-08
overrides the workspace default per request.
Non-breaking changes
- Adding new endpoints, fields, enum values or optional parameters.
- Adding new event types and new error
codevalues.
Webhooks overview
InvoRec delivers asynchronous results by POSTing signed JSON to your endpoints. Use this in place of polling.
- At-least-once. Endpoints must be idempotent — the same
evt_…can arrive twice. - Retries. Transient failures are retried with exponential backoff for up to 24 hours.
- Order. Events for the same invoice are delivered in order; across invoices they may interleave.
Event types
invoice.processedinvoice.failed
Signature verification
Every webhook carries an InvoRec-Signature header. Verify it
before trusting the body — anyone can POST to your URL.
The header has two comma-separated values: t=<unix_seconds> and
v1=<hex>, an HMAC-SHA256 of "<t>.<raw_body>" keyed
with your endpoint secret. Reject timestamps drifting more than ±300 seconds.
Retry policy
A delivery succeeds on any 2xx within 15 seconds. Failures retry
on exponential backoff; persistent failures disable the endpoint.
- Backoff schedule: 1m, 5m, 15m, 1h, 6h, 24h, then stop.
- Acknowledge fast (return
200immediately) and process asynchronously. - Deduplicate by event
id— it is stable across retries.
GET List webhook endpoints
Returns all of the organization's webhook endpoints. Secrets are never included.
POST Create a webhook endpoint
Registers an HTTPS endpoint for the given `events`. The response includes the signing `secret` (`whsec_...`) exactly once - capture it now; it cannot be retrieved later.
POST Send a test event
Fires a synthetic `invoice.processed` event at the endpoint's URL with a fixed sample payload (invoice `inv_test_...`, "Test Vendor", $100.00, dated 2026-01-01 - not a real invoice) and returns the raw delivery outcome. Always 200: a non-2xx, unreachable, or SSRF-blocked target surfaces as `success:false`, not an API error. Works on disabled / auto-disabled endpoints (the point is to verify a URL before re-enabling). Persists no delivery row and schedules no retry.
Parameters
id string · path required | Webhook endpoint id (`whk_<32hex>`). |
POST Rotate the signing secret
Generates a new `whsec_` secret and returns it exactly once. The previous secret stops signing immediately, so existing handlers will fail verification until updated.
Parameters
id string · path required | Webhook endpoint id (`whk_<32hex>`). |
GET Get a webhook endpoint
Returns a single endpoint by id. No secret.
Parameters
id string · path required | Webhook endpoint id (`whk_<32hex>`). |
PATCH Update a webhook endpoint
Partial update (tri-state: omit = unchanged, value = set). Flipping `enabled` from false to true clears `auto_disabled` atomically, re-arming a disabled endpoint.
Parameters
id string · path required | Webhook endpoint id (`whk_<32hex>`). |
DEL Delete a webhook endpoint
Soft-deletes the endpoint. Returns 204.
Parameters
id string · path required | Webhook endpoint id (`whk_<32hex>`). |
GET List invoices
Lists invoices newest-first with cursor pagination. Follow `next_cursor` (null when no more pages) to page forward.
Parameters
cursor string · query optional | Opaque pagination cursor (base64url). Pass back the `next_cursor` from the previous page verbatim; do not construct or parse it. |
limit int32 · query optional | Page size, 1-100 (default 25). |
status enum · query optional | Filter by status. |
created_after string · query optional | Only invoices created at/after this ISO-8601 timestamp. |
created_before string · query optional | Only invoices created at/before this ISO-8601 timestamp. |
POST Upload an invoice
Uploads a document (PDF/PNG/JPEG, max 25MB) for asynchronous processing and returns 202 with the invoice in `processing` status; poll the invoice or subscribe to the `invoice.processed` webhook for completion. **Idempotency** (optional `Idempotency-Key` header): keys are retained 24 hours and only 2xx responses are cached. Replaying the same key with the same body returns the cached response; the same key with a different body returns 409 `idempotency_conflict`. Replays still consume a rate-limit slot. Note: a replayed response is numerically equivalent but NOT byte-for-byte identical (decimal scale is not preserved), so compare fields, not raw bytes. `schema_id` (optional form field) selects a custom extraction schema by its `sch_<32hex>` id; omit it to use the organization's default schema.
Parameters
Idempotency-Key string · header optional | Optional idempotency key. 24h TTL, 2xx-only caching. Same key + different body returns 409. |
POST Reprocess an invoice
Re-runs extraction on an existing invoice, optionally with a different schema (`{"schema_id": "sch_..."}` body). Returns 202; the invoice returns to `processing`. The invoice **id is stable** across reprocess - always reference an invoice by id. Its `created_at` may shift slightly when the underlying row is recreated on completion, so never key off timestamps. Honours the same `Idempotency-Key` semantics as upload.
Parameters
id string · path required | Invoice id (`inv_<32hex>`). |
Idempotency-Key string · header optional | Optional idempotency key. 24h TTL, 2xx-only caching. Same key + different body returns 409. |
GET Get an invoice
Returns a single invoice by id.
Parameters
id string · path required | Invoice id (`inv_<32hex>`). |
PATCH Correct invoice fields
Partially updates extracted fields. Tri-state JSON merge: omit a key to leave it unchanged, send `null` to clear it, send a value to set it. Line items are not editable here.
Parameters
id string · path required | Invoice id (`inv_<32hex>`). |
DEL Delete an invoice
Soft-deletes an invoice. Returns 204.
Parameters
id string · path required | Invoice id (`inv_<32hex>`). |
GET Download the original file
Returns a 302 redirect to a short-lived presigned URL for the original uploaded document. The URL expires after 5 minutes; do not cache it.
Parameters
id string · path required | Invoice id (`inv_<32hex>`). |
GET List extraction schemas
Returns all active extraction schemas for the organization in a single page (count is plan-bounded, so `next_cursor` is always null).
GET Get an extraction schema
Returns a single schema by id.
Parameters
id string · path required | Schema id (`sch_<32hex>`). |
GET Get credit balance
Returns the organization's current credit balance: subscription credits, top-up credits, and their total. The same `remaining` value is echoed on every API response via the `X-Credits-Remaining` header.