Skip to main content

Webhooks

Webhooks push real-time events to your endpoint — a new transaction, a completed extraction, a viewed disclosure — so you can react instead of polling. Send them to Zapier, Slack, your own service, or any HTTPS URL.

You can manage webhook subscriptions two ways:

  • In DocJacketSettings → Connections (create, edit, view delivery stats).
  • Via the API — with your mcp_at_ key, for fully programmatic setup.

Manage subscriptions with the API

# List the event types you can subscribe to
curl https://api.docjacket.com/api/v1/webhook-events \
-H "Authorization: Bearer mcp_at_YOUR_KEY"

# Create a subscription (requires the `actions` scope)
curl -X POST https://api.docjacket.com/api/v1/webhooks \
-H "Authorization: Bearer mcp_at_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Ops Slack relay",
"url": "https://example.com/hooks/docjacket",
"events": ["extraction.completed", "task.completed"]
}'

The create response includes the signing secret in full, exactly once — store it; you'll need it to verify signatures. Later reads only show a masked prefix. Other operations:

MethodPathScopePurpose
GET/api/v1/webhooksreadList your subscriptions
GET/api/v1/webhooks/{id}readGet one subscription
POST/api/v1/webhooksactionsCreate a subscription
PUT/api/v1/webhooks/{id}actionsUpdate url / events / active
DELETE/api/v1/webhooks/{id}actionsDelete a subscription
POST/api/v1/webhooks/{id}/testactionsFire a test delivery now
POST/api/v1/webhooks/{id}/regenerate-secretactionsRotate the signing secret
GET/api/v1/webhooks/{id}/deliveriesreadRecent delivery attempts
GET/api/v1/webhook-eventsreadThe event catalog

Subscribe to "*" to receive every event type.

Event catalog

EventFires when
transaction.createdA new transaction is created
transaction.status_changedA transaction's status changes
transaction.closedA transaction is closed
document.uploadedA document is uploaded to a transaction
document.deletedA document is deleted
task.createdA new task is created
task.completedA task is marked complete
extraction.completedA document extraction job finishes (includes jobId, status, confidence)
key_date.updatedA key date is added or changed
key_date.completedA key date is marked complete
contact.createdA new contact is created
disclosure.recipient_viewedA disclosure-package recipient opens the disclosure
form.submission_receivedA public form submission arrives

extraction.completed turns a document upload into a round-trip: subscribe, upload via the API, and receive the signed callback with the jobId and confidence when extraction finishes — no polling.

Payload

Every delivery is a POST with a JSON body in this envelope:

{
"eventType": "extraction.completed",
"eventId": "b1c2…",
"timestamp": "2026-07-04T13:00:00Z",
"organizationId": "org-…",
"userId": null,
"data": {
"jobId": "…",
"transactionId": "…",
"documentId": "…",
"status": "completed",
"confidence": 0.98,
"requiresReview": false
}
}

Payloads are thin — they carry IDs and a few key fields. Fetch the full resource from the REST API using the IDs when you need more. Fields may be added over time; ignore ones you don't recognize.

Each request also carries these headers:

HeaderValue
X-Webhook-Signaturesha256=<hmac-hex> — see below
X-Webhook-Event-Typee.g. extraction.completed
X-Webhook-Event-IdUnique per delivery attempt
X-Webhook-TimestampISO 8601 send time

Verify the signature

DocJacket signs every payload with HMAC-SHA256 using your subscription's secret. Always verify before trusting a delivery — compute the HMAC of the raw request body and compare it to the X-Webhook-Signature header.

// Node.js (Express) — use the RAW body, not the parsed JSON
import crypto from 'crypto';

function verify(rawBody, signatureHeader, secret) {
const expected =
'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(signatureHeader);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post('/hooks/docjacket',
express.raw({ type: 'application/json' }),
(req, res) => {
if (!verify(req.body, req.get('X-Webhook-Signature'), process.env.DJ_WEBHOOK_SECRET)) {
return res.status(401).end();
}
const event = JSON.parse(req.body);
// …handle event.eventType / event.data…
res.status(200).end();
});
# Python (Flask)
import hmac, hashlib

def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header or "")

Return a 2xx quickly (do heavy work asynchronously). Any non-2xx — or a timeout — counts as a failed delivery.

Retries, circuit breaker & delivery history

  • Retries — failed deliveries retry with backoff.
  • Circuit breaker — if an endpoint fails repeatedly, DocJacket automatically pauses it to avoid flooding a down service. Re-enable it (and reset the breaker) once you've fixed the endpoint.
  • Delivery historyGET /api/v1/webhooks/{id}/deliveries (or the Connections page) shows recent attempts with status codes, latency, errors, and the next retry time, so you can self-debug.

Test it

Fire a test delivery to confirm your endpoint and signature check work before going live:

curl -X POST https://api.docjacket.com/api/v1/webhooks/SUBSCRIPTION_ID/test \
-H "Authorization: Bearer mcp_at_YOUR_KEY"