Insider One processes the messages you have sent by queuing them and prioritizing them according to the number of messages that can be sent per second. Therefore, when you send the message to Insider One, you will get a return with a tracking key. This tracking key will be included in all webhook events of the message you sent.
To define your webhook address and token, refer to the Save Webhook URL step.
Your queued messages are processed and forwarded to WhatsApp. If your message is successfully accepted by WhatsApp, a message like the one below will be sent to your webhook address:
Parameter | Description | Data Type | Required |
|---|---|---|---|
messaging_product | String | Yes | |
contacts | Contact information | Array | Yes |
input | User's phone number | String | Yes |
wa_id | The customer's WhatsApp ID. A business can respond to a message using this ID. | String | Yes |
messages | Array | Yes | |
id | The ID for the message that was received by the business. You could use the messages endpoint to mark this specific message as read. | String | Yes |
Key | Message tracking key, created by Insider One | String | Yes |
{
"messaging_product": "whatsapp",
"contacts": [
{
"input": "{{USER_PHONE_NUMBER}}",
"wa_id": "{{WHATSAPP_ID}}"
}
],
"messages": [
{
"id": "{{MESSAGE_ID}}"
}
],
"key": "whatsapp-***********"
}If any error is received from WhatsApp related to your message, a message like the one below will be sent to your webhook by Insider One.
Parameter | Description | Data Type | Required |
|---|---|---|---|
error | The object that contains information about the error | Object | Yes |
message | Error code message, such as Rate limit hit. Note that the message property in API error response payloads pre-pends this value with a # symbol and the error code in parentheses, such as (#130429) Rate limit hit. | String | Yes |
type | Error type | String | Yes |
code | Error code | Integer | Yes |
fbtrace_id | Trace ID you can include when contacting Direct Support. The ID might be useful to debug the error. | String | Yes |
Key | Message tracking key, created by Insider One | String | Yes |
{
"error": {
"message": "{{ERROR_MESSAGE}}",
"type": "{{ERROR_TYPE}}",
"code": {{ERROR_CODE}},
"fbtrace_id": "{{FBTRACE_ID}}"
},
"key": "whatsapp-***********"
}Sample Error Codes
When you send WhatsApp messages via Insider One, any errors returned from WhatsApp (Cloud API or On-Premise) are forwarded to your webhook. Below are sample error responses you may encounter, grouped by category.
Important Note on
error_dataThe
error_datafield is optional. Meta may include it for some errors to provide additional context (for example, message throughput details) and omit it for others. Always rely on the code and message fields as the primary source of information, and treaterror_dataas supplementary metadata when available.Below you can see a sample error response with the
error_datafield included:{ "error": { "message": "(#130429) Rate limit hit", "type": "OAuthException", "code": 130429, "error_data": { "messaging_product": "whatsapp", "details": "Cloud API message throughput reached." } } }
Cloud API Error Codes
The following are sample error responses you might receive when using the WhatsApp Cloud API via Insider One.
Failure response
{
"message": "failed to validate the webhook",
"errorCode": "2020"
}Success response (HTTP 200)
{
"message": "Settings updated successfully"
}Authorization Errors
{
"error": {
"message": "We were unable to authenticate the app user",
"type": "OAuthException",
"code": 0
}
}{
"error": {
"message": "Your access token has expired",
"type": "OAuthException",
"code": 190
}
}Rate Limiting Errors
{
"error": {
"message": "(#130429) Rate limit hit",
"type": "OAuthException",
"code": 130429,
"error_data": {
"messaging_product": "whatsapp",
"details": "Cloud API message throughput reached."
}
}
}{
"error": {
"message": "Spam rate limit hit",
"code": 131048,
"error_data": {
"messaging_product": "whatsapp",
"details": "Too many messages sent from this phone number in a short period of time."
}
}
}Account and Permission Errors
{
"error": {
"message": "Access denied",
"code": 131005
}
}{
"error": {
"message": "Account has been blocked for policy violations",
"code": 368
}
}On-Premise API Error Codes
The following are sample error responses you might receive when using the WhatsApp On-Premise API via Insider One.
Client Errors (400-499)
{
"errors": [
{
"code": 402,
"title": "Business eligibility issue",
"details": "Payment issue preventing message delivery"
}
]
}{
"errors": [
{
"code": 408,
"title": "Message not valid",
"details": "Message has been pending validation too long"
}
]
}{
"errors": [
{
"code": 429,
"title": "Rate limit exceeded",
"details": "Too many requests in a given amount of time"
}
]
}Template Errors
{
"errors": [
{
"code": 2000,
"title": "Template parameter mismatch",
"details": "Number of parameters provided does not match expected parameter count"
}
]
}{
"errors": [
{
"code": 2060,
"title": "Template rejected",
"details": "Template has been rejected and cannot be used"
}
]
}Server Error (500)
{
"errors": [
{
"code": 500,
"title": "Internal server error",
"details": "Temporary server issue, please retry"
}
]
}Refer to Failed Event for the webhook payload structure where these errors are returned.
Refer to Meta’s Error Codes guide for further information.
Save Webhook URL
You can define your webhook address and token.
Headers
Header | Sample Value | Description |
|---|---|---|
X-INS-AUTH-KEY | 1a2b3c4d5e6f | This key is required to authorize your request. Refer to API Authentication Tokens to generate your token. |
Content-Type | application/json | This header specifies the media type of the resource. |
The Body Parameters
Parameter | Description | Data Type | Required |
|---|---|---|---|
isActive | Option to turn on transactional message sending. | Boolean | Yes |
url | Your webhook URL | String | Yes |
apiKey | Your webhook Bearer token | String | Yes |
Sample Request
curl --location 'https://whatsapp.useinsider.com/v1/conversational/settings/update' \
--header 'Content-Type: application/json' \
--header 'x-ins-auth-key: INS.**************************************' \
--data '{
"isActive": true,
"webhookUrl": "{{YOUR_WEBHOOK_URL}}",
"apiKey": "{{YOUR_WEBHOOK_BEARER_TOKEN_KEY}}"
}'Your system must respond with a 200 OK status to our request for the webhook to be saved and function correctly. If you receive any response other than 200 from the settings endpoint, it indicates an issue with the URL you provided. Please review the error message returned and verify your endpoint accordingly.
Sent/Read/Delivered Events
Parameter | Description | Data Type | Required |
|---|---|---|---|
entry[0].changes[0].value.metadata.display_phone_number | The phone number that is displayed for a business | String | Yes |
entry[0].changes[0].value.metadata.display_phone_number_id | ID for the phone number. A business can respond to a message using this ID. | String | Yes |
entry[0].changes[0].value.statuses[0].id | The ID for the message that was received by the business. You could use the messages endpoint to mark this specific message as read. | String | Yes |
entry[0].changes[0].value.statuses[0].recipient_id | The WhatsApp ID for the customer of the business, which is subscribed to the webhooks, sent to the customer | String | Yes |
entry[0].changes[0].value.statuses[0].status | read/sent/delivered | String | Yes |
key | Message tracking key, created by Insider One | String | Yes |
{
"entry": [
{
"changes": [
{
"field": "messages",
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{{SENDER_PHONE_NUMBER}}",
"phone_number_id": "{{SENDER_PHONE_NUMBER_ID}}"
},
"statuses": [
{
"id": "{{MESSAGE_ID}}",
"recipient_id": "{{PHONE_NUMBER}}",
"status": "{{STATUS}}",
"timestamp": "1111111111"
}
]
}
}
],
"id": "111111111"
}
],
"key": "whatsapp-***********",
"object": "whatsapp_business_account"
}Template Message Webhook Events
Insider One now helps you identify which template message triggered a chatbot. Each time a template message is sent, Insider One forwards the template information to your defined webhook. This lets you match chatbot responses with the right template inside your system.
Regardless of how the message content is triggered (whether through single, transactional, etc., via InOne), all messages classified as template message types will be transmitted to the previously defined webhook URL.
The content sent will generally mirror the message sending content dispatched to Meta, with the following additions based on your request:
timestamp: Indicates the exact time the message was sent to Meta.
content: Contains the template's message content.
Refer to Send Conversational WhatsApp Template Messages to Chatbot Systems for further information.
Failed Event
Parameter | Description | Data Type | Required |
|---|---|---|---|
entry[0].changes[0].value.metadata.display_phone_number | The phone number that is displayed for a business | String | Yes |
entry[0].changes[0].value.metadata.display_phone_number_id | ID for the phone number. A business can respond to a message using this ID. | String | Yes |
entry[0].changes[0].value.statuses[0].id | The ID for the message that was received by the business. You could use the messages endpoint to mark this specific message as read. | String | Yes |
entry[0].changes[0].value.statuses[0].recipient_id | The WhatsApp ID for the customer that the business, that is subscribed to the webhooks, sent to the customer | String | Yes |
entry[0].changes[0].value.statuses[0].status | failed | String | Yes |
entry[0].changes[0].value.statuses[0].errors | Array | Yes | |
code | Error code. Integer Example: 130429 | Integer | Yes |
title | Error code title Example: Rate limit hit | String | Yes |
href | Document link with description of the error | String | Yes |
key | Message tracking key, created by Insider One | String | Yes |
Delivery Report Missing refers to messages for which no delivery report is received from Meta. Since Meta does not send any events for these error messages, they are not delivered to you through either the Transactional API or the Conversational API.
{
"key": "whatsapp-**************",
"object": "whatsapp_business_account",
"entry": [
{
"id": "1231313123",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{{SENDER_PHONE_NUMBER}}",
"phone_number_id": "{{SENDER_PHONE_NUMBER_ID}}"
},
"statuses": [
{
"id": "{{MESSAGE_ID}}",
"status": "failed",
"timestamp": "1671526301",
"recipient_id": "RECIPIENT_ID",
"errors": [
{
"code": {{ERROR_CODE}},
"title": "{{ERROR_MESSAGE}}",
"href": "https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/"
}
]
}
]
},
"field": "messages"
}
]
}
]
}User Reply with Text Event
Parameter | Description | Data Type | Required |
|---|---|---|---|
entry[0].changes[0].value.metadata.display_phone_number | The phone number that is displayed for a business | String | Yes |
entry[0].changes[0].value.metadata.display_phone_number_id | ID for the phone number. A business can respond to a message using this ID. | String | Yes |
entry[0].changes[0].value.messages[0].from | The WhatsApp ID for the customer who replied to an inbound message | String | Yes |
entry[0].changes[0].value.messages[0].id | The message ID for the sent message for an inbound reply | String | Yes |
entry[0].changes[0].value.messages[0].text.body | User’s reply | String | Yes |
key | Message tracking key, created by Insider One. | String | Yes |
{
"key": "whatsapp-******************", // be empty
"object": "whatsapp_business_account",
"entry": [
{
"id": "1231313123",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{{PHONE_NUMBER}}",
"phone_number_id": "{{PHONE_NUMBER_ID}}"
},
"contacts": [
{
"profile": {
"name": "Insider"
},
"wa_id": "{{PHONE_NUMBER}}"
}
],
"messages": [
{
"from": "{{PHONE_NUMBER}}",
"id": "{{MESSAGE_ID}}",
"timestamp": "111111111",
"text": {
"body": "{{MESSAGE_BODY}}"
},
"type": "text"
}
]
},
"field": "messages"
}
]
}
]
}User Reply With Sticker Example
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "105710252456442",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{{PHONE_NUMBER}}",
"phone_number_id": "{{PHONE_NUMBER_ID}}"
},
"contacts": [
{
"profile": {
"name": "Insider"
},
"wa_id": "{{PHONE_NUMBER}}"
}
],
"messages": [
{
"from": "393336188770",
"id": "{{MESSAGE_ID}}",
"timestamp": "1678889298",
"type": "sticker",
"sticker": {
"mime_type": "image/webp",
"sha256": "{{ENCODED_STICKER}}",
"id": "{{STICKER_ID}}",
"animated": true
}
}
]
},
"field": "messages"
}
]
}
]
}User Reply With Video Example
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "105710252456442",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{{PHONE_NUMBER}}",
"phone_number_id": "{{PHONE_NUMBER_ID}}"
},
"contacts": [
{
"profile": {
"name": "Insider"
},
"wa_id": "{{PHONE_NUMBER}}"
}
],
"messages": [
{
"from": "393336188770",
"id": "{{MESSAGE_ID}}",
"timestamp": "1678889564",
"type": "video",
"video": {
"mime_type": "video/mp4",
"sha256": "{{ENCODED_VIDEO}}",
"id": "{{VIDEO_ID}}"
}
}
]
},
"field": "messages"
}
]
}
]
}User Reply With Image Example
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "105710252456442",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{{PHONE_NUMBER}}",
"phone_number_id": "{{PHONE_NUMBER_ID}}"
},
"contacts": [
{
"profile": {
"name": "Insider"
},
"wa_id": "{{PHONE_NUMBER}}"
}
],
"messages": [
{
"from": "393336188770",
"id": "{{MESSAGE_ID}}",
"timestamp": "1678889571",
"type": "image",
"image": {
"mime_type": "image/jpeg",
"sha256": "{{ENCODED_IMAGE}}",
"id": "{{IMAGE_ID}}"
}
}
]
},
"field": "messages"
}
]
}
]
}User Reply With Document Example
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "105710252456442",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{{PHONE_NUMBER}}",
"phone_number_id": "{{PHONE_NUMBER_ID}}"
},
"contacts": [
{
"profile": {
"name": "Insider"
},
"wa_id": "{{PHONE_NUMBER}}"
}
],
"messages": [
{
"from": "393336188770",
"id": "{{MESSAGE_ID}}",
"timestamp": "1678889577",
"type": "document",
"document": {
"filename": "doc.pdf",
"mime_type": "application/pdf",
"sha256": "{{ENCODED_DOCUMENT}}",
"id": "{{DOCUMENT_ID}}"
}
}
]
},
"field": "messages"
}
]
}
]
}User Reply with Button Event
Parameter | Description | Data Type | Required |
|---|---|---|---|
entry[0].changes[0].value.metadata.display_phone_number | The phone number that is displayed for a business | String | Yes |
entry[0].changes[0].value.metadata.display_phone_number_id | ID for the phone number. A business can respond to a message using this ID. | String | Yes |
entry[0].changes[0].value.messages[0].from | The WhatsApp ID for the customer who replied to an inbound message | String | Yes |
entry[0].changes[0].value.messages[0].id | The message ID for the sent message for an inbound reply | String | Yes |
entry[0].changes[0].value.messages[0].button.body | Button text that is returned when the button is clicked, in addition to the display text on the button | String | Yes |
entry[0].changes[0].value.messages[0].button.payload | A developer-defined payload that is returned when the button is clicked, in addition to the display text on the button | String | Yes |
key | Message tracking key, created by Insider One | String | Yes |
{
"key": "whatsapp-**************",
"object": "whatsapp_business_account",
"entry": [
{
"id": "1231313123",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "{{PHONE_NUMBER}}",
"phone_number_id": "{{PHONE_NUMBER_ID}}"
},
"contacts": [
{
"profile": {
"name": "Insider"
},
"wa_id": "{{PHONE_NUMBER}}"
}
],
"messages": [
{
"context": {
"from": "{{PHONE_NUMBER}}",
"id": "MESSAGE_ID"
},
"from": "{{PHONE_NUMBER}}",
"id": "{{MESSAGE_ID}}",
"timestamp": "1111111",
"type": "button",
"button": {
"payload": "{{BUTTON_PAYLOAD}}",
"text": "{{BUTTON_TEXT}}"
}
}
]
},
"field": "messages"
}
]
}
]
}Manage Multiple WhatsApp Webhooks with OAuth 2.0
You can use the V2 WhatsApp Webhook API to list, create, update, and delete OAuth 2.0-authenticated webhooks for a sender. This version is designed for integrations that want Insider One to authenticate outbound webhook delivery by using OAuth 2.0 credentials.
All examples below use a dummy sender phone number
15551234567. Replace it with your own sender number when you go live.
Important
The OAuth token generation request uses snake_case fields such as
client_idandclient_secret. The webhook CRUD request bodies use camelCase fields such asauthType,webhookUrl,grantType, andclientId.
Required OAuth 2.0 Scopes
Scope | Description |
|---|---|
wa-webhook-read | Allows you to list OAuth 2.0 webhooks and inspect their details. |
wa-webhook-manage | Allows you to create new OAuth 2.0 webhooks. |
wa-webhook-update | Allows you to update existing OAuth 2.0 webhooks. |
wa-webhook-delete | Allows you to delete existing OAuth 2.0 webhooks. |
Generate an OAuth Access Token
Before calling the V2 webhook endpoints, generate a Gateway access token. Notice that this request uses snake_case field names.
curl --location 'https://gw.useinsider.com/auth/token' \
--header 'Content-Type: application/json' \
--data '{
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"scopes": ["wa-webhook-read", "wa-webhook-manage", "wa-webhook-update", "wa-webhook-delete"]
}'Endpoint Overview
Operation | Method | Endpoint | Description |
|---|---|---|---|
List OAuth 2.0 webhooks | GET | https://gw.useinsider.com/api/wa/v2/webhooks?phoneNumber=15551234567 | Returns only OAuth 2.0 webhook records for the sender. |
Create OAuth 2.0 webhook | POST | https://gw.useinsider.com/api/wa/v2/webhooks?phoneNumber=15551234567 | Creates a new OAuth 2.0 webhook. |
Update OAuth 2.0 webhook | PUT | https://gw.useinsider.com/api/wa/v2/webhooks/84?phoneNumber=15551234567 | Updates an existing OAuth 2.0 webhook. |
Delete OAuth 2.0 webhook | DELETE | https://gw.useinsider.com/api/wa/v2/webhooks/84?phoneNumber=15551234567 | Soft deletes the selected OAuth 2.0 webhook. |
Authentication
All V2 webhook CRUD requests must include a bearer token returned by the Gateway Auth API.
Authorization: Bearer your-oauth2-token
Field Naming Reference
Flow | Example Fields | Expected Style |
|---|---|---|
Token generation request |
| snake_case |
Webhook CRUD request body |
| camelCase |
Create Webhook Request Body
Field | Type | Required | Description |
|---|---|---|---|
authType | String | Yes | Must be |
subProduct | String | Yes | Accepted values are |
webhookUrl | String | Yes | The destination endpoint that will receive webhook events. |
events | Array[String] | Yes | Supported values are |
oauth2.grantType | String | Yes | Accepted values are |
oauth2.tokenUrl | String | Yes | Your token endpoint used to fetch an access token for outbound delivery. |
oauth2.clientId | String | Yes | The OAuth 2.0 client identifier used for outbound webhook delivery. |
oauth2.clientSecret | String | Yes | The client secret used for outbound webhook delivery. |
oauth2.refreshToken | String | Required for | Only required when |
oauth2.scopes | Array[String] | No | The scopes Insider should send to your OAuth 2.0 token endpoint. |
oauth2.expiresIn | Integer | Yes | The token lifetime in seconds. |
Important: If subProduct is conversational, the reply event must be included in the events array.
List Webhooks
curl --location 'https://gw.useinsider.com/api/wa/v2/webhooks?phoneNumber=15551234567' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-oauth2-token'Sample Response
{
"webhooks": [
{
"id": 84,
"subProduct": "conversational",
"webhookUrl": "https://partner.example.com/whatsapp/webhooks/conversational",
"events": [
"reply",
"read"
],
"isActive": true,
"authType": "oauth2",
"oauth2": {
"grantType": "client_credentials",
"tokenUrl": "https://partner.example.com/oauth/token",
"clientId": "partner-whatsapp-client",
"clientSecret": "partner-whatsa********",
"scopes": [
"whatsapp.read",
"whatsapp.write"
],
"expiresIn": 3600
},
"createdAt": "2026-04-15T12:45:00Z"
}
]
}Create Webhook
This example uses the client_credentials grant type. Notice that the CRUD body uses camelCase field names.
curl --location 'https://gw.useinsider.com/api/wa/v2/webhooks?phoneNumber=15551234567' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-oauth2-token' \
--data '{
"authType": "oauth2",
"subProduct": "conversational",
"webhookUrl": "https://partner.example.com/whatsapp/webhooks/conversational",
"events": ["sent", "delivered", "failed"],
"oauth2": {
"grantType": "client_credentials",
"tokenUrl": "https://partner.example.com/oauth/token",
"clientId": "partner-whatsapp-client",
"clientSecret": "partner-whatsapp-secret",
"scopes": ["whatsapp.read", "whatsapp.write"],
"expiresIn": 3600
}
}'Sample Response
{
"status": true,
"webhook": 84
}Create a Webhook with refresh_token
If your OAuth 2.0 server requires the refresh_token grant type, include refreshToken in the request body.
{
"authType": "oauth2",
"subProduct": "conversational",
"webhookUrl": "https://partner.example.com/whatsapp/webhooks/conversational",
"events": ["sent", "delivered", "failed"],
"oauth2": {
"grantType": "refresh_token",
"tokenUrl": "https://partner.example.com/oauth/token",
"clientId": "partner-whatsapp-client",
"clientSecret": "partner-whatsapp-secret",
"refreshToken": "partner-refresh-token",
"scopes": ["whatsapp.read", "whatsapp.write"],
"expiresIn": 3600
}
}Update Webhook
Do not send subProduct in the update body. Keep using camelCase field names for all nested OAuth 2.0 fields.
curl --location --request PUT 'https://gw.useinsider.com/api/wa/v2/webhooks/84?phoneNumber=15551234567' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-oauth2-token' \
--data '{
"authType": "oauth2",
"webhookUrl": "https://partner.example.com/whatsapp/webhooks/conversational-v2",
"events": ["sent", "delivered", "read", "failed"],
"oauth2": {
"grantType": "client_credentials",
"tokenUrl": "https://partner.example.com/oauth/token",
"clientId": "partner-whatsapp-client",
"clientSecret": "partner-whatsapp-secret-updated",
"scopes": ["whatsapp.read", "whatsapp.write"],
"expiresIn": 3600
}
}'Sample Response
{
"status": true,
"webhook": 84
}Delete Webhook
curl --location --request DELETE 'https://gw.useinsider.com/api/wa/v2/webhooks/84?phoneNumber=15551234567' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-oauth2-token'Sample Response
{
"status": true
}Error Responses
Scenario | Status Code | Sample Message |
|---|---|---|
The sender's phone number is missing. | 400 |
|
The request body uses an unsupported auth type. | 400 |
|
The webhook URL already exists for the selected API type. | 400 |
|
The sender cannot be matched to a provider. | 404 |
|
Best Practices
Keep snake_case only for the token generation request and camelCase for the webhook CRUD request bodies.
Store the returned webhook ID so you can update or delete the same record later.
Use dedicated OAuth 2.0 credentials for each environment whenever possible.
Validate the sender number and webhook URL values before moving your integration to production.