Document Flow webhooks
Webhooks let you receive information about process starts, recipient activity, document confirmation and sealing without polling the Document Flow API.
Contents
- Configuration
- Headers and signature
- Example payload
- Event types
- Cancellation, rejection and expiry
- Duplicates and retries
- Best practices
Configuration
An account administrator configures webhooks in the Document Flow module settings in the SARE panel.
- Provide a publicly accessible HTTPS URL that accepts
POSTrequests. - Select the event types you want to receive.
- Save the settings and test the webhook.
- Use the secret from module settings to verify signatures on the receiving server.
The configuration applies to the account. The webhook URL, secret and event list are not passed when creating a process through the API. Delivery is not queued if no URL or matching event type is configured.
The test sends a webhook.test event with event, eventId, occurredAt, source: "aurora.doc-flow", account and details fields. The account object contains tenantId and integrationKey, while details.message describes the test. The test has no process object and makes a single delivery attempt.
Headers and signature
| Header | Meaning |
|---|---|
Content-Type | application/json |
X-Confirmation-Event | Event type matching event in the payload |
X-Confirmation-Id | Event ID matching eventId in the payload |
X-Confirmation-Signature | Signature in sha256=<hex HMAC-SHA256> format, included when a secret is available |
The signature covers the exact JSON content sent in the request. Verify it using the raw body bytes before the JSON parser converts them into an object. Serializing the object again can change field order or formatting and invalidate the signature.
Node.js example:
import { createHmac, timingSafeEqual } from 'node:crypto'
function verifyWebhook(rawBody, signature, secret) {
if (!Buffer.isBuffer(rawBody) || typeof signature !== 'string') {
return false
}
const match = /^sha256=([a-f0-9]{64})$/.exec(signature)
if (!match) {
return false
}
const expected = createHmac('sha256', secret).update(rawBody).digest()
const received = Buffer.from(match[1], 'hex')
return received.length === expected.length && timingSafeEqual(received, expected)
}
const signature = request.headers['x-confirmation-signature']
if (!verifyWebhook(rawBody, signature, webhookSecret)) {
throw new Error('Invalid webhook signature')
}
const payload = JSON.parse(rawBody.toString('utf8'))Here, rawBody is a Buffer containing the original request body, and webhookSecret is the secret from module settings. Configure your server to preserve the raw body before parsing JSON.
Example payload
A step.confirmed event:
{
"event": "step.confirmed",
"eventId": "dfw_t1_k8V4wN7xP2mQ6rS9aB3c",
"occurredAt": "2026-10-19T10:15:00.000Z",
"process": {
"id": "dfp_t1_n7K2vP4qR8sT6wX9aB3c",
"referenceId": "REF-2026-0001",
"externalId": "case-2026-0001",
"documentId": "dfd_t1_m3N8pQ2rS6tV4wX9aB7c",
"sender": {
"name": "Customer service",
"email": "dokumenty@example.com",
"replyTo": "dokumenty@example.com"
}
},
"details": {
"stepKey": "step_1",
"actor": "recipient",
"confirmedAt": "2026-10-19T10:15:00.000Z",
"ip": "192.0.2.10",
"userAgent": "Mozilla/5.0",
"latestArtifactVersion": 2,
"latestArtifactKind": "artifact",
"fileAccessMode": "pin",
"approvalMode": "button_only",
"processStatus": "in_progress",
"recipientEmail": "jan@example.com"
}
}| Field | Meaning |
|---|---|
event | Event type |
eventId | Event ID, also used for retries |
occurredAt | Webhook event creation time in ISO 8601 format |
process.id | Process ID used in the API |
process.referenceId | Process reference number |
process.externalId | Identifier in the integrator's system or null |
process.documentId | Process document ID |
process.sender | Message sender: name, email, replyTo; may be null for older processes |
details | Details specific to the event type |
If an event identifies a step through stepKey, details.recipientEmail contains that recipient's email address when available. ip and userAgent may be null. Handwritten signature data in signatureDataUrl is not included in webhooks.
For step.confirmed, fileAccessMode and approvalMode describe the access and approval methods. The payload does not include the confirmationMethod or sourceIp fields shown in older documentation.
For a process belonging to a bulk send, details.campaign includes additional context: id, name, recipientId, executionId, documentUploadId, emailSubject, emailPreheader, scheduledAt, startedAt, expiresAt, fileAccessMode, approvalMode, pinDeliveryChannel, pinFallbackToEmail, includeSignatureCard, sealingEnabled and eurocertSealId. Some of these values may be null.
Event types
The following types can be selected in module settings:
| Event type | Meaning |
|---|---|
process.created | Process created; see the emission note below |
process.started | Process started with recipients |
email.sent | Email queued for sending, e.g. an access link or PIN |
sms.sent | SMS submitted for sending |
sms.delivered | Emitted after a successful SMS sending call; see the delivery note below |
step.email_sent | Access link message queued for a step |
step.opened | Step opened through the recipient link |
step.viewed | Document view recorded |
step.confirmed | Step approved according to its mode |
step.signed | Handwritten signature added in a step |
process.cancelled | Process withdrawn, rejected by a recipient or expired |
artifact.sealing_started | Final document sealing started |
artifact.sealed | Sealed document version created |
artifact.sealing_failed | Document sealing failed |
process.completed | All process steps completed |
Warning
process.created is available in settings, but the current process creation path records it only in process history. Select process.started to receive flow start notifications. Saving a draft without recipients does not trigger that event.
email.sent and step.email_sent do not confirm delivery to the recipient's inbox. They may describe the same queue operation under different names, with separate eventId values. sms.delivered is currently emitted immediately after a successful SMS sending operation and is not an independent delivery report from the handset.
process.completed does not guarantee successful sealing. Its details include completedAt, latestArtifactVersion, latestArtifactKind, latestSealedVersion, latestSealedKind and processStatus. If no sealed version has been created, latestSealedVersion and latestSealedKind are null. Also check artifact.sealed or artifact.sealing_failed to determine the sealing outcome.
Process history also includes process.paused, process.resumed, email.accepted, email.failed, step.pin_verified, password.requested and password.delivered. These types cannot be selected in webhook configuration. Do not expect them as webhook notifications.
Cancellation, rejection and expiry
All these scenarios use the process.cancelled event. Distinguish them using details:
| Scenario | Distinctive details fields |
|---|---|
| Operator withdrawal | processStatus: "cancelled" and reason, which may be null |
| Recipient rejection | actor: "recipient", stepKey, stepStatus: "failed", rejectedAt, reason, ip, userAgent and recipient email |
expiresAt deadline reached | reason: "expired", completedAt and readUntil |
Example details for a rejected document:
{
"processStatus": "cancelled",
"stepKey": "step_1",
"stepStatus": "failed",
"actor": "recipient",
"rejectedAt": "2026-10-19T10:20:00.000Z",
"reason": "Please correct the data in the document.",
"ip": "192.0.2.10",
"userAgent": "Mozilla/5.0",
"recipientEmail": "jan@example.com"
}Duplicates and retries
Webhooks are sent as POST requests with a 30-second response timeout. The receiver should return a 2xx status after durably storing the event.
- Standard delivery makes up to 3 attempts in total: the initial attempt and 2 retries.
- Retries are scheduled 30 seconds, then 60 seconds after the failed attempt. Queue load may increase the wait.
- Connection errors, timeouts and HTTP error responses, including
4xx, are retried. - Retries preserve the
eventId, request body, destination URL and headers saved when the delivery was created. - An administrator can review delivery history and manually retry delivery in the SARE panel.
- Webhook delivery history is retained for 30 days after the record is created. Retries do not extend this period.
The same event may be delivered more than once. Store processed eventId values and return 2xx for correctly signed duplicates without repeating the business operation. Do not rely on webhook delivery order.
Best practices
- Verify the signature against the raw body before processing business data.
- Store
eventId,eventandprocess.idto associate events with processes and detect duplicates. - After durably storing the webhook, process longer tasks asynchronously.
- Handle missing optional fields,
nullvalues and new fields added to the payload. - Retrieve the current process state and the appropriate PDF version through the Document Flow API.