Developer Reference
Outbound Webhooks
Receive real-time signed HTTP POST notifications on your servers when asynchronous tasks, document extraction jobs, or system events conclude.
Overview & Registration
Webhooks allow your application to react instantaneously to completed jobs without constant HTTP polling. Webhooks can be registered either permanently per-organization via the API/Settings, or ephemerally per-job:
- Organization Webhook: Register with
POST /api/v1/webhooks(or Account Portal → Settings → Integrations). Accie returns a dedicated signing secret prefixed withwhsec_. - Per-Job Ephemeral Callback: Include
options: { "webhook_url": "https://api.your-domain.com/callbacks" }in the job creation request.
Headers & Security
Accie signs every webhook delivery using HMAC-SHA256 over the raw JSON payload bytes. Every webhook request includes the following headers:
| Header | Format | Description |
|---|---|---|
X-Accie-Signature | sha256=<hex> | HMAC-SHA256 signature calculated over the unparsed raw request body. |
X-Accie-Event | string | The event identifier (e.g. job.ready, job.failed). |
User-Agent | Accie-OCR-Webhooks/0.1 | Client identifier for Accie event dispatcher. |
Content-Type | application/json | Payload MIME type. |
Payload Structure
{
"id": "e4f80808-1123-4455-8899-aabbccddeeff",
"type": "job.ready",
"created_at": "2026-09-09T18:30:00Z",
"data": {
"job_id": "93a1e204-7f12-4c22-9df1-8e01b3456789",
"organization_id": "029b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"status": "ready",
"filename": "gst_tax_invoice_aug2026.pdf",
"page_count": 2,
"batch_id": null,
"error_message": null
}
}
HMAC Signature Verification Code
import hmac
import hashlib
from fastapi import FastAPI, Request, HTTPException, Header
app = FastAPI()
WEBHOOK_SECRET = "whsec_your_secret_here"
@app.post("/webhooks/accie/v1")
async def accie_webhook(request: Request, x_accie_signature: str = Header(...)):
raw_body = await request.body()
# Compute HMAC-SHA256 over raw body bytes
expected = "sha256=" + hmac.new(
WEBHOOK_SECRET.encode("utf-8"),
raw_body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, x_accie_signature):
raise HTTPException(status_code=401, detail="Invalid webhook signature")
event = await request.json()
job_id = event["data"]["job_id"]
status = event["data"]["status"]
print(f"Received webhook for job {job_id}: {status}")
return {"status": "accepted"}
const express = require('express');
const crypto = require('crypto');
const app = express();
const WEBHOOK_SECRET = process.env.ACCIE_WEBHOOK_SECRET;
// Use express.raw() to preserve unparsed body bytes for HMAC check
app.post('/webhooks/accie/v1', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-accie-signature'];
if (!signature) return res.status(401).send('Missing signature');
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
hmac.update(req.body);
const expected = 'sha256=' + hmac.digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
if (!valid) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body.toString('utf-8'));
console.log(`Webhook received for job: ${event.data.job_id}`);
res.status(200).json({ received: true });
});
Accie Extract Event Types
job.ready: Extraction, parsing, and tax reconciliation completed successfully. Results are ready to fetch or export.job.failed: Document could not be processed due to file corruption, unsupported encryption, or processing timeout.