Skip to content
DigiCalls Developers
Documentation · Webhooks

DigiCalls Developers / Webhooks

Bring replies and statuses into your app.

DigiCalls calls your HTTPS endpoint when an SMS arrives or its delivery status changes. Verify the notification, save it and process it in your own workflow.

Choose your events

EventMeaning
sms.message.receivedA new incoming SMS was saved.
sms.message.status_updatedAn SMS delivery or operational status changed.
webhook.testA synthetic connection test. Handle it without fetching or sending an SMS.

Subscribe to either or both SMS events. The payload contains message metadata, not SMS text or phone numbers.

Example incoming event
{
  "id": "6f190477-3789-482b-a282-c365fcb9043b",
  "object": "event",
  "type": "sms.message.received",
  "createdAt": "2026-10-26T12:00:00Z",
  "accountId": "YOUR_CUSTOMER_ID",
  "data": {
    "id": "9315df70-30f0-4eeb-a9db-172d9ce4d92a",
    "object": "sms_message",
    "direction": "inbound",
    "status": "received",
    "updatedAt": "2026-10-26T12:00:00Z",
    "resource": "/api/v1/sms/messages/9315df70-30f0-4eeb-a9db-172d9ce4d92a"
  }
}

Use sms:read to fetch message content after verification. Webhook management permission does not grant access to SMS content.

Connect your receiver

Use API & Integrations → SMS Webhooks in the dashboard, or use the API below with webhooks:write. Reads and delivery history require webhooks:read.

  1. Prepare an endpoint on a domain you control, with public HTTPS on port 443 and a valid certificate. Redirects, private/local addresses and credentials in URLs are rejected.
  2. Create an endpoint. It starts paused. Save the one-time secret on your receiver; this is a signing secret, separate from your API key.
  3. Configure verification and durable event storage, then send a synthetic test.
  4. Inspect delivery history. After a successful 2xx response for the current configuration, enable the endpoint explicitly.
cURL · create paused endpoint
curl --fail-with-body --request POST \
  "https://digicalls.com/api/v1/webhooks" \
  --header "Authorization: Bearer $DIGICALLS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "name": "Customer app",
  "url": "https://your-app.example/webhooks/digicalls",
  "events": [
    "sms.message.received",
    "sms.message.status_updated"
  ]
}'

Store data.id as DIGICALLS_WEBHOOK_ID and use the current data.revision for each configuration action. This example uses revision 1; replace it with the value returned for your endpoint.

cURL · synthetic test
curl --fail-with-body --request POST \
  "https://digicalls.com/api/v1/webhooks/$DIGICALLS_WEBHOOK_ID/test" \
  --header "Authorization: Bearer $DIGICALLS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "expectedRevision": 1
}'
cURL · delivery history
curl --fail-with-body \
  "https://digicalls.com/api/v1/webhooks/$DIGICALLS_WEBHOOK_ID/deliveries" \
  --header "Authorization: Bearer $DIGICALLS_API_KEY"
cURL · enable after a successful test
curl --fail-with-body --request POST \
  "https://digicalls.com/api/v1/webhooks/$DIGICALLS_WEBHOOK_ID/enabled" \
  --header "Authorization: Bearer $DIGICALLS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "enabled": true,
  "expectedRevision": 1
}'

A queued test response is not proof of delivery. A successful delivery proves HTTP receipt, not correct signature verification inside your app. Test your receiver’s rejection path too.

Verify before processing

Read these headers case-insensitively:

Webhook headers
DigiCalls-Event-Id: EVENT_UUID
DigiCalls-Delivery-Id: DELIVERY_UUID
DigiCalls-Signature: t=UNIX_SECONDS,v1=HEX_DIGEST
  1. Capture the original raw request bytes before any JSON parser.
  2. Reject missing/malformed signatures and timestamps more than 300 seconds in the past or future.
  3. Calculate HMAC-SHA256 with your signing secret over timestamp + "." + rawBody. Compare the digest in constant time.
  4. Then parse JSON and verify your public Customer ID, supported event type and matching body/header event ID.
  5. Persist the event with a unique event ID before acknowledging 2xx. Do slow CRM work in a separate worker.

The Node.js receiver example implements these checks with Express and PostgreSQL. It accepts matching duplicates with 204, rejects conflicting reuse with 409 and returns 503 if storage fails.

Run the receiver example

Download sms-webhook-receiver.cjs to your application server. Install Express and pg in that project. Supply DATABASE_URL, DIGICALLS_WEBHOOK_SECRET and DIGICALLS_ACCOUNT_ID through your secret manager.

Receiver setup
npm install express pg
node sms-webhook-receiver.cjs --init
node sms-webhook-receiver.cjs

The example listens on localhost port 4100 at /webhooks/digicalls. Expose it behind your own HTTPS reverse proxy on port 443. It uses your application’s PostgreSQL database, never DigiCalls’ database.

It stores verified events. Add a worker that fetches the message with sms:read, performs your CRM action idempotently and marks the event processed. Handle webhook.test without an SMS lookup.

Duplicates, ordering and retries

  • Delivery is at least once. The same event can arrive again; do not create duplicate CRM entries or send repeated replies.
  • Events can arrive out of order. Fetch current message status when making a decision.
  • Network failures, timeouts, HTTP 408, 429 and 5xx are retried with backoff, up to eight attempts within 24 hours. Retry-After is honored up to six hours.
  • Other non-2xx responses require review. Redirects are not followed. A manual retry cannot reset the attempt or age limit.
  • Paused periods are not replayed when you enable the endpoint. Review message history separately if you need to reconcile a gap.

Up to three non-removed endpoints and 20 synthetic tests per hour per business. Changing URL, event selection or signing secret pauses delivery and requires a new test. Pausing cannot recall a request already in flight.

All webhook endpoints →