Webhooks

Receive message.received and message.status events for your Edesy WhatsApp numbers on your own HTTPS endpoint, signed with HMAC-SHA256 and retried with backoff.

3 min read

Base URL
https://voice-api.edesy.in/v1/whatsapp
Auth
Authorization: Bearer sk_...Get a key

WhatsApp webhooks send events for your Edesy numbers to your own HTTPS endpoint. Register a URL, choose message.received, message.status or both, and set a signing secret. Each POST carries an X-Edesy-Signature HMAC-SHA256 header, failed deliveries are retried with backoff, and every attempt is shown in a delivery log.

Facts#

Item Detail
Where wa-connect.edesy.in > Webhooks, or the API below
Events message.received (a customer sent a message), message.status (sent, delivered, read, failed)
Filter Pick event types per webhook; an empty list means all events
Multiple endpoints Yes, register as many as you need
Signature X-Edesy-Signature: sha256=<hex>, HMAC-SHA256 of the raw body with your secret
Success Any 2xx response within 5 seconds
Retries Up to 6 attempts, backoff of about 30 s, 1 min, 2 min, 4 min, 8 min
Delivery log Event, status, attempts, HTTP code, error, next retry, payload
Test Send a webhook.test event from the portal or API

How it works#

  1. Add a webhook on the Webhooks page: endpoint URL, optional signing secret, and events.
  2. Click Test to send a webhook.test event and check that your endpoint returns 2xx.
  3. Verify the signature on every request (below).
  4. Return 2xx quickly. Do slow work after you respond.
  5. Check the delivery log if events are missing. Failed attempts show the HTTP code and error, and pending ones show the next retry time.

Payload#

Every event uses the same envelope:

{
  "event": "message.received",
  "timestamp": "2026-10-28T10:15:12Z",
  "data": { }
}

message.received#

data is the stored inbound message:

{
  "event": "message.received",
  "timestamp": "2026-10-28T10:15:12Z",
  "data": {
    "id": "5b1c2d3e-0000-4000-8000-000000000000",
    "conversation_id": "7d8e9f00-0000-4000-8000-000000000000",
    "wamid": "wamid.HBgM...",
    "direction": "inbound",
    "type": "text",
    "status": "delivered",
    "from": "+919876543210",
    "to": "+911234567890",
    "content": "Is my order shipped?",
    "created_at": "2026-10-28T10:15:12Z"
  }
}

Media messages also carry media_id, media_mime_type and, for documents, file_name. Replies carry context_message_id.

message.status#

data is the WhatsApp status update:

{
  "event": "message.status",
  "timestamp": "2026-10-28T10:15:20Z",
  "data": {
    "id": "wamid.HBgM...",
    "recipient_id": "919876543210",
    "status": "delivered",
    "timestamp": "1761646520"
  }
}

status is sent, delivered, read or failed. Failed updates include an errors array. Match data.id to the wamid you got when sending.

Verify the signature#

import crypto from 'crypto';

function isValid(rawBody, header, secret) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  if (!header || header.length !== expected.length) return false;
  return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}

Compute the HMAC over the raw request body, before any JSON parsing. If you did not set a secret, no signature header is sent.

Webhooks API#

Base URL: https://voice-api.edesy.in/v1/whatsapp. Auth: Authorization: Bearer sk_....

Method Path Description
POST /webhooks Register. Body: url (required), secret, event_types
GET /webhooks List (the secret is never returned; has_secret shows whether one is set)
DELETE /webhooks/{id} Remove
POST /webhooks/{id}/test Send a webhook.test event; returns ok and status_code
GET /webhooks/{id}/deliveries Recent delivery attempts (limit, default 50)
curl -X POST https://voice-api.edesy.in/v1/whatsapp/webhooks \
  -H "Authorization: Bearer sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/whatsapp",
    "secret": "a-long-random-string",
    "event_types": ["message.received", "message.status"]
  }'

FAQ#

Which events can I subscribe to?#

message.received for inbound messages and message.status for sent, delivered, read and failed updates.

How do I check a webhook is genuine?#

Compute HMAC-SHA256 of the raw body with your secret and compare it to X-Edesy-Signature (sha256=<hex>).

What happens if my server is down?#

The delivery is retried up to 6 attempts with growing gaps (about 30 s, 1 min, 2 min, 4 min, 8 min). After the last attempt it is marked failed in the delivery log.

How fast must my endpoint respond?#

Within 5 seconds, with a 2xx status. Anything else counts as a failed attempt.

Can I send events to more than one URL?#

Yes. Register several webhooks, each with its own events and secret.

Can I test my endpoint before going live?#

Yes. Use Test in the portal or POST/v1/whatsapp/webhooks/{id}/test. It sends a webhook.test event.

Do I get template approval events?#

No. Template status is updated in the portal and API; use Sync with Meta or GET/v1/whatsapp/templates to check it.

Was this page helpful?