About Webhook Receiver Service
The Webhook Receiver Service allows your application to receive real-time notifications about envelope status changes from Sovos Signer.
When an envelope reaches a final state in Sovos Signer, the system sends a POST request to your configured webhook endpoint. This enables your application to respond immediately to envelope events without polling the API.
How it works
The webhook notification flow works as follows:
-
You configure a webhook URL in your Sovos Signer account.
-
An envelope in your account reaches a final status (completed, rejected, canceled, or expired).
-
Sovos Signer sends a POST request to your webhook URL with details about the envelope event.
-
Your application receives the notification and processes it.
-
Your endpoint returns a 200 status code to confirm receipt.
Prerequisites
Before you implement webhook receivers, ensure you have:
-
A publicly accessible HTTPS endpoint that can receive POST requests.
-
The ability to process JSON payloads.
-
A valid Sovos Signer account with webhook configuration access. Contact the Professional Services team for more details on activating this service.
Available endpoints
The Webhook Receiver Service provides the following endpoints that correspond to different envelope final states. All webhook endpoints use the POST method and accept JSON payloads. Your implementation must respond with an HTTP 200 status code to confirm successful receipt.
All webhook notifications share the same request structure and payload format. The only difference is the endpoint path, which indicates the envelope event type.
| Event | Method | Path | Description |
|---|---|---|---|
| Envelope completed | POST | /webhook-receiver/envelope/completed | Receives notifications when an envelope is successfully completed with all required signatures. |
| Envelope rejected | POST | /webhook-receiver/envelope/rejected | Receives notifications when a signer rejects an envelope. |
| Envelope canceled | POST | /webhook-receiver/envelope/cancelled | Receives notifications when an envelope is canceled by the creator or an authorized user. |
| Envelope expired | POST | /webhook-receiver/envelope/expired | Receives notifications when an envelope expires before completion. |
| Envelope unprocessable | POST | /webhook-receiver/envelope/unprocessable | Receives notifications when an envelope cannot be processed due to system errors or invalid configuration. |
Common request structure
- Request headers
- All webhook requests include the
Content-Type: application/jsonheader. - Response requirements
- Your webhook endpoint must:
-
Return an HTTP 200 status code to acknowledge successful receipt.
-
Respond within 30 seconds to avoid timeout.
-
Return an empty response body or a simple JSON object.
Important:If your endpoint returns a non-200 status code or times out, Sovos Signer will retry the notification using an exponential backoff strategy.
-
- Error responses
- If an error occurs during webhook delivery, Sovos Signer returns an error response with an HTTP error status code and a JSON body containing error details.
Webhook notification schema
All webhook notifications use the NotificationFinishedRequest payload structure, which includes envelope information, status details, and file attachments.
This example shows a completed envelope with one document file:
{
"initiative": "5b1aea4b-8e58-4050-91cc-d320ff5c41cf",
"envelopeId": "b16ea039-f2fe-4f8d-829a-d97698d367f1",
"status": "COMPLETED",
"reason": "All signers completed successfully",
"documentFiles": [
{
"name": "contrato_12345.pdf",
"mediaType": "application/pdf",
"content": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDQ5Nj4+c3RyZWFtCniclZTPb..."
}
],
"generatedFiles": [
{
"name": "audit_trail_12345.pdf",
"mediaType": "application/pdf",
"content": "JVBERi0xLjYKJeLjz9MKNSAwIG9iago8PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDYxOD4+c3RyZWFtCniclZbRc..."
}
]
}
Where:
| Field | Type | Required | Description |
|---|---|---|---|
initiative | string | Yes | Unique identifier for the initiative associated with the envelope. |
envelopeId | string | Yes | Unique identifier for the envelope. |
status | enum | Yes | Final status of the envelope. Possible values: COMPLETED, REJECTED, CANCELLED, EXPIRED, UNPROCESSABLE. |
reason | string | Yes | Explanation for the status change. |
documentFiles | array | Yes | List of processed document files included in the envelope. Each file contains name, mediaType, and content (Base64-encoded) of the file. |
generatedFiles | array | Yes | List of files generated by the system, such as audit trails. Each file contains name, mediaType, and content (Base64-encoded) of the file. |
- Rejected envelope
- When a signer rejects an envelope, the notification includes a specific reason. When an envelope is rejected, the
generatedFilesarray is typically empty because no signed documents are produced.{ "initiative": "5b1aea4b-8e58-4050-91cc-d320ff5c41cf", "envelopeId": "c27fb14a-a3gf-5g9e-93ab-e08709e478g2", "status": "REJECTED", "reason": "Signer declined: Terms not acceptable", "documentFiles": [], "generatedFiles": [] } - Cancelled envelope
- The notification includes information about why the cancellation occurred.
{ "initiative": "5b1aea4b-8e58-4050-91cc-d320ff5c41cf", "envelopeId": "d38gc25b-b4hg-6h0f-04bc-f19810f589h3", "status": "CANCELLED", "reason": "Cancelled by envelope creator: Contract terms changed", "documentFiles": [], "generatedFiles": [] } - Unprocessable envelope
- This notification indicates system-level issues that prevented completion.
{ "initiative": "5b1aea4b-8e58-4050-91cc-d320ff5c41cf", "envelopeId": "e49hd36c-c5ih-7i1g-15cd-g20921g690i4", "status": "UNPROCESSABLE", "reason": "System error: Unable to validate digital certificate", "documentFiles": [], "generatedFiles": [] }
Implementation example
This is a basic example of a webhook receiver in Node.js using Express:
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook-receiver/envelope/completed', async (req, res) => {
try {
const payload = req.body;
// Log the envelope completion
console.log(`Envelope completed: ${payload.envelopeId}`);
console.log(`Initiative: ${payload.initiative}`);
console.log(`Status: ${payload.status}`);
// Process document files
for (const file of payload.documentFiles) {
console.log(`Document: ${file.name} (${file.mediaType})`);
// Decode base64 content and save file
const buffer = Buffer.from(file.content, 'base64');
// Save buffer to storage...
}
// Process generated files (signed documents, audit trails)
for (const file of payload.generatedFiles) {
console.log(`Generated file: ${file.name} (${file.mediaType})`);
// Process generated files...
}
// Return 200 to acknowledge receipt
res.status(200);
} catch (error) {
console.error('Error processing webhook:', error);
res.status(500);
}
});
app.listen(3000, () => {
console.log('Webhook receiver listening on port 3000');
});
