Skip to main content
Webhooks let your server react in real time to things happening on Tanvik — an inbound WhatsApp message, a delivery status update, an OTP verification, a template review result — without polling the API.

Registering an endpoint

curl https://xwialxkobwygraiddimj.supabase.co/functions/v1/public-api/v1/webhooks \
  -H "Authorization: Bearer tvk_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/tanvik",
    "events": ["message.received", "message.status", "otp.verified"]
  }'

Request body

url
string
required
Your endpoint. Must be https://.
events
string[]
required
One or more of message.received, message.status, otp.verified, template.status.

Response

{
  "webhook_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "url": "https://yourapp.com/webhooks/tanvik",
  "events": ["message.received", "message.status", "otp.verified"],
  "secret": "whsec_9f2ac1e460a040bc...",
  "status": "active"
}
The secret is shown exactly once, at registration. Store it — you’ll need it to verify signatures, and Tanvik can’t show it to you again.
You can register multiple endpoints, each subscribed to a different subset of events.

Listing and removing webhooks

# List
curl https://xwialxkobwygraiddimj.supabase.co/functions/v1/public-api/v1/webhooks \
  -H "Authorization: Bearer tvk_live_xxxxxxxxxxxxxxxx"

# Remove
curl -X DELETE https://xwialxkobwygraiddimj.supabase.co/functions/v1/public-api/v1/webhooks/{webhook_id} \
  -H "Authorization: Bearer tvk_live_xxxxxxxxxxxxxxxx"
The list response never includes the secret — only id, url, events, status, and timestamps.

Verifying signatures

Every webhook request includes an X-Tanvik-Signature header — an HMAC-SHA256 signature of the raw request body, signed with the secret you got at registration.
const crypto = require('crypto');

function isValidSignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(`sha256=${expected}`));
}
Always verify the signature before trusting a webhook payload. Compute it over the raw request body, not a re-serialized JSON object.

Delivery and retries

  • Your endpoint must respond with a 2xx status within 10 seconds.
  • Failed deliveries are retried: 1 minute, 5 minutes, 30 minutes, then hourly.
  • After 24 hours of a delivery still failing, that endpoint is automatically set to paused — check GET /v1/webhooks to see status and pause_reason. Re-registering (or a future re-activate endpoint) is needed to resume it.

Event types

EventFired when
message.receivedA customer sends you a WhatsApp message
message.statusA sent message changes status (sent, delivered, read, failed)
otp.verifiedA customer successfully verifies an OTP
template.statusA submitted template is approved or rejected by Meta
See the WhatsApp Webhook page for the exact payload shape of each event.
Webhooks are polled into your account continuously for messages and OTPs. template.status specifically depends on Tanvik’s template sync running for your account — if you need it to fire faster after a Meta review, ask your account team.