PerfectParser Docs

Webhooks Overview

Learn how to configure webhooks to receive real-time notifications when extractions finish.

A Webhook is an HTTP callback that PerfectParser triggers the moment your document extraction batch or single document completes processing. This removes the need to constantly poll batch status endpoints.


Configuring a Webhook

Dashboard (Integrations page)

  1. Navigate to your PerfectParser dashboard.
  2. Click Integrations in the left sidebar.
  3. Open the Webhooks tab and click Add Webhook.
  4. Fill in:
    • Target URL: Your server's HTTPS endpoint.
    • Scope: (Optional) Limit callbacks to a specific Parser. Leave blank for all parsers.
    • Custom Verification Header: (Optional) Static secret sent as X-Webhook-Secret. Useful for Zapier or Make.

Dashboard webhooks fire batch.* events when an extraction batch reaches a terminal state. Copy the auto-generated Signing Secret from the subscription card to verify HMAC signatures.

Programmatic API (POST /v1/webhooks)

Use the Create Webhook Endpoint when managing subscriptions from code. API webhooks subscribe to extraction.* events. An optional static secret is sent as X-Webhook-Secret; a signing_secret is returned once on create for HMAC verification.

After creating a webhook, call POST /v1/webhooks/:id/test to verify your endpoint receives and validates payloads before submitting real extractions.


Event Types

EventSourceWhen it fires
batch.completedIntegrations pageEntire batch finished successfully
batch.failedIntegrations pageEntire batch failed
batch.partialIntegrations pageBatch finished with mixed success/failure
extraction.document_completedPOST /v1/webhooksA single document reaches completed or failed
extraction.job_completedPOST /v1/webhooksAll documents in a batch finish processing

Webhook Verification

PerfectParser includes two validation headers in every callback request:

1. Static Secret Header (X-Webhook-Secret)

If you provide a static secret during webhook configuration (via customHeader in the dashboard or secret in POST /v1/webhooks), it will be sent verbatim in this header.

  • Best for: Simple, no-code integrations like Zapier or Make, where you can easily verify header values but cannot run HMAC cryptography.

2. HMAC Signature Header (X-PerfectParser-Signature)

PerfectParser computes a SHA-256 HMAC signature of the raw request payload using the webhook's private signing secret, sent in this header.

  • Best for: Custom web servers.
  • Note: Programmatic webhooks return signing_secret once on POST /v1/webhooks. Dashboard webhooks reveal the signing secret from Integrations → Webhooks. The optional static secret you pass in POST /v1/webhooks is sent as X-Webhook-Secret, not used for HMAC.

Webhook payloads include both extraction_id and document_id. If delivery fails, retry by calling GET /v1/extractions/:extraction_id/documents/:document_id.

See Verify Webhooks for timing-safe verification examples in Node.js and Python.


Webhook Payloads

PerfectParser sends an HTTP POST request to your URL. The JSON body depends on the subscribed event type.

Dashboard events (batch.*)

Triggered when an extraction batch reaches a terminal state. Fired once per batch completion.

batch.completed / batch.failed / batch.partial

{
  "event": "batch.completed",
  "timestamp": "2026-06-20T10:00:45.000Z",
  "data": {
    "batch_id": "ext_123",
    "batch_name": "June Invoices",
    "parser_id": "prs_999",
    "parser_name": "Invoice Parser",
    "status": "completed",
    "file_count": 2,
    "results": [
      {
        "document_id": "doc_abc",
        "filename": "invoice1.pdf",
        "status": "completed",
        "extracted_data": { "invoice_number": "INV-25", "total_amount": 450.00 },
        "confidence": 0.98,
        "error_message": null
      }
    ]
  }
}

API events (extraction.*)

Subscribed via POST /v1/webhooks. Use these when you need per-document callbacks or a single job-level summary from the public API.

extraction.document_completed

Triggered when a single document inside an extraction batch reaches a terminal success (completed) or failed (failed) state.

{
  "event": "extraction.document_completed",
  "timestamp": "2026-06-20T10:00:42.000Z",
  "data": {
    "document_id": "doc_abc",
    "extraction_id": "ext_123",
    "parser_id": "prs_999",
    "filename": "invoice.pdf",
    "status": "completed",
    "page_count": 3,
    "credits_used": 3,
    "extracted_data": {
      "invoice_number": "INV-2026-001",
      "total_amount": 1250.00
    },
    "error_message": null
  }
}

extraction.job_completed

Triggered when all documents inside a submitted extraction batch have completed processing.

{
  "event": "extraction.job_completed",
  "timestamp": "2026-06-20T10:00:45.000Z",
  "data": {
    "extraction_id": "ext_123",
    "parser_id": "prs_999",
    "parser_name": "Invoice Parser",
    "status": "completed",
    "file_count": 2,
    "total_pages": 7,
    "credits_used": 7,
    "documents": [
      {
        "document_id": "doc_abc",
        "filename": "invoice1.pdf",
        "status": "completed",
        "page_count": 3,
        "credits_used": 3,
        "extracted_data": {
          "invoice_number": "INV-25",
          "total_amount": 450.00
        },
        "error_message": null
      },
      {
        "document_id": "doc_xyz",
        "filename": "invoice2.pdf",
        "status": "completed",
        "page_count": 4,
        "credits_used": 4,
        "extracted_data": {
          "invoice_number": "INV-26",
          "total_amount": 800.00
        },
        "error_message": null
      }
    ]
  }
}

Timings, Retries, and Failures

  • Timeout: Webhook delivery requests time out after 10 seconds. Your server should respond with a 2xx status code immediately and process the payload asynchronously.
  • Retries: If delivery fails (returns a non-2xx code or times out), the log status becomes pending_retry. PerfectParser will retry up to 5 times using exponential backoff:
    • Retry 1: 5 minutes after initial failure
    • Retry 2: 10 minutes later
    • Retry 3: 20 minutes later
    • Retry 4: 40 minutes later
    • Retry 5: 80 minutes later