Boltly Boltly / Docs
Docs / Webhooks

Webhooks

Receive real-time notifications when events happen in your Boltly account. Webhooks are delivered as HTTP POST requests to your endpoint.


Event types

Subscribe to any combination of these events when creating a webhook endpoint.

message.received A new inbound message from a contact
message.sent An outbound message was accepted by WhatsApp
message.delivered Message was delivered to the contact's device
message.read Contact opened and read the message
message.failed Message delivery failed

Creating a webhook

Register an endpoint via the dashboard at Settings → Developer Access → Webhooks, or use the API:

cURL
curl -X POST https://api.boltly.online/v1/developer-access/webhooks \
  -H "X-API-Key: sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/boltly",
    "events": ["message.received", "message.delivered"],
    "description": "Production webhook"
  }'

The response includes a signing_secret starting with whsec_. Store this to verify incoming payloads.


Payload format

Every webhook delivery sends a JSON payload with this structure:

JSON
{
  "id": "evt_a1b2c3d4-...",
  "type": "message.received",
  "organization_id": "org_...",
  "created_at": "2026-04-03T12:00:00Z",
  "data": {
    "message_id": "msg_...",
    "conversation_id": "conv_...",
    "from": "+1234567890",
    "type": "text",
    "text": { "body": "Hi, I'd like to book an appointment" }
  }
}

Verifying signatures

Every webhook request includes an X-Webhook-Signature header. Verify it to ensure the request came from Boltly.

Verification steps

  1. 1. Read the raw request body (do not parse JSON first)
  2. 2. Compute HMAC-SHA256(body, signing_secret)
  3. 3. Hex-encode the result
  4. 4. Compare with the X-Webhook-Signature header (constant-time comparison)
Node.js
import crypto from "crypto";

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Delivery & retries

Webhooks are delivered asynchronously via a queue worker. Your endpoint must respond with a 2xx status within 30 seconds. Failed deliveries are retried automatically.