Webhooks
Configure a destination URL once and receive a clean JSON payload every time a document or email is processed — the instant extraction completes.
How it works
When a parsing job completes, DocPeel sends an HTTP POST request to your configured endpoint with the extraction result as a JSON body. The payload includes the job ID, parser name, all extracted fields, per-field confidence scores, and an ISO 8601 timestamp.
This removes the need to poll the API for results and makes it straightforward to trigger actions in downstream systems the instant structured data is ready.
Example payload
A completed invoice extraction delivers a payload like this to your endpoint:
{
"event": "job.completed",
"job_id": "job_9f3a2b8c",
"parser": "invoice-parser",
"status": "completed",
"created_at": "2026-04-13T10:22:31.000Z",
"result": {
"invoice_number": "INV-2026-00441",
"vendor_name": "Acme Corp",
"total_amount": "$4,850.00",
"due_date": "2026-05-01"
},
"confidence": {
"invoice_number": 0.99,
"vendor_name": 0.97,
"total_amount": 0.98,
"due_date": 0.95
}
}Setting up your endpoint
Navigate to Integrations → Webhooks and add your destination URL. DocPeel sends a test event immediately so you can verify your endpoint is reachable before any live jobs run.
Your endpoint must respond with a 200 status within 10 seconds. Failed deliveries are retried up to three times with exponential backoff — after 30 s, 5 min, and 30 min.
Verifying signatures
Every request includes an X-DocPeel-Signature header — an HMAC-SHA256 digest of the raw request body computed using your webhook secret. Always verify this before processing any payload.
Never skip verification. Processing payloads without checking the signature leaves your endpoint open to spoofed requests. Your secret is available in Integrations → Webhooks and can be rotated at any time without downtime.
import hashlib
import hmac
import os
from flask import Flask, abort, request
app = Flask(__name__)
SECRET = os.environ["DOCPEEL_WEBHOOK_SECRET"]
# Convert secret to bytes once (recommended)
SECRET_BYTES = SECRET.encode("utf-8")
@app.post("/docpeel/webhook")
def receive():
sig = request.headers.get("X-DocPeel-Signature", "")
# Get raw body as bytes
raw = request.get_data()
# Fixed: pass SECRET_BYTES instead of SECRET
expected = "sha256=" + hmac.new(SECRET_BYTES, raw, hashlib.sha256).hexdigest()
# Constant-time comparison
if not hmac.compare_digest(sig, expected):
abort(401, "Invalid signature")
event = request.headers.get("X-DocPeel-Event")
payload = request.get_json()
if event == "extraction.completed":
filename = payload.get("fileName")
data = payload.get("extractedData", {}).get("data")
print(f"Extraction complete for {filename}")
print(" ")
print(f"Extracted data: {data}")
# TODO: process the extracted data
return {"ok": True}
if __name__ == "__main__":
app.run(port=5000, debug=True)Ready to ship?
Connect your first webhook in under two minutes. DocPeel handles extraction — you handle what happens next.