RCS Webhooks
EnableX posts real-time HTTP notifications to your configured webhook URL for every RCS event — incoming messages, delivery status changes, template approvals, user interactions with suggestions, and typing indicators. Your webhook processes these notifications to drive business logic, update delivery dashboards, and respond to users.
Each RCS project needs a webhook URL configured in the EnableX Portal. All notifications arrive as JSON payloads in the HTTP request body.
Webhook Setup Requirements
Your webhook server must meet the following requirements to receive notifications:
HTTPS Host — Your webhook URL must use HTTPS. Plain HTTP endpoints are not supported.
Valid TLS/SSL Certificate — A valid certificate issued by a trusted Certificate Authority is required. Self-signed certificates are not accepted.
Raw Body Parsing — JSON payloads are delivered as raw HTTP body content. Your server must parse the raw body directly — not as form-encoded data.
Securing Your Webhook — HTTP Basic Authentication
EnableX supports HTTP Basic Authentication for RCS webhook delivery. When enabled, EnableX includes your credentials in every webhook POST so your server can verify the request is genuinely from EnableX before processing the payload.
To enable this, check the HTTP Authentication checkbox in the webhook configuration screen in the EnableX Portal and enter a username and password. EnableX will include these credentials in the Authorization header of every RCS notification sent to your endpoint.
Your webhook URL must be publicly reachable over HTTPS. During local development, use a tunnelling tool such as ngrok http 3000 to expose your local server, then paste the generated HTTPS URL into the portal.
Acknowledging Webhook Notifications
Your webhook endpoint MUST return an HTTP 200 status code to confirm successful receipt of every notification. This acknowledgement must be sent in the same HTTP connection.
If your server does not return HTTP 200, the RBM platform treats the delivery as unacknowledged. Unacknowledged events may be retried, and persistent failures may cause the platform to stop delivering notifications to your endpoint.
200 immediately — before processing business logic. Queue the payload internally and process it asynchronously. This ensures you acknowledge within the connection timeout.
Below is a minimal webhook handler in PHP, Node.js, and Python demonstrating the mandatory HTTP 200 acknowledgement:
<?php
// Read the incoming JSON payload
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
// Process the webhook data (your business logic here)
// ...
// MANDATORY: Return HTTP 200 to acknowledge receipt
header("HTTP/1.1 200 OK");
?>
// Node.js / Express
app.post('/webhook/rcs', (req, res) => {
const data = req.body;
// Process the webhook data (your business logic here)
// ...
// MANDATORY: Return HTTP 200 to acknowledge receipt
res.status(200).send('OK');
});
# Python / Flask
@app.route('/webhook/rcs', methods=['POST'])
def rcs_webhook():
data = request.get_json()
# Process the webhook data (your business logic here)
# ...
# MANDATORY: Return HTTP 200 to acknowledge receipt
return 'OK', 200
Webhook Notification Types
The following notification types are posted to your webhook. Each section below explains when the notification is triggered, the JSON payload structure, and what your server should do upon receiving it.
| Notification Type | Trigger | type Value |
|---|---|---|
| Incoming Text Message | User sends a text message to your business | text |
| Incoming File Message | User sends an image, video, or document | file |
| Delivery Status Update | Outgoing message status changes (SENT, DELIVERED, READ, FAILED, REVOKED) | message |
| Template Status Update | Template is approved or rejected by RBM | template |
| Suggestion Response | User taps a suggested reply or suggested action | suggestion |
| Location Sharing | User shares a location (via share_location suggestion) | location |
| User Typing | User starts typing a response | typing |
Incoming Messages
When a user sends a message to your business, it arrives on your webhook as an incoming message notification. The type field indicates the content type.
Standard Incoming Message Format
All incoming messages share a common structure with type-specific fields appended:
{
"agent": "your-agent-name",
"phone": "+919876543210",
"request_id": "req_abc123",
"session_id": "sess_xyz789",
"type": "text | file | suggestion | location",
"timestamp": "2025-03-15T10:30:00.000Z"
}
| Key | Type | Description |
|---|---|---|
agent | String | Your RBM Agent name |
phone | String | User's phone number with country code |
request_id | String | Unique identifier for this incoming message. Use this to mark the message as read or send a typing indicator |
session_id | String | Session ID for the conversation thread |
type | String | Content type: text, file, suggestion, or location |
timestamp | String | UTC timestamp (YYYY-MM-DDTHH:II:SS.000Z) |
Incoming Text Message
Triggered when a user sends a free-form text message to your business.
{
"agent": "your-agent-name",
"phone": "+919876543210",
"request_id": "req_abc123",
"session_id": "sess_xyz789",
"type": "text",
"text": "I want to check my order status",
"timestamp": "2025-03-15T10:30:00.000Z"
}
| Key | Type | Description |
|---|---|---|
type | String | "text" |
text | String | The plain text message content |
Incoming File Message
Triggered when a user sends an image, video, or document file.
{
"agent": "your-agent-name",
"phone": "+919876543210",
"request_id": "req_def456",
"session_id": "sess_xyz789",
"type": "file",
"file": {
"media": "image",
"image": {
"mimeType": "image/jpeg",
"fileSizeBytes": 245760,
"fileUri": "https://storage.rbm.example.com/files/abc123.jpg",
"fileName": "receipt.jpg"
}
},
"timestamp": "2025-03-15T10:31:00.000Z"
}
The file object structure:
| Key | Type | Description |
|---|---|---|
file.media | String | Media category: image, video, or document |
file.{media} | Object | Named after the media value (e.g., file.image when media is "image") |
mimeType | String | MIME type of the file (e.g., image/jpeg) |
fileSizeBytes | Number | File size in bytes |
fileUri | String | URL to download the file |
fileName | String | Original filename |
file.media value. If file.media is "video", the detail object key is file.video (not file.image).
Delivery Status Notifications
When your business sends an outgoing message, its delivery status changes over time as it moves through the RBM platform. Every status change is posted to your webhook so you can track the message lifecycle.
Message Status Lifecycle
| Status | Description |
|---|---|
SENT | Message has been queued for sending by the RBM platform |
DELIVERED | Message has been delivered to the user's device |
READ | User has opened and read the message |
FAILED | RBM failed to deliver the message. The failure_reason field provides details |
REVOKED | Message was withdrawn from the queue — either by your revoke API call, or because ttl/expire_time elapsed |
Delivery Notification Payload
{
"phone": "+919876543210",
"agent": "your-agent-name",
"type": "message",
"message": {
"message_id": "msg_abc123def456",
"status": "DELIVERED",
"failure_reason": ""
},
"timestamp": "2025-03-15T10:30:05.000Z"
}
| Key | Type | Description |
|---|---|---|
type | String | "message" — indicates a delivery status notification |
message.message_id | String | The message_id returned when you originally sent the message |
message.status | String | SENT, DELIVERED, READ, FAILED, or REVOKED |
message.failure_reason | String | Present only when status is FAILED. Describes the reason for delivery failure |
timestamp | String | UTC timestamp of the status change |
200 to acknowledge every delivery notification. Track the message_id and status progression to maintain an accurate delivery dashboard.
Template Status Notifications
When you submit a template for RBM approval, the review process typically completes within minutes to 24 hours. When the template status changes (approved or rejected), a notification is posted to your webhook.
Template Notification Payload
{
"agent": "your-agent-name",
"type": "template",
"template": {
"name": "order_update",
"status": "approved",
"type": "text",
"comment": "Ok"
},
"timestamp": "2025-03-15T12:00:00.000Z"
}
| Key | Type | Description |
|---|---|---|
type | String | "template" — indicates a template status notification |
template.name | String | The unique template name you assigned during creation |
template.status | String | approved or rejected |
template.type | String | Template content type: text, card, or carousel |
template.comment | String | Review comment. For approved templates, this is typically "Ok". For rejected templates, it explains the rejection reason |
200 to acknowledge every template status notification.
Suggestion Interaction Webhooks
When a user taps a suggested reply or performs a suggested action, the interaction details are posted to your webhook. These notifications let your business logic respond to user choices in real time.
Suggested Reply Response
Triggered when a user taps a suggested reply button. Your webhook receives the postback and text values you defined when sending the suggestion.
{
"agent": "your-agent-name",
"phone": "+919876543210",
"request_id": "req_ghi789",
"session_id": "sess_xyz789",
"type": "suggestion",
"suggestion": {
"type": "reply",
"postback": "booking_confirmed_12345",
"text": "Confirm Booking"
},
"timestamp": "2025-03-15T10:32:00.000Z"
}
| Key | Type | Description |
|---|---|---|
suggestion.type | String | "reply" — the user tapped a suggested reply |
suggestion.postback | String | The postback value you set when creating the suggestion |
suggestion.text | String | The display text of the suggestion the user tapped |
Suggested Action Response
Triggered when a user performs a suggested action (opens a URL, dials a number, etc.). The structure is identical to the reply response, except suggestion.type is "action".
{
"agent": "your-agent-name",
"phone": "+919876543210",
"request_id": "req_jkl012",
"session_id": "sess_xyz789",
"type": "suggestion",
"suggestion": {
"type": "action",
"postback": "buy_headphones",
"text": "Buy Now"
},
"timestamp": "2025-03-15T10:33:00.000Z"
}
Location Sharing Response
Triggered when a user shares a location (in response to a share_location suggestion). The payload includes latitude and longitude coordinates.
{
"agent": "your-agent-name",
"phone": "+919876543210",
"request_id": "req_mno345",
"session_id": "sess_xyz789",
"type": "location",
"location": {
"latitude": "28.4595",
"longitude": "77.0266"
},
"timestamp": "2025-03-15T10:34:00.000Z"
}
| Key | Type | Description |
|---|---|---|
location.latitude | String | Latitude of the shared location |
location.longitude | String | Longitude of the shared location |
200 to acknowledge every suggestion interaction and location sharing notification.
Miscellaneous Events
User Typing Notification
When a user starts typing a response during an active conversation, your webhook receives a typing indicator notification. Use this to trigger business-side actions like preparing a response or displaying a typing indicator back to the user.
{
"agent": "your-agent-name",
"phone": "+919876543210",
"message_id": "msg_typ789",
"type": "typing",
"timestamp": "2025-03-15T10:35:00.000Z"
}
| Key | Type | Description |
|---|---|---|
type | String | "typing" — user is typing a message |
message_id | String | Message identifier associated with the typing event |
POST /rcs/v1/indicators/typing. This creates a responsive conversational experience.
200 to acknowledge typing notifications.
Webhook Best Practices
Acknowledge immediately. Return HTTP 200 before processing any business logic. Queue the payload and handle it asynchronously.
Handle duplicates. In rare cases, a notification may be delivered more than once. Use message_id or request_id as an idempotency key to avoid processing duplicates.
Log all events. Store the complete JSON payload for every webhook notification. This provides an audit trail for debugging delivery issues and tracking conversation flows.
Route by type. Use the top-level type field to route notifications to the appropriate handler: text and file for incoming messages, message for delivery updates, template for approval status, suggestion for user interactions, location for shared locations, and typing for typing indicators.