Docs/Webhooks

Webhooks

Receive real-time notifications when events happen in your HanDl account. Webhooks let you build reactive integrations without polling the API.

How Webhooks Work

When an event occurs (e.g., a new order is created), HanDl sends an HTTP POST request to your configured endpoint with the event payload. Your server should respond with a 200 status within 10 seconds.

Event occurs
HanDl sends POST
Your endpoint

Configuring Webhooks

Set up webhooks from Settings → API or via the API.

POST/v1/webhooks
ParameterTypeDescription
url
Required
stringThe HTTPS URL to receive webhook events.
events
Required
arrayList of event types to subscribe to. Use '*' for all events.
description
Optional
stringA label for this webhook endpoint.
curl
curl -X POST https://api.handl-ng.com/v1/webhooks \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/handl",
    "events": ["order.created", "order.updated", "payment.completed"],
    "description": "Production webhook"
  }'

Event Types

message.receivedA new inbound message from a customer
message.sentAn outbound message has been sent
conversation.createdA new conversation started
order.createdA new order was created
order.updatedAn order status changed
payment.completedA payment was confirmed
payment.failedA payment attempt failed
product.createdA new product was added
product.updatedA product was modified

Event Payload

Every webhook delivery has the same envelope structure:

json
{
  "id": "evt_abc123",
  "object": "event",
  "type": "order.created",
  "created_at": "2025-06-15T14:30:00Z",
  "data": {
    "id": "ord_1042",
    "object": "order",
    "status": "pending",
    "customer": {
      "name": "Amara Obi",
      "phone": "+2348012345678"
    },
    "total": 850000,
    "currency": "NGN"
  }
}

Verifying Signatures

Every webhook request includes a X-HanDl-Signature header containing an HMAC-SHA256 signature. Verify it to ensure the request came from HanDl.

javascript
import crypto from 'crypto';

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body, 'utf8')
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
app.post('/webhooks/handl', (req, res) => {
  const sig = req.headers['x-handl-signature'];
  const valid = verifyWebhook(req.rawBody, sig, 'whsec_...');

  if (!valid) return res.status(401).send('Invalid signature');

  const event = JSON.parse(req.body);
  console.log(event.type); // "order.created"

  res.status(200).send('OK');
});
🚨
Always verify webhook signatures. Without verification, an attacker could send fake events to your endpoint.

Retry Policy

If your endpoint returns a non-2xx status or times out, HanDl retries with exponential backoff:

1st retry30 seconds
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry (final)24 hours

After 5 failed attempts, the endpoint is marked as unhealthy. You'll receive an email notification. Re-enable from Settings → API.