صادقSadq®
GuidesAdmin
All Guides

Webhooks Integration Guide

Complete guide to creating, managing, and receiving Sadq webhooks — including the default webhook behavior, targeting a specific webhook per envelope, and reading delivery logs.

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:

FieldTypeRequiredNotes
webhookUrlstringYour endpoint that will receive the callback
headerTokenstringIf set, Sadq sends it back as the Authorization header on every callback to your URL
isDefaultbool❌ (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 the Authorization header when it calls your webhookUrl. 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:

FieldTypeRequiredNotes
idGuidWhich webhook to update
webhookUrlstringNew target URL
isDefaultboolNew 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: true on 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/initiate
  • POST /api/v1/envelopes/initiate-base64
  • POST /api/v1/envelopes/initiate-by-template
  • POST /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:

FieldTypeRequiredNotes
requestIdGuidThe 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):

FieldTypeRequiredNotes
requestIdstringFilter logs by request ID
webhookUrlstringFilter logs by your webhook URL
webhookStatusintegerFilter 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/webhooks endpoint 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 Authorization header, 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 to POST /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 PUT and DELETE endpoints 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

  1. AuthenticatePOST /Authentication/Authority/Token → get Bearer token.
  2. Register a webhook (once)POST /api/v1/webhooks with webhookUrl (and optionally headerToken, isDefault). Save the returned id.
  3. Initiate an envelopePOST /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.
  4. Receive the callback — your server gets a POST from Sadq at webhookUrl when the event fires, with the payload shown in section 8. Verify it using the Authorization header against your headerToken.
  5. Troubleshoot if neededGET /api/v1/webhooks/logs to see delivery status/errors, POST /api/v1/webhooks/recall to retry a failed delivery (using the requestId).

13. Quick reference table

EndpointMethodPurposeAlso in portal?
/api/v1/webhooksPOSTCreate webhook
/api/v1/webhooks/bulkPOSTCreate multiple webhooks❌ (one at a time in UI)
/api/v1/webhooksGETList webhooks
/api/v1/webhooks/{id}GETGet webhook by ID
/api/v1/webhooksPUTUpdate webhook
/api/v1/webhooks/{id}DELETEDelete webhook
/api/v1/webhooks/recallPOSTRetry a failed delivery (by requestId)
/api/v1/webhooks/logsGET (with JSON body)View delivery logs
Send a test event to a webhook✅ (portal-only)
/api/v1/envelopes/initiate-base64 (and similar)POSTPass webhookId to target a specific webhook❌ (API only)