The webhook endpoint allows you to receive incoming WhatsApp messages in real-time. When a message is received, it will be sent to your configured webhook URL with the following payload structure.
Think of it as setting up an automatic forwarding system - whenever someone messages your AI agent on WhatsApp, we’ll immediately forward that message to your specified webhook URL, so your agent can process and respond to it right away.
{
"thread_id" : "chat_123456789" ,
"message_id" : "msg_987654321" ,
"thread_type" : "individual" ,
"sender_number" : "+61400123456" ,
"sender_name" : "Jane" ,
"a1_account_id" : "123-123-123" ,
"a1_phone_number" : "+1415123456" ,
"timestamp" : "2024-12-20T00:48:15+00:00" ,
"service" : "whatsapp" ,
"message_type" : "text" ,
"is_from_agent" : false ,
"message_content" : {
"text" : "Hello world"
}
}
This webhook will receive all incoming messages, including those created using the A1Base API. To prevent infinite loops, you may want to check the sender_number to avoid agents replying to themselves.
Webhook Payload
Unique identifier for the chat thread
Unique identifier for the specific message
Type of chat - can be “group”, “individual”, or “broadcast”
Phone number of the message sender with country code. e.g. “+61400123456”
Name of the message sender
Your A1Base account identifier
Your A1Base account identifier
The A1Base phone number that received the message. e.g. “+61400999888”
When the message was handled on WhatsApp, in ISO 8601 format. e.g. “2024-12-20T00:48:15+00:00”
The messaging service used (e.g. “whatsapp”)
Type of the message. Can be one of: “text”, “rich_text”, “image”, “video”, “audio”, “reaction”, “group_invite”, “location”, “unsupported_message_type”
Whether the message was sent by an agent
The complete message content object containing all message data. Structure varies by message_type: For message_type: “text” (simple text) {
"text" : "Hello world"
}
For message_type: “rich_text” (rich text with optional quote) {
"text" : "This is a reply to something" ,
"quoted_message_content" : "Original message that was replied to" ,
"quoted_message_sender" : "61400123456"
}
For message_type: “image” {
"data" : "base64_encoded_image_data"
}
For message_type: “video” {
"data" : "base64_encoded_video_data"
}
For message_type: “audio” {
"data" : "base64_encoded_audio_data"
}
For message_type: “reaction” For message_type: “group_invite” {
"groupName" : "My WhatsApp Group" ,
"inviteCode" : "Ab12Cd34"
}
For message_type: “location” {
"latitude" : -33.8688 ,
"longitude" : 151.2093 ,
"name" : "Optional location name" ,
"address" : "Optional address"
}
For message_type: “unsupported_message_type” {
"error" : "Unsupported Message Type"
}
HMAC-SHA256 signature used to verify the authenticity of the webhook. Created using your API secret and the timestamp + request body.
Unix timestamp (in seconds) when the webhook was sent. Used to verify the request and prevent replay attacks.
Response Codes
200: Message received successfully
403: Invalid secret key
500: Internal server error
Create an endpoint in your application to receive webhook events:
import express from 'express' ;
import { WhatsAppIncomingData } from 'a1base-node' ;
const app = express ();
app . use ( express . json ());
app . post ( '/whatsapp/incoming' , async ( req , res ) => {
const {
thread_id ,
message_id ,
thread_type ,
sender_number ,
sender_name ,
a1_account_id ,
a1_phone_number ,
timestamp ,
service ,
message_type ,
is_from_agent ,
message_content ,
} = req . body as WhatsAppIncomingData ;
// Process the incoming message
console . log ( `Received message from ${ sender_name } : ${ message_content . text } ` );
// Always respond with 200 to acknowledge receipt
res . json ({ success: true });
});
Deploy your endpoint to a public URL (e.g. using ngrok for testing)
Update your webhook URL on the A1Base dashboard at https://www.a1base.com/dashboard/phone-numbers
For a complete implementation example including message handling and AI responses, see our chat agent example: startLine: 130
endLine: 209
Validate the webhook payload structure matches the expected format
Check the sender_number to avoid infinite loops with your own agent
Use HTTPS endpoints only
Keep your webhook URL private
Implement rate limiting if needed
Add error handling for failed message processing
All webhook requests from A1Base include an x-signature and x-timestamp header.
You can verify the authenticity of each request using your API secret and the HMAC-SHA256 algorithm.
Here’s how the signature is generated on our side:
const message = timestamp + JSON . stringify ( body );
const signature = crypto
. createHmac ( 'sha256' , apiSecret )
. update ( message )
. digest ( 'hex' );
On your server, do the following to verify the signature:
Read the raw JSON body of the request
Get the x-timestamp header
Recreate the message string as timestamp + rawBody
Generate your own HMAC signature with your API secret
Compare it with the x-signature using a constant-time comparison
Example in Express (Node.js) import crypto from 'crypto' ;
import express from 'express' ;
const app = express ();
app . use ( express . json ({
verify : ( req , res , buf ) => {
req . rawBody = buf ; // capture raw body for HMAC check
}
}));
app . post ( '/whatsapp/incoming' , ( req , res ) => {
const rawBody = req . rawBody . toString ();
const timestamp = req . headers [ 'x-timestamp' ];
const receivedSig = req . headers [ 'x-signature' ];
const secret = process . env . A1BASE_API_SECRET ;
const expectedSig = crypto
. createHmac ( 'sha256' , secret )
. update ( timestamp + rawBody )
. digest ( 'hex' );
if ( receivedSig !== expectedSig ) {
return res . status ( 403 ). send ( 'Invalid signature' );
}
// Continue processing the verified request
res . sendStatus ( 200 );
});
Reject any webhook requests with a timestamp older than 5 minutes to prevent replay attacks.
Unique identifier for the chat thread
Unique identifier for the specific message
Available options:
group,
individual,
broadcast
Phone number of the message sender
Name of the message sender
Your A1Base account identifier
A timestamp in ISO 8601 format
Available options:
whatsapp,
telegram
Available options:
text,
image,
video,
audio,
document
Whether the message is from an agent
Structured message content
Message received successfully