Skip to main content

Introduction

Webhooks allow your application to receive real-time notifications when events occur in your EnviaAI account. Instead of polling our API, webhooks push data to your server instantly.

Setting Up Webhooks

1. Create a Webhook Endpoint

Your server needs an endpoint to receive webhook events. This endpoint must:
  • Accept POST requests
  • Return a 2xx status code quickly (within 5 seconds)
  • Be publicly accessible via HTTPS
// Example Express.js endpoint
app.post('/webhooks/enviaai', express.json(), (req, res) => {
  const event = req.body;

  // Verify webhook signature
  const signature = req.headers['x-enviaai-signature'];
  if (!verifySignature(event, signature)) {
    return res.status(401).send('Invalid signature');
  }

  // Process event asynchronously
  processEvent(event);

  // Respond quickly
  res.status(200).send('OK');
});

2. Configure Your Webhook

Configure your webhook URL in the dashboard or via API:
await client.webhooks.create({
  url: 'https://myapp.com/webhooks/enviaai',
  events: [
    'message.received',
    'message.sent',
    'message.delivered',
    'message.read',
    'instance.connected',
    'instance.disconnected'
  ],
  secret: 'your-webhook-secret'
});

3. Verify Webhook Signatures

All webhook requests include a signature header for verification:
const crypto = require('crypto');

function verifySignature(payload, signature) {
  const expected = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(`sha256=${expected}`)
  );
}

Webhook Events

Message Events

Triggered when a new message is received.
{
  "event": "message.received",
  "timestamp": "2026-02-03T12:00:00.000Z",
  "data": {
    "messageId": "msg_abc123",
    "instanceId": "inst_xyz789",
    "chatId": "chat_def456",
    "from": "5511999999999",
    "type": "text",
    "content": "Hello!",
    "timestamp": "2026-02-03T12:00:00.000Z",
    "contactName": "John Doe",
    "isGroup": false
  }
}
Triggered when your message is sent to WhatsApp.
{
  "event": "message.sent",
  "timestamp": "2026-02-03T12:00:00.000Z",
  "data": {
    "messageId": "msg_abc123",
    "instanceId": "inst_xyz789",
    "chatId": "chat_def456",
    "to": "5511999999999",
    "type": "text",
    "content": "Hi there!",
    "status": "sent"
  }
}
Triggered when your message is delivered to the recipient.
{
  "event": "message.delivered",
  "timestamp": "2026-02-03T12:00:05.000Z",
  "data": {
    "messageId": "msg_abc123",
    "instanceId": "inst_xyz789",
    "chatId": "chat_def456",
    "to": "5511999999999",
    "status": "delivered",
    "deliveredAt": "2026-02-03T12:00:05.000Z"
  }
}
Triggered when the recipient reads your message.
{
  "event": "message.read",
  "timestamp": "2026-02-03T12:00:10.000Z",
  "data": {
    "messageId": "msg_abc123",
    "instanceId": "inst_xyz789",
    "chatId": "chat_def456",
    "to": "5511999999999",
    "status": "read",
    "readAt": "2026-02-03T12:00:10.000Z"
  }
}
Triggered when message delivery fails.
{
  "event": "message.failed",
  "timestamp": "2026-02-03T12:00:00.000Z",
  "data": {
    "messageId": "msg_abc123",
    "instanceId": "inst_xyz789",
    "chatId": "chat_def456",
    "to": "5511999999999",
    "status": "failed",
    "error": {
      "code": "recipient_not_found",
      "message": "The phone number is not registered on WhatsApp"
    }
  }
}

Instance Events

Triggered when an instance connects to WhatsApp.
{
  "event": "instance.connected",
  "timestamp": "2026-02-03T12:00:00.000Z",
  "data": {
    "instanceId": "inst_xyz789",
    "phone": "5511999999999",
    "profileName": "My Business"
  }
}
Triggered when an instance disconnects from WhatsApp.
{
  "event": "instance.disconnected",
  "timestamp": "2026-02-03T12:00:00.000Z",
  "data": {
    "instanceId": "inst_xyz789",
    "reason": "logged_out"
  }
}
Triggered when a new QR code is generated.
{
  "event": "instance.qr_updated",
  "timestamp": "2026-02-03T12:00:00.000Z",
  "data": {
    "instanceId": "inst_xyz789",
    "qrCode": "data:image/png;base64,...",
    "expiresAt": "2026-02-03T12:01:00.000Z"
  }
}

Webhook Configuration

API Endpoints

MethodEndpointDescription
POST/v1/webhooksCreate a new webhook
GET/v1/webhooksList all webhooks
GET/v1/webhooks/{id}Get webhook details
PUT/v1/webhooks/{id}Update a webhook
DELETE/v1/webhooks/{id}Delete a webhook

Webhook Object

{
  "id": "wh_abc123",
  "url": "https://myapp.com/webhooks/enviaai",
  "events": ["message.received", "message.sent"],
  "secret": "whs_...",
  "status": "active",
  "createdAt": "2026-02-01T10:00:00.000Z",
  "lastDeliveryAt": "2026-02-03T12:00:00.000Z",
  "lastDeliveryStatus": "success"
}

Retry Policy

If your endpoint fails to respond with a 2xx status code, we’ll retry the webhook:
AttemptDelay
1Immediate
230 seconds
32 minutes
410 minutes
51 hour
66 hours
After 6 failed attempts, the webhook event is marked as failed.

Best Practices

Respond Quickly

Return a 2xx response within 5 seconds. Process events asynchronously.

Verify Signatures

Always verify the webhook signature to ensure authenticity.

Handle Duplicates

Implement idempotency using the messageId or eventId.

Log Everything

Log all webhook events for debugging and auditing.

Example: Async Processing

const Queue = require('bull');
const webhookQueue = new Queue('webhooks');

app.post('/webhooks/enviaai', express.json(), async (req, res) => {
  // Verify signature
  if (!verifySignature(req.body, req.headers['x-enviaai-signature'])) {
    return res.status(401).send('Invalid signature');
  }

  // Queue for async processing
  await webhookQueue.add(req.body);

  // Respond immediately
  res.status(200).send('OK');
});

// Process events asynchronously
webhookQueue.process(async (job) => {
  const event = job.data;

  switch (event.event) {
    case 'message.received':
      await handleIncomingMessage(event.data);
      break;
    case 'message.delivered':
      await updateMessageStatus(event.data);
      break;
    // Handle other events...
  }
});

Testing Webhooks

Use the webhook test endpoint to send test events:
curl -X POST https://api.enviaai.app/v1/webhooks/wh_abc123/test \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "message.received"
  }'
Or use tools like ngrok to expose your local development server:
ngrok http 3000

Webhook Logs

View webhook delivery logs in the dashboard or via API:
curl "https://api.enviaai.app/v1/webhooks/wh_abc123/logs?limit=50" \
  -H "Authorization: Bearer your-api-key"
Response:
{
  "data": [
    {
      "id": "log_xyz789",
      "event": "message.received",
      "status": "success",
      "statusCode": 200,
      "responseTime": 145,
      "timestamp": "2026-02-03T12:00:00.000Z"
    }
  ]
}