Parseo

Webhooks Overview

Subscribe to real-time invoice events delivered directly to your server.

Overview

Parseo delivers webhook events to your HTTPS endpoints when invoices are processed, updated, or deleted. This eliminates the need to poll GET /invoices/:id.

Events

Event typeFired when
invoice.processedOCR succeeds and an invoice is materialised
invoice.failedProcessing terminates without producing an invoice, or a reprocess run fails on an existing invoice
invoice.updatedA team member edits an invoice field in the Parseo UI
invoice.deletedA team member deletes an invoice in the Parseo UI

invoice.deleted only fires for deletions performed via the Parseo web UI. The API does not expose DELETE /invoices/:id in v1, so this event will not fire for API-initiated deletions.

Payload shapes

All events share the same envelope. data has one of two shapes depending on whether the invoice was materialised:

Invoice-shaped data.invoice (invoice.processed, invoice.updated, invoice.deleted, reprocess-failure invoice.failed)

{
  "id": "evt_7G6f5E4d3C2b1A0z",
  "type": "invoice.processed",
  "apiVersion": "2026-04-01",
  "createdAt": "2026-04-14T12:34:56.789Z",
  "data": {
    "invoice": { ... }
  }
}

data.invoice is the full invoice DTO, identical to the response from GET /invoices/:id. Partners can import directly from the webhook payload without a follow-up API call.

Job-shaped data.job (invoice.failed when OCR never produced an invoice)

{
  "id": "evt_7G6f5E4d3C2b1A0z",
  "type": "invoice.failed",
  "apiVersion": "2026-04-01",
  "createdAt": "2026-04-14T12:34:56.789Z",
  "data": {
    "job": {
      "id": "job_abc123",
      "status": "failed",
      "sourceFile": "invoice.pdf",
      "createdAt": "2026-04-14T12:34:50.000Z",
      "error": { "message": "OCR provider returned error 502" }
    }
  }
}

This shape is emitted when the processing pipeline failed before an invoice could be materialised — e.g. OCR provider outage, extraction timeout, payload rejected. There is no invoice to fetch. Your handler should check for data.job vs data.invoice to route accordingly:

if (event.data.invoice) {
  // OCR succeeded OR this is a reprocess-of-existing failure
  handleInvoiceEvent(event.data.invoice);
} else if (event.data.job) {
  // OCR never produced an invoice
  handleJobFailure(event.data.job);
}

Idempotency

Each event carries a unique id (evt_ prefixed). Parseo delivers events at-least-once — retries on failure may result in the same event being delivered more than once. Store the id and deduplicate on your side.

The same id is used across all retry attempts of the same delivery, so deduplicating on id protects against retry duplicates.

Payload size cap

When the full invoice DTO exceeds 1 MB, Parseo delivers a minimal envelope instead:

{
  "id": "evt_7G6f5E4d3C2b1A0z",
  "type": "invoice.processed",
  "apiVersion": "2026-04-01",
  "createdAt": "2026-04-14T12:34:56.789Z",
  "data": {
    "invoice": {
      "id": "inv_abc123",
      "status": "completed"
    }
  },
  "oversized": true
}

When oversized: true is present, fetch the full invoice via GET /invoices/:id.

Forward compatibility

Parseo may add new optional fields to any event payload at any time without bumping apiVersion. Your handler must tolerate unknown fields. Standard JSON parsers (JSON.parse in Node.js, json.loads in Python, encoding/json in Go) tolerate unknown fields by default.

apiVersion changes only when the payload structure changes in a backwards-incompatible way (field removed, renamed, or changes semantic meaning).

Delivery

  • Parseo attempts delivery up to 8 times with exponential backoff.
  • Your endpoint must return a 2xx status within 30 seconds.
  • Redirects (3xx) are treated as failures.
  • After 8 failed attempts, the event is marked dead_lettered.

Source filtering

Each webhook endpoint has an optional sourceFilter to limit which events it receives:

ValueReceives events from
"any" (default)All sources
"api"API-originated events only
"ui"UI-originated events only
{ "apiKeyId": "..." }A specific API key only

Managing endpoints

See the Webhooks API Reference for CRUD operations on webhook endpoints.

Endpoint limit

Each team may register up to 20 webhook endpoints.

Testing

Use POST /webhooks/:id/test to send a test invoice.processed event to your endpoint immediately. Rate limited to 10 test deliveries per hour per endpoint.

On this page