Reference · v1

InvoRec API

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

HTTPS https://api.invorec.com/v1

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. 1250 for €12.50).
  • Object IDs are type-prefixed: invoices inv_…, schemas sch_…, events evt_….
  • Collections return at most 100 items per page. See pagination.
Getting started

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.
Never embed live keys in frontend code. Proxy uploads through your backend and keep secrets server-side.
Getting started

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.

Getting started

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.

Free, Starter and Growth are dashboard-only. Upgrade to Business to issue API keys and call the API.

Every response carries the current quota state in X-RateLimit-* headers; a 429 includes Retry-After.

Getting started

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.

Getting started

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.

Getting started

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 code values.
Webhooks

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.
Webhooks

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.

Verify against the raw request body, not re-serialised JSON — pretty-printing changes the bytes and the signature won't match.
Webhooks

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 200 immediately) and process asynchronously.
  • Deduplicate by event id — it is stable across retries.
Webhooks

GET List webhooks

GET /v1/webhooks
Webhooks

POST Create webhook

POST /v1/webhooks

Parameters

url string · body optional

events array<string> · body optional

description string · body optional

Webhooks

GET Retrieve webhook

GET /v1/webhooks/{id}

Parameters

id string · path required

Webhooks

PATCH Update webhook

PATCH /v1/webhooks/{id}

Parameters

id string · path required

url any · body optional

events any · body optional

description any · body optional

enabled any · body optional

Webhooks

DEL Delete webhook

DEL /v1/webhooks/{id}

Parameters

id string · path required

Invoices

GET List invoices

GET /v1/invoices

Parameters

cursor string · query optional

limit int32 · query optional

status string · query optional

created_after string · query optional

created_before string · query optional

Invoices

POST Create invoice

POST /v1/invoices

Parameters

schema_id string · query optional

Idempotency-Key string · header optional

file binary · body required

Invoices

POST Reprocess invoice

POST /v1/invoices/{id}/reprocess

Parameters

id string · path required

Idempotency-Key string · header optional

Invoices

GET Retrieve invoice

GET /v1/invoices/{id}

Parameters

id string · path required

Invoices

PATCH Update invoice

PATCH /v1/invoices/{id}

Parameters

id string · path required

invoiceNumber any · body optional

invoiceDate any · body optional

dueDate any · body optional

vendorName any · body optional

vendorEmail any · body optional

vendorPhone any · body optional

vendorTaxId any · body optional

vendorAddress any · body optional

customerName any · body optional

customerEmail any · body optional

customerPhone any · body optional

customerTaxId any · body optional

customerAddress any · body optional

subtotalAmount any · body optional

taxAmount any · body optional

totalAmount any · body optional

taxRate any · body optional

discountAmount any · body optional

discountPercent any · body optional

currency any · body optional

paymentTerms any · body optional

paymentMethod any · body optional

paymentStatus any · body optional

notes any · body optional

customFields any · body optional

Invoices

DEL Delete invoice

DEL /v1/invoices/{id}

Parameters

id string · path required

Invoices

GET File invoice

GET /v1/invoices/{id}/file

Parameters

id string · path required

Schemas

GET List schemas

GET /v1/schemas
Schemas

GET Retrieve schema

GET /v1/schemas/{id}

Parameters

id string · path required

Credits

GET List credits

GET /v1/credits
# Available everywhere — no SDK required export INVOREC_KEY="invr_live_8a3f...c91" curl https://api.invorec.com/v1/invoices \ -H "Authorization: Bearer $INVOREC_KEY" \ -F "file=@invoice.pdf"
curl https://api.invorec.com/v1/invoices \ -H "Authorization: Bearer invr_live_8a3f...c91"
{ "error": { "code": "invalid_api_key", "message": "The provided key has been revoked." } }
{ "error": { "code": "unprocessable_invoice", "message": "The uploaded file is not a recognisable invoice.", "param": "file", "request_id": "req_01HFAB7Z5K8C4M2N7Y9P3R6V0X" } }
# 400 invalid_request_error # 401 authentication_required · invalid_api_key # 403 insufficient_scope # 404 resource_not_found # 409 idempotency_conflict # 422 unprocessable_invoice · file_too_large # 429 rate_limited # 500 internal_error · (always safe to retry)
HTTP/1.1 200 OK X-RateLimit-Limit: 60 X-RateLimit-Remaining: 42 X-RateLimit-Reset: 1716638460
HTTP/1.1 429 Too Many Requests Retry-After: 3 { "error": { "code": "rate_limited", "message": "Slow down — retry in 3s." } }
curl https://api.invorec.com/v1/invoices \ -H "Authorization: Bearer $INVOREC_KEY" \ -H "Idempotency-Key: req_2026_05_25_a1b2" \ -F "file=@invoice.pdf"
{ "id": "inv_01HFAB6ZQ3K7X9N2T4M5Y8R0PD", "status": "processing", "_meta": { "idempotent_replay": true } }
curl 'https://api.invorec.com/v1/invoices?limit=100' \ -H "Authorization: Bearer $INVOREC_KEY" # take next_cursor from the response, then: curl 'https://api.invorec.com/v1/invoices?cursor=eyJpZCI6...&limit=100' \ -H "Authorization: Bearer $INVOREC_KEY"
{ "object": "list", "data": [/* 100 invoices */], "has_more": true, "next_cursor": "eyJpZCI6Imludl8wMUhGQUI..." }
curl https://api.invorec.com/v1/invoices \ -H "Authorization: Bearer $INVOREC_KEY" \ -H "InvoRec-Version: 2026-04-08"
{ "id": "evt_01HFAB7Z5K8C4M2N7Y9P3R6V0X", "object": "event", "type": "invoice.succeeded", "created": 1716638400, "data": { /* full invoice object */ } }
import crypto from "node:crypto"; export function verifyWebhook(req, rawBody) { const [t, v1] = req.headers["invorec-signature"] .split(",").map(p => p.split("=")[1]); if (Math.abs(Date.now()/1000 - +t) > 300) throw new Error("timestamp drift"); const expected = crypto .createHmac("sha256", process.env.SECRET) .update(`${t}.${rawBody}`).digest("hex"); if (!crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(v1))) throw new Error("invalid signature"); }
app.post("/webhooks/invorec", async (req, res) => { res.json({ received: true }); // ack immediately if (await seen(req.body.id)) return; // dedupe await handle(req.body); });
curl https://api.invorec.com/v1/webhooks \ -H "Authorization: Bearer $INVOREC_KEY"
{ "data": [ { "id": "string", "url": "string", "events": [ "string" ], "description": "string", "enabled": true, "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z", "lastDeliveryAt": "2026-01-01T12:00:00Z", "lastDeliveryStatus": "string" } ], "nextCursor": "string" }
curl -X POST https://api.invorec.com/v1/webhooks \ -H "Authorization: Bearer $INVOREC_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "string", "events": [ "string" ], "description": "string" }'
{ "id": "string", "url": "string", "events": [ "string" ], "description": "string", "enabled": true, "secret": "string", "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z", "lastDeliveryAt": "2026-01-01T12:00:00Z", "lastDeliveryStatus": "string" }
curl https://api.invorec.com/v1/webhooks/{id} \ -H "Authorization: Bearer $INVOREC_KEY"
{ "id": "string", "url": "string", "events": [ "string" ], "description": "string", "enabled": true, "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z", "lastDeliveryAt": "2026-01-01T12:00:00Z", "lastDeliveryStatus": "string" }
curl -X PATCH https://api.invorec.com/v1/webhooks/{id} \ -H "Authorization: Bearer $INVOREC_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": { "present": true, "value": null }, "events": { "present": true, "value": null }, "description": { "present": true, "value": null }, "enabled": { "present": true, "value": null } }'
{ "id": "string", "url": "string", "events": [ "string" ], "description": "string", "enabled": true, "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z", "lastDeliveryAt": "2026-01-01T12:00:00Z", "lastDeliveryStatus": "string" }
curl -X DELETE https://api.invorec.com/v1/webhooks/{id} \ -H "Authorization: Bearer $INVOREC_KEY"
# empty body
curl https://api.invorec.com/v1/invoices?cursor=…&limit=…&status=…&created_after=…&created_before=… \ -H "Authorization: Bearer $INVOREC_KEY"
{ "data": [ { "id": "string", "status": "string", "invoiceNumber": "string", "vendorName": "string", "vendorEmail": "string", "vendorPhone": "string", "vendorTaxId": "string", "vendorAddress": "string", "customerName": "string", "customerEmail": "string", "customerPhone": "string", "customerTaxId": "string", "customerAddress": "string", "invoiceDate": "2026-01-01", "dueDate": "2026-01-01", "subtotalAmount": 0, "taxAmount": 0, "totalAmount": 0, "taxRate": 0, "discountAmount": 0, "discountPercent": 0, "currency": "string", "paymentTerms": "string", "paymentMethod": "string", "paymentStatus": "string", "notes": "string", "extractionConfidence": 0, "extractionSchemaId": "string", "extractionSchemaName": "string", "customFields": {}, "lineItems": [ { "description": "string", "quantity": 0, "unitPrice": 0, "totalPrice": 0, "taxRate": 0, "taxAmount": 0, "discountPercent": 0, "discountAmount": 0 } ], "error": { "message": "string" }, "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z" } ], "nextCursor": "string" }
curl -X POST https://api.invorec.com/v1/invoices?schema_id=… \ -H "Authorization: Bearer $INVOREC_KEY" \ -F "file=…"
{}
curl -X POST https://api.invorec.com/v1/invoices/{id}/reprocess \ -H "Authorization: Bearer $INVOREC_KEY" \ -H "Content-Type: application/json" \ -d '"string"'
{}
curl https://api.invorec.com/v1/invoices/{id} \ -H "Authorization: Bearer $INVOREC_KEY"
{ "id": "string", "status": "string", "invoiceNumber": "string", "vendorName": "string", "vendorEmail": "string", "vendorPhone": "string", "vendorTaxId": "string", "vendorAddress": "string", "customerName": "string", "customerEmail": "string", "customerPhone": "string", "customerTaxId": "string", "customerAddress": "string", "invoiceDate": "2026-01-01", "dueDate": "2026-01-01", "subtotalAmount": 0, "taxAmount": 0, "totalAmount": 0, "taxRate": 0, "discountAmount": 0, "discountPercent": 0, "currency": "string", "paymentTerms": "string", "paymentMethod": "string", "paymentStatus": "string", "notes": "string", "extractionConfidence": 0, "extractionSchemaId": "string", "extractionSchemaName": "string", "customFields": {}, "lineItems": [ { "description": "string", "quantity": 0, "unitPrice": 0, "totalPrice": 0, "taxRate": 0, "taxAmount": 0, "discountPercent": 0, "discountAmount": 0 } ], "error": { "message": "string" }, "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z" }
curl -X PATCH https://api.invorec.com/v1/invoices/{id} \ -H "Authorization: Bearer $INVOREC_KEY" \ -H "Content-Type: application/json" \ -d '{ "invoiceNumber": { "present": true, "value": null }, "invoiceDate": { "present": true, "value": null }, "dueDate": { "present": true, "value": null }, "vendorName": { "present": true, "value": null }, "vendorEmail": { "present": true, "value": null }, "vendorPhone": { "present": true, "value": null }, "vendorTaxId": { "present": true, "value": null }, "vendorAddress": { "present": true, "value": null }, "customerName": { "present": true, "value": null }, "customerEmail": { "present": true, "value": null }, "customerPhone": { "present": true, "value": null }, "customerTaxId": { "present": true, "value": null }, "customerAddress": { "present": true, "value": null }, "subtotalAmount": { "present": true, "value": null }, "taxAmount": { "present": true, "value": null }, "totalAmount": { "present": true, "value": null }, "taxRate": { "present": true, "value": null }, "discountAmount": { "present": true, "value": null }, "discountPercent": { "present": true, "value": null }, "currency": { "present": true, "value": null }, "paymentTerms": { "present": true, "value": null }, "paymentMethod": { "present": true, "value": null }, "paymentStatus": { "present": true, "value": null }, "notes": { "present": true, "value": null }, "customFields": { "present": true, "value": null } }'
{ "id": "string", "status": "string", "invoiceNumber": "string", "vendorName": "string", "vendorEmail": "string", "vendorPhone": "string", "vendorTaxId": "string", "vendorAddress": "string", "customerName": "string", "customerEmail": "string", "customerPhone": "string", "customerTaxId": "string", "customerAddress": "string", "invoiceDate": "2026-01-01", "dueDate": "2026-01-01", "subtotalAmount": 0, "taxAmount": 0, "totalAmount": 0, "taxRate": 0, "discountAmount": 0, "discountPercent": 0, "currency": "string", "paymentTerms": "string", "paymentMethod": "string", "paymentStatus": "string", "notes": "string", "extractionConfidence": 0, "extractionSchemaId": "string", "extractionSchemaName": "string", "customFields": {}, "lineItems": [ { "description": "string", "quantity": 0, "unitPrice": 0, "totalPrice": 0, "taxRate": 0, "taxAmount": 0, "discountPercent": 0, "discountAmount": 0 } ], "error": { "message": "string" }, "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z" }
curl -X DELETE https://api.invorec.com/v1/invoices/{id} \ -H "Authorization: Bearer $INVOREC_KEY"
# empty body
curl https://api.invorec.com/v1/invoices/{id}/file \ -H "Authorization: Bearer $INVOREC_KEY"
# empty body
curl https://api.invorec.com/v1/schemas \ -H "Authorization: Bearer $INVOREC_KEY"
{ "data": [ { "id": "string", "name": "string", "description": "string", "isDefault": true, "definition": {}, "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z" } ], "nextCursor": "string" }
curl https://api.invorec.com/v1/schemas/{id} \ -H "Authorization: Bearer $INVOREC_KEY"
{ "id": "string", "name": "string", "description": "string", "isDefault": true, "definition": {}, "createdAt": "2026-01-01T12:00:00Z", "updatedAt": "2026-01-01T12:00:00Z" }
curl https://api.invorec.com/v1/credits \ -H "Authorization: Bearer $INVOREC_KEY"
{ "subscription": 0, "topUp": 0, "remaining": 0, "planMonthlyAllotment": 0, "plan": "string" }