API Reference

Payloads & Signature

Payload field reference and HMAC verification for inbound webhook deliveries.

Message event payload

Used by message.received, message.sent, message.delivered, message.read, and message.failed.

message.received — example
{
  "event": "message.received",
  "timestamp": "2026-07-10T12:00:00+03:00",
  "data": {
    "message_id": 300541,
    "whatsapp_message_id": "3EB0XXXX",
    "conversation_id": 20717,
    "account_id": 74,
    "channel_id": 74,
    "device_id": "8_abc123xyz",
    "channel_type": "device",
    "direction": "inbound",
    "status": "unknown",
    "message_type": "text",
    "text": "Hello from WhatsApp",
    "media_url": null,
    "sender_phone": "966500000000",
    "contact": {
      "id": 4821,
      "name": "Ahmed Ali",
      "phone": "966500000000"
    },
    "sent_at": "2026-07-10T12:00:00+03:00",
    "timestamp": "2026-07-10T12:00:00+03:00",
    "updated_at": "2026-07-10T12:00:00+03:00"
  }
}
FieldTypeDescription
message_id integer Internal Washeej message ID.
whatsapp_message_id string WhatsApp message ID when available.
conversation_id integer Conversation this message belongs to.
account_id integer WhatsApp account (channel) ID.
channel_id integer Same as account_id — channel identifier.
device_id string|null GOWA/device instance ID (Device channels only).
channel_type string cloud or device.
direction string inbound or outbound.
status string sent, delivered, read, failed, or unknown.
message_type string text, image, video, audio, document, location, contact, sticker.
text string|null Message body or media caption.
media_url string|null Public URL to download media when message_type is not text.
sender_phone string|null E.164-style phone number of the contact.
contact object|null id, name, phone — contact profile when available.
sent_at ISO 8601 When the message was sent/received.
timestamp ISO 8601 Same as sent_at.
updated_at ISO 8601 Last update time (e.g. status change).

Device connection payload

Used by device.connected, device.disconnected, and device.status_changed. The device.status_changed event fires on every connection-status transition for any channel type (including Cloud/Coexistence) and carries from_status / to_status; device.connected / device.disconnected remain Device/QR-only for backward compatibility.

FieldTypeDescription
account_id integer WhatsApp account ID.
device_id string|null GOWA/device instance identifier (null for Cloud channels).
channel_type string device, cloud, or coexistence.
status string New connection status constant.
from_status string|null Previous connection status (device.status_changed).
to_status string New connection status — same as status (device.status_changed).
phone_number string|null Linked WhatsApp phone number.
business_name string|null Display name of the channel.

HTTP headers

HeaderDescription
Content-Typeapplication/json
User-AgentWasheej-Webhook/1.0
X-Washeej-EventSame as body event field
X-Washeej-Signaturesha256=<HMAC-SHA256 hex> of the raw JSON body
X-Washeej-Webhook-IdYour webhook endpoint ID
X-Washeej-Delivery-IdUnique delivery log ID for debugging and resend
X-Washeej-TimestampUnix timestamp when the delivery was sent
Deprecated header Older docs referenced X-Webhook-Signature. Use X-Washeej-Signature for all new integrations.

Signature verification

  1. Read the raw request body as a string (before JSON parsing).
  2. Compute HMAC-SHA256 of the body using your webhook secret.
  3. Compare with the header value after removing the sha256= prefix.
  4. Use timing-safe comparison (e.g. hash_equals in PHP).
PHP
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WASHEEJ_SIGNATURE'] ?? '';
$secret    = 'whsec_your_secret';

$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$data = json_decode($payload, true);
// Process $data['event'] and $data['data']

Respond with HTTP 2xx within the timeout window. Non-2xx responses trigger retries.