WhatsApp Webhook Format Reference
v1.6.0+Complete technical reference for WhatsApp webhook payloads forwarded by WhatsMarkSaaS to external endpoints like N8N, Zapier, and Make.com.
Overview
This document provides the complete specification for WhatsApp webhook payloads in N8N format. All webhooks follow a consistent structure regardless of event type.
Audience
This reference is for developers building custom integrations. If you're using N8N, Zapier, or Make.com, see the WhatsApp Webhook Forwarding Guide instead.
Base Payload Structure
All WhatsApp webhooks follow this standard structure:
interface WhatsAppWebhookPayload {
event: EventObject;
tenant: TenantObject;
data: DataObject;
whatsapp: WhatsAppObject;
metadata: MetadataObject;
}Complete Schema
{
"event": {
"id": "string", // Format: evt_{timestamp}_{random}
"type": "string", // Event type (see Event Types section)
"timestamp": "string", // ISO 8601 datetime
"version": "string" // Format version (currently "1.0")
},
"tenant": {
"id": number, // Tenant ID
"name": "string" // Tenant/company name
},
"data": {
"resource": {
"type": "string", // Resource type: message, status, account, etc.
"id": "string|null", // Resource identifier (message ID, etc.)
"attributes": object // Resource-specific attributes
},
"relationships": object // Related entities (contact, metadata, etc.)
},
"whatsapp": {
"original_payload": object // Complete original WhatsApp webhook
},
"metadata": {
"source": "whatsapp_webhook_forward",
"environment": "string", // production, staging, etc.
"request_id": "string" // UUID for request tracing
}
}Event Object
Contains event metadata and identification.
interface EventObject {
id: string; // Unique event identifier
type: string; // Event type (see Event Types)
timestamp: string; // ISO 8601 timestamp
version: string; // Payload format version
}Event ID Format
evt_{unix_timestamp}_{random_string}
Example: evt_1767263928_7KGQvXqbFFEvent Types
All possible event types:
type WhatsAppEventType =
// Message Events
| 'whatsapp.message.received'
| 'whatsapp.message.sent'
| 'whatsapp.message.delivered'
| 'whatsapp.message.read'
| 'whatsapp.message.failed'
// Status Events
| 'whatsapp.status.updated'
// Account Events
| 'whatsapp.account.alert'
| 'whatsapp.account.review_updated'
| 'whatsapp.account.updated'
// Business Events
| 'whatsapp.business.capability_updated'
| 'whatsapp.business.status_updated'
// Template Events
| 'whatsapp.template.status_updated'
| 'whatsapp.template.quality_updated'
// Phone Events
| 'whatsapp.phone.quality_updated'
| 'whatsapp.phone.name_updated'
// Other Events
| 'whatsapp.call.received'
| 'whatsapp.flow.event';Tenant Object
Multi-tenancy context information.
interface TenantObject {
id: number; // Tenant identifier
name: string; // Tenant/company name
}Example:
{
"id": 3,
"name": "Acme Corporation"
}Data Object
Contains the actual event data and relationships.
interface DataObject {
resource: ResourceObject;
relationships: RelationshipsObject;
}Resource Object
interface ResourceObject {
type: string; // Resource type
id: string | null; // Resource identifier
attributes: object; // Resource-specific data
}Relationships Object
Related entities vary by resource type. Common relationships:
interface RelationshipsObject {
contact?: ContactRelationship;
metadata?: MetadataRelationship;
[key: string]: any;
}WhatsApp Object
Contains the complete original WhatsApp webhook payload.
interface WhatsAppObject {
original_payload: {
object: string;
entry: Array<{
id: string;
changes: Array<{
value: object;
field: string;
}>;
}>;
};
}Metadata Object
Request tracking and environment information.
interface MetadataObject {
source: 'whatsapp_webhook_forward';
environment: string; // production, staging, development
request_id: string; // UUID for tracing
}Event Type Details
Message Events
whatsapp.message.received
Incoming message from customer.
Payload Example:
{
"event": {
"id": "evt_1767263928_abc123",
"type": "whatsapp.message.received",
"timestamp": "2026-01-01T10:38:48+00:00",
"version": "1.0"
},
"tenant": {
"id": 3,
"name": "Acme Corp"
},
"data": {
"resource": {
"type": "message",
"id": "wamid.HBgMOTE5OTI1MTE5Mjg0FQIAEhgWM0VCMDE1NDRCMTFBMDQ1RTlFM0NFMwA=",
"attributes": {
"message_id": "wamid.HBgMOTE5OTI1MTE5Mjg0FQIAEhgWM0VCMDE1NDRCMTFBMDQ1RTlFM0NFMwA=",
"from": "919876543210",
"timestamp": "1767263926",
"type": "text",
"text": "Hello, I need help!",
"context": null
}
},
"relationships": {
"contact": {
"wa_id": "919876543210",
"name": "John Doe"
},
"metadata": {
"phone_number_id": "339141689277134",
"display_phone_number": "919428735270"
}
}
},
"whatsapp": {
"original_payload": {
/* Full WhatsApp payload */
}
},
"metadata": {
"source": "whatsapp_webhook_forward",
"environment": "production",
"request_id": "595bbcf8-93bf-418b-8209-3343c76ad852"
}
}Message Types:
text- Plain text messageimage- Image with optional captionvideo- Video with optional captionaudio- Audio/voice messagedocument- Document/filelocation- Location coordinatescontacts- Contact cardsticker- Stickerinteractive- Button/list responsesbutton- Quick reply buttonorder- Order message
**Text Message Attributes:
{
message_id: string;
from: string; // Phone number with country code
timestamp: string; // Unix timestamp
type: "text";
text: string; // Message text
context: { // Reply context (if replying)
from: string;
id: string;
} | null;
}Image Message Attributes:
{
message_id: string;
from: string;
timestamp: string;
type: "image";
image: {
id: string; // Media ID
mime_type: string;
sha256: string;
caption?: string;
};
context: object | null;
}Document Message Attributes:
{
message_id: string;
from: string;
timestamp: string;
type: "document";
document: {
id: string;
filename: string;
mime_type: string;
sha256: string;
caption?: string;
};
context: object | null;
}Location Message Attributes:
{
message_id: string;
from: string;
timestamp: string;
type: "location";
location: {
latitude: number;
longitude: number;
name?: string;
address?: string;
};
context: object | null;
}whatsapp.message.sent
Message sent by your business (echo event).
Payload Structure: Same as message.received but triggered when your business sends a message.
Note: The from field will be your business phone number.
whatsapp.message.delivered
Message delivered to customer's device.
Payload Example:
{
"event": {
"type": "whatsapp.message.delivered",
"timestamp": "2026-01-01T10:39:00+00:00"
},
"data": {
"resource": {
"type": "status",
"id": "wamid.xxx",
"attributes": {
"status": "delivered",
"timestamp": "1767264000",
"recipient_id": "919876543210",
"conversation": {
"id": "conv_id",
"origin": {
"type": "user_initiated"
}
}
}
}
}
}Status Values:
sent- Message sent from your serverdelivered- Delivered to customer's deviceread- Customer read the messagefailed- Delivery failed
whatsapp.message.read
Customer read your message (blue checkmarks).
Payload Structure: Similar to message.delivered with status: "read".
whatsapp.message.failed
Message delivery failed.
Payload Example:
{
"event": {
"type": "whatsapp.message.failed"
},
"data": {
"resource": {
"type": "status",
"attributes": {
"status": "failed",
"timestamp": "1767264000",
"recipient_id": "919876543210",
"errors": [
{
"code": 131047,
"title": "Re-engagement message",
"message": "Re-engagement message is outside the customer service window."
}
]
}
}
}
}Template Events
whatsapp.template.status_updated
Message template approval status changed.
Payload Example:
{
"event": {
"type": "whatsapp.template.status_updated"
},
"data": {
"resource": {
"type": "template",
"id": null,
"attributes": {
"event": "APPROVED",
"message_template_id": "1234567890",
"message_template_name": "welcome_message",
"message_template_language": "en",
"reason": null
}
}
}
}Status Values:
APPROVED- Template approved and activeREJECTED- Template rejectedPENDING- Under reviewPAUSED- Template pausedDISABLED- Template disabled
Rejection Reasons: When status is REJECTED, reason field contains explanation.
whatsapp.template.quality_updated
Template quality score changed.
Payload Example:
{
"event": {
"type": "whatsapp.template.quality_updated"
},
"data": {
"resource": {
"type": "template_quality",
"attributes": {
"message_template_id": "1234567890",
"message_template_name": "welcome_message",
"message_template_language": "en",
"quality_score": "GREEN",
"previous_quality_score": "YELLOW"
}
}
}
}Quality Scores:
GREEN- High qualityYELLOW- Medium qualityRED- Low quality (at risk)UNKNOWN- Not enough data
Account Events
whatsapp.account.alert
Account alert or warning.
Payload Example:
{
"event": {
"type": "whatsapp.account.alert"
},
"data": {
"resource": {
"type": "account_alert",
"attributes": {
"alert_type": "ACCOUNT_UPDATE",
"description": "Your phone number quality is low",
"severity": "WARNING"
}
}
}
}Alert Types:
ACCOUNT_UPDATE- Account information updatedACCOUNT_REVIEW- Account under reviewBUSINESS_CAPABILITY_UPDATE- Capability changedTEMPLATE_QUALITY_UPDATE- Template quality alert
Severity Levels:
INFO- InformationalWARNING- WarningCRITICAL- Critical issue
whatsapp.account.review_updated
Account review status changed.
Payload Example:
{
"event": {
"type": "whatsapp.account.review_updated"
},
"data": {
"resource": {
"type": "account_review",
"attributes": {
"review_status": "APPROVED",
"previous_status": "PENDING"
}
}
}
}whatsapp.business.capability_updated
Business account capabilities changed.
Payload Example:
{
"event": {
"type": "whatsapp.business.capability_updated"
},
"data": {
"resource": {
"type": "business_capability",
"attributes": {
"capability": "MESSAGE_TEMPLATES",
"status": "AVAILABLE",
"previous_status": "RESTRICTED"
}
}
}
}Capabilities:
MESSAGE_TEMPLATES- Template messagingBUSINESS_INITIATED_CONVERSATIONS- Initiate conversationsUNLIMITED_CONVERSATIONS- No conversation limits
Phone Events
whatsapp.phone.quality_updated
Phone number quality rating changed.
Payload Example:
{
"event": {
"type": "whatsapp.phone.quality_updated"
},
"data": {
"resource": {
"type": "phone_quality",
"attributes": {
"phone_number": "919428735270",
"quality_score": "GREEN",
"previous_quality_score": "YELLOW"
}
}
}
}Quality Scores:
GREEN- High quality (good)YELLOW- Medium quality (warning)RED- Low quality (at risk)UNKNOWN- Not determined
whatsapp.phone.name_updated
Display name updated.
Payload Example:
{
"event": {
"type": "whatsapp.phone.name_updated"
},
"data": {
"resource": {
"type": "phone_name",
"attributes": {
"phone_number": "919428735270",
"display_name": "Acme Corp Support",
"previous_name": "Acme Support"
}
}
}
}Other Events
whatsapp.call.received
Incoming WhatsApp call.
Payload Example:
{
"event": {
"type": "whatsapp.call.received"
},
"data": {
"resource": {
"type": "call",
"id": "call_id_xxx",
"attributes": {
"from": "919876543210",
"timestamp": "1767264000"
}
},
"relationships": {
"contact": {
"wa_id": "919876543210",
"name": "John Doe"
}
}
}
}HTTP Headers
All webhook requests include these headers:
Content-Type: application/json
Accept: application/json
User-Agent: whatsmark-Webhook/1.0
X-Webhook-Signature: <hmac-sha256-signature>
X-Webhook-Event: <event-type>
X-Webhook-Timestamp: <iso-8601-timestamp>
X-Webhook-Format: n8nHeader Details
| Header | Description | Example |
|---|---|---|
X-Webhook-Signature | HMAC-SHA256 signature | a1b2c3... |
X-Webhook-Event | Event type | whatsapp.message.received |
X-Webhook-Timestamp | Event timestamp | 2026-01-01T10:38:48+00:00 |
X-Webhook-Format | Payload format | n8n |
Signature Verification
Algorithm
signature = HMAC-SHA256(payload_json, secret_key)Node.js Implementation
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Usage
const payload = req.body;
const signature = req.headers['x-webhook-signature'];
const secret = process.env.WEBHOOK_SECRET;
if (!verifyWebhookSignature(payload, signature, secret)) {
return res.status(403).json({ error: 'Invalid signature' });
}PHP Implementation
<?php
function verifyWebhookSignature($payload, $signature, $secret) {
$expectedSignature = hash_hmac(
'sha256',
json_encode($payload),
$secret
);
return hash_equals($signature, $expectedSignature);
}
// Usage
$payload = json_decode(file_get_contents('php://input'), true);
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'];
$secret = getenv('WEBHOOK_SECRET');
if (!verifyWebhookSignature($payload, $signature, $secret)) {
http_response_code(403);
echo json_encode(['error' => 'Invalid signature']);
exit;
}Testing
Sample Payloads
Text Message:
{
"event": {
"id": "evt_test_12345",
"type": "whatsapp.message.received",
"timestamp": "2026-01-01T10:00:00Z",
"version": "1.0"
},
"tenant": {
"id": 1,
"name": "Test Company"
},
"data": {
"resource": {
"type": "message",
"id": "wamid.test123",
"attributes": {
"message_id": "wamid.test123",
"from": "1234567890",
"timestamp": "1735728000",
"type": "text",
"text": "Test message",
"context": null
}
},
"relationships": {
"contact": {
"wa_id": "1234567890",
"name": "Test User"
},
"metadata": {
"phone_number_id": "1111111111",
"display_phone_number": "1234567890"
}
}
},
"whatsapp": {
"original_payload": {}
},
"metadata": {
"source": "whatsapp_webhook_forward",
"environment": "test",
"request_id": "test-request-id"
}
}cURL Test Command
curl -X POST https://your-endpoint.com/webhook \
-H "Content-Type: application/json" \
-H "X-Webhook-Event: whatsapp.message.received" \
-H "X-Webhook-Timestamp: 2026-01-01T10:00:00Z" \
-H "X-Webhook-Format: n8n" \
-d '{
"event": {
"id": "evt_test_12345",
"type": "whatsapp.message.received",
"timestamp": "2026-01-01T10:00:00Z",
"version": "1.0"
},
"tenant": {"id": 1, "name": "Test"},
"data": {
"resource": {
"type": "message",
"attributes": {
"text": "Test message"
}
}
}
}'Related Documentation
- WhatsApp Webhook Forwarding Guide - User guide
- N8N Webhook Integration - Tenant events
- Webhook Format Reference - Tenant webhook format