Webhooks let Sadq automatically notify your server (via an HTTP POST) when envelope/signing events happen, instead of you having to poll the status endpoint.
All webhook endpoints require a Bearer token (Authorization: Bearer {token}, obtained from POST /Authentication/Authority/Token).
Base URLs:
- Sandbox:
https://sandbox-api.sadq-sa.com - Production:
https://api.sadq-sa.com
Note: all JSON field names below are camelCase (
webhookUrl,headerToken,isDefault, etc.) — this matches the live API, not PascalCase.
1. Create a webhook
POST /api/v1/webhooks
Authorization: Bearer {token}
Content-Type: application/json
Body:
| Field | Type | Required | Notes |
|---|---|---|---|
webhookUrl | string | ✅ | Your endpoint that will receive the callback |
headerToken | string | ❌ | If set, Sadq sends it back as the Authorization header on every callback to your URL |
isDefault | bool | ❌ (default false) | Marks this webhook as the account's default |
{
"webhookUrl": "https://example.com/webhook1",
"headerToken": "Bearer secret_token_12345",
"isDefault": true
}
Response:
{
"data": {
"id": "4ad46fc9-a3c4-442d-9c10-680213a76486",
"webhookUrl": "https://example.com/webhook1",
"accountId": "989f0e83-6913-4b7c-9ab1-109a3fbc4262",
"isDefault": true,
"headerToken": "Bearer secret_token_12345"
},
"errorCode": 0,
"message": null
}
Save the returned id — you'll need it if you ever want to target this specific webhook instead of the default one (see section 7).
Note on
headerToken: whatever value you put here, Sadq attaches it as theAuthorizationheader when it calls yourwebhookUrl. Use this to verify that the incoming callback genuinely came from Sadq.
2. Create multiple webhooks at once
POST /api/v1/webhooks/bulk
Authorization: Bearer {token}
Content-Type: application/json
Body: an array of the same object shape as section 1.
[
{ "webhookUrl": "https://app1.example.com/webhooks", "headerToken": "secret1", "isDefault": true },
{ "webhookUrl": "https://app2.example.com/webhooks", "headerToken": "secret2", "isDefault": false }
]
Returns: an array of the created webhook objects, in the same order.
3. List / get a webhook
List all webhooks on the account:
GET /api/v1/webhooks
Authorization: Bearer {token}
No body/params. Returns every webhook on the account, including which one has isDefault: true.
{
"data": [
{ "id": "4ad46fc9-...", "webhookUrl": "https://example.com/webhook1", "accountId": "989f0e83-...", "isDefault": true, "headerToken": "Bearer secret_token_12345" },
{ "id": "5be57gd0-...", "webhookUrl": "https://example.com/webhook2", "accountId": "989f0e83-...", "isDefault": false, "headerToken": "Bearer secret_token_67890" }
],
"errorCode": 0
}
Get a single webhook by ID:
GET /api/v1/webhooks/{id}
Authorization: Bearer {token}
4. Update a webhook
PUT /api/v1/webhooks
Authorization: Bearer {token}
Content-Type: application/json
Body:
| Field | Type | Required | Notes |
|---|---|---|---|
id | Guid | ✅ | Which webhook to update |
webhookUrl | string | ✅ | New target URL |
isDefault | bool | ✅ | New default status |
{
"id": "4ad46fc9-a3c4-442d-9c10-680213a76486",
"webhookUrl": "https://example.com/webhook-updated",
"isDefault": false
}
Note: this call doesn't let you change
headerToken— that's set when the webhook is created.
5. Delete a webhook
DELETE /api/v1/webhooks/{id}
Authorization: Bearer {token}
Once deleted, that webhook stops receiving callbacks. Any envelope still referencing its webhookId will fall back to the account default (if one exists).
6. The default webhook
You can create as many webhooks as you like, but only one webhook can actually be used as the default at a time.
- If you set
isDefault: trueon more than one webhook, Sadq does not call all of them — it picks and calls only one default webhook. - Whenever you initiate an envelope without explicitly specifying a webhook, Sadq falls back to this single default webhook.
So if you need multiple integrations listening for events, don't rely on multiple "default" webhooks — create separate (non-default) webhooks and target them explicitly per envelope instead, as shown next.
7. Calling a specific webhook (instead of the default)
If you don't want a particular envelope's events to go to the default webhook, pass that webhook's id as webhookId when you initiate the envelope. Sadq will then call that specific webhook for events on this envelope instead of the default one.
Supported on:
POST /api/v1/envelopes/initiatePOST /api/v1/envelopes/initiate-base64POST /api/v1/envelopes/initiate-by-templatePOST /api/v1/envelopes/bulk/initiate-base64
Example (initiate-base64):
{
"webhookId": "4ad46fc9-a3c4-442d-9c10-680213a76486",
"referenceNumber": "REF-2024-001",
"files": {
"fileId": "",
"file": "JVBERi0xLjQK...",
"fileName": "contract.pdf"
}
}
If webhookId is omitted, Sadq uses the account's default webhook (see section 6).
8. What you receive on your endpoint (the callback payload)
When an event fires, Sadq sends a POST to your webhookUrl with this JSON body:
{
"RequestId": "7bdc3c37-15e7-4c2b-9658-cd3c52c42457",
"Status": 1,
"Files": [
{ "FileName": "828f5487-ebe7-44fd-a2d7-1832a5ed5415.pdf", "File": "Base64File" }
],
"ReferencNumber": "Req-staging-2025-8266",
"Fields": [],
"Signatory": [
{
"Id": "5f7c322b-f2cf-460a-99e3-ad5becc96719",
"Status": "SIGNED",
"FullName": "Test New User",
"FullNameAr": "مستخدم جديد",
"NationalId": "2034485954",
"SignOrder": 0,
"Email": "test@sadq.sa",
"PhoneNumber": "",
"AuthenticationType": "WITHOUTVALIDATION",
"Gender": "MALE",
"Nationlity": "",
"RejectReason": null
}
]
}
Key fields: RequestId (the envelope/request ID — use this for recall and logs lookups), Status (envelope status code), Files (signed file(s), base64-encoded), Signatory (per-signer status, name, contact info, auth type, rejection reason if any).
Your endpoint should check the Authorization header against the headerToken you configured to confirm the call genuinely came from Sadq, then respond with a 2xx status.
9. Retry a failed delivery (recall)
If a delivery to your endpoint failed (server down, timeout, non-2xx response, etc.), you can ask Sadq to resend it instead of re-triggering the whole envelope:
POST /api/v1/webhooks/recall
Authorization: Bearer {token}
Content-Type: application/json
Body:
| Field | Type | Required | Notes |
|---|---|---|---|
requestId | Guid | ✅ | The request/envelope ID to trigger the webhook for — this is the RequestId from the callback payload, not a webhook's own id |
{ "requestId": "7bdc3c37-15e7-4c2b-9658-cd3c52c42457" }
10. Get webhook delivery logs
Use this to troubleshoot — see what was sent, what came back, and whether the delivery succeeded or failed.
GET /api/v1/webhooks/logs
Authorization: Bearer {token}
Content-Type: application/json
This is a GET request but, per the live docs, it takes its filters in a JSON body (not query string):
| Field | Type | Required | Notes |
|---|---|---|---|
requestId | string | ❌ | Filter logs by request ID |
webhookUrl | string | ❌ | Filter logs by your webhook URL |
webhookStatus | integer | ❌ | Filter by delivery status |
{
"requestId": "",
"webhookUrl": "",
"webhookStatus": null
}
Response:
{
"data": [
{
"requestId": "D019910D-8831-481F-B491-0D09F9443D8D",
"createdDate": "2026-01-04T11:22:19.993",
"webhookStatus": "FAILEDFROMCLIENT (4)",
"httpStatusCode": 404,
"webhookUrl": "https://webhook.site/0e69f910-6c36-487a-aa09",
"reasons": ""
}
],
"errorCode": 0
}
Each log entry tells you the event's requestId, when it was sent, the resulting webhookStatus, the HTTP status your server returned, and any failure reasons. If a delivery shows as failed, grab its requestId and call recall (section 9) to retry it.
11. Doing all of this from the Sadq portal
Everything above is also available without writing code, directly in the Sadq web portal, under your account/integration settings:
- Create a webhook — open the Webhooks section, click "Add Webhook," enter the target URL and (optionally) a header token, and choose whether it should be the default. The portal calls the same
POST /api/v1/webhooksendpoint under the hood. - Test a webhook — the portal lets you send a test event to your URL so you can confirm your endpoint is reachable and correctly validates the
Authorizationheader, before you wire it into a real envelope flow. - View logs — the Webhooks section shows a logs/activity tab listing every delivery attempt (event, status, response time, errors) for each webhook, equivalent to
GET /api/v1/webhooks/logs. From there you can also trigger a retry on a failed delivery, equivalent toPOST /api/v1/webhooks/recall. - Edit / delete / set default — the same list view lets you edit a webhook's URL, switch which webhook is marked default, or delete one — equivalent to the
PUTandDELETEendpoints above.
This is useful for quick setup and debugging, but for anything automated (e.g. provisioning a webhook per customer/environment) you'll still want to use the API directly.
12. End-to-end flow
- Authenticate —
POST /Authentication/Authority/Token→ get Bearer token. - Register a webhook (once) —
POST /api/v1/webhookswithwebhookUrl(and optionallyheaderToken,isDefault). Save the returnedid. - Initiate an envelope —
POST /api/v1/envelopes/initiate-base64(or/initiate,/initiate-by-template). Either:- omit
webhookId→ uses the account default webhook, or - pass
webhookId→ uses that specific webhook for this envelope.
- omit
- Receive the callback — your server gets a
POSTfrom Sadq atwebhookUrlwhen the event fires, with the payload shown in section 8. Verify it using theAuthorizationheader against yourheaderToken. - Troubleshoot if needed —
GET /api/v1/webhooks/logsto see delivery status/errors,POST /api/v1/webhooks/recallto retry a failed delivery (using therequestId).
13. Quick reference table
| Endpoint | Method | Purpose | Also in portal? |
|---|---|---|---|
/api/v1/webhooks | POST | Create webhook | ✅ |
/api/v1/webhooks/bulk | POST | Create multiple webhooks | ❌ (one at a time in UI) |
/api/v1/webhooks | GET | List webhooks | ✅ |
/api/v1/webhooks/{id} | GET | Get webhook by ID | ✅ |
/api/v1/webhooks | PUT | Update webhook | ✅ |
/api/v1/webhooks/{id} | DELETE | Delete webhook | ✅ |
/api/v1/webhooks/recall | POST | Retry a failed delivery (by requestId) | ✅ |
/api/v1/webhooks/logs | GET (with JSON body) | View delivery logs | ✅ |
| — | — | Send a test event to a webhook | ✅ (portal-only) |
/api/v1/envelopes/initiate-base64 (and similar) | POST | Pass webhookId to target a specific webhook | ❌ (API only) |