Skip to main content
Webhooks allow your application to receive real-time notifications when events occur, such as incoming messages, delivery status changes, or partner invitation updates. Zavu supports two types of webhooks:
  • Sender Webhooks: Receive events for a specific sender (messages, conversations)
  • Project Webhooks: Receive project-level events (partner invitations)

Project Webhooks

Project webhooks are ideal for receiving notifications about project-level events, such as when a partner invitation is completed. This is particularly useful if you’re using the Partner Invitations API to onboard clients.

Via Dashboard

  1. Go to Dashboard and select your project
  2. Navigate to Webhooks in the sidebar
  3. In the “Project Webhook” section, click Configure
  4. Enter your webhook URL and select the events you want to receive
  5. Save - you’ll receive a signing secret

Via API

Configure a project webhook using the invitations API:
cURL
curl -X POST https://api.zavu.dev/v1/invitations/webhook \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/zavu",
    "events": ["invitation.status_changed"]
  }'
Response:
{
  "webhook": {
    "url": "https://your-app.com/webhooks/zavu",
    "events": ["invitation.status_changed"],
    "secret": "whsec_abc123def456...",
    "active": true
  }
}

Managing Project Webhooks

Get current configuration:
cURL
curl https://api.zavu.dev/v1/invitations/webhook \
  -H "Authorization: Bearer zv_live_xxx"
Update webhook:
cURL
curl -X PATCH https://api.zavu.dev/v1/invitations/webhook \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://new-url.com/webhooks",
    "active": true
  }'
Remove webhook:
cURL
curl -X DELETE https://api.zavu.dev/v1/invitations/webhook \
  -H "Authorization: Bearer zv_live_xxx"

Project Webhook Events

EventDescription
invitation.status_changedA partner invitation status changed (pending, in_progress, completed, cancelled)

Project Webhook Payload

{
  "id": "evt_1234567890_abc123",
  "type": "invitation.status_changed",
  "timestamp": 1705312200000,
  "projectId": "prj_xyz789",
  "data": {
    "invitationId": "inv_abc123",
    "clientName": "John Doe",
    "clientEmail": "john@example.com",
    "currentStatus": "completed",
    "newSenderId": "snd_new123",
    "wabaAccountId": "waba_123456"
  }
}
Project webhooks are independent of sender webhooks. You can have both configured simultaneously.

Sender Webhooks

Each sender can have one webhook configured. Webhooks are managed as part of the sender resource.

Via Dashboard

  1. Go to Dashboard and select your project
  2. Navigate to your Sender’s settings
  3. Click Add Webhook
  4. Enter your webhook URL and select the events you want to receive
  5. Save - you’ll receive a signing secret

Via API

Configure a webhook when creating a new sender:
cURL
curl -X POST https://api.zavu.dev/v1/senders \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Sender",
    "phoneNumber": "+15551234567",
    "webhookUrl": "https://your-app.com/webhooks/zavu",
    "webhookEvents": ["message.inbound", "message.delivered", "message.failed"]
  }'
Response:
{
  "id": "snd_abc123",
  "name": "My Sender",
  "phoneNumber": "+15551234567",
  "isDefault": false,
  "webhook": {
    "url": "https://your-app.com/webhooks/zavu",
    "events": ["message.inbound", "message.delivered", "message.failed"],
    "secret": "whsec_abc123def456...",
    "active": true
  },
  "createdAt": "2024-01-15T10:30:00.000Z"
}
Store your webhook secret securely. It’s only shown once when you create the sender with a webhook. You’ll need it to verify webhook signatures.

Available Events

Inbound (Receiving Messages)

EventDescription
conversation.newFirst message from a new contact (new conversation started)
message.inboundA customer sent you a message

Outbound (Delivery Tracking)

EventDescription
message.queuedYour message was queued for delivery
message.sentYour message was sent to the carrier
message.deliveredYour message was delivered to the recipient
message.failedMessage delivery failed

Templates

EventDescription
template.status_changedA WhatsApp template status changed (draft, pending, approved, rejected)

Partner Invitations (Project Webhook)

EventDescription
invitation.status_changedA partner invitation status changed (pending, in_progress, completed, cancelled)
The invitation.status_changed event is delivered via Project Webhooks, not Sender Webhooks. See the Project Webhooks section above for configuration.
Subscribe to message.inbound to receive all customer messages. Add conversation.new to get notified when a new contact messages you for the first time (useful for lead tracking). The outbound events are optional and used for tracking delivery status.

Webhook Payload

All webhook payloads follow the same structure:
{
  "id": "evt_1234567890_abc123",
  "type": "message.inbound",
  "timestamp": 1705312200000,
  "senderId": "snd_abc123",
  "projectId": "prj_xyz789",
  "data": {
    // Event-specific data
  }
}
FieldDescription
idUnique event identifier
typeEvent type (e.g., message.inbound)
timestampUnix timestamp in milliseconds
senderIdThe Sender that received this event
projectIdYour project ID
dataEvent-specific payload

Handling Webhooks

Your webhook endpoint must:
  1. Respond with 2xx status within 30 seconds
  2. Verify the signature to ensure the request is from Zavu
  3. Process asynchronously for long-running tasks
import express from "express";
const app = express();

app.post("/webhooks/zavu", express.json(), (req, res) => {
  // 1. Verify signature (see Security guide)
  const signature = req.headers["x-zavu-signature"];
  if (!verifySignature(signature, req.body, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }

  // 2. Acknowledge receipt immediately
  res.status(200).send("OK");

  // 3. Process the event asynchronously
  const event = req.body;
  processEvent(event).catch(console.error);
});

async function processEvent(event) {
  switch (event.type) {
    case "message.inbound":
      await handleInboundMessage(event.data);
      break;
    case "message.delivered":
      await handleDeliveryConfirmation(event.data);
      break;
    case "message.failed":
      await handleDeliveryFailure(event.data);
      break;
  }
}

Retry Policy

If your endpoint returns an error or doesn’t respond within 30 seconds, Zavu will retry the delivery:
AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry15 minutes
4th retry1 hour
5th retry4 hours
After 5 failed attempts, the webhook delivery is marked as failed. You can view failed deliveries in the Dashboard.
Use a service like webhook.site or ngrok for testing webhooks during development.

Managing Webhooks

Update Webhook Configuration

Update your sender’s webhook settings:
cURL
curl -X PATCH https://api.zavu.dev/v1/senders/snd_abc123 \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookUrl": "https://new-url.com/webhooks",
    "webhookEvents": ["message.inbound"],
    "webhookActive": true
  }'

Disable Webhook

cURL
curl -X PATCH https://api.zavu.dev/v1/senders/snd_abc123 \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookActive": false
  }'

Remove Webhook

Set webhookUrl to null to remove the webhook:
cURL
curl -X PATCH https://api.zavu.dev/v1/senders/snd_abc123 \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookUrl": null
  }'

Regenerate Secret

If your webhook secret is compromised:
cURL
curl -X POST https://api.zavu.dev/v1/senders/snd_abc123/webhook/secret \
  -H "Authorization: Bearer zv_live_xxx"
Response:
{
  "secret": "whsec_new_secret_here..."
}

Next Steps