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.

Development Testing

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.

Important: Return HTTP 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 TypeTriggertype Value
Incoming Text MessageUser sends a text message to your businesstext
Incoming File MessageUser sends an image, video, or documentfile
Delivery Status UpdateOutgoing message status changes (SENT, DELIVERED, READ, FAILED, REVOKED)message
Template Status UpdateTemplate is approved or rejected by RBMtemplate
Suggestion ResponseUser taps a suggested reply or suggested actionsuggestion
Location SharingUser shares a location (via share_location suggestion)location
User TypingUser starts typing a responsetyping

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"
}
KeyTypeDescription
agentStringYour RBM Agent name
phoneStringUser's phone number with country code
request_idStringUnique identifier for this incoming message. Use this to mark the message as read or send a typing indicator
session_idStringSession ID for the conversation thread
typeStringContent type: text, file, suggestion, or location
timestampStringUTC 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"
}
KeyTypeDescription
typeString"text"
textStringThe 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:

KeyTypeDescription
file.mediaStringMedia category: image, video, or document
file.{media}ObjectNamed after the media value (e.g., file.image when media is "image")
mimeTypeStringMIME type of the file (e.g., image/jpeg)
fileSizeBytesNumberFile size in bytes
fileUriStringURL to download the file
fileNameStringOriginal filename
Note: The media detail object is named dynamically based on the 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

StatusDescription
SENTMessage has been queued for sending by the RBM platform
DELIVEREDMessage has been delivered to the user's device
READUser has opened and read the message
FAILEDRBM failed to deliver the message. The failure_reason field provides details
REVOKEDMessage 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"
}
KeyTypeDescription
typeString"message" — indicates a delivery status notification
message.message_idStringThe message_id returned when you originally sent the message
message.statusStringSENT, DELIVERED, READ, FAILED, or REVOKED
message.failure_reasonStringPresent only when status is FAILED. Describes the reason for delivery failure
timestampStringUTC timestamp of the status change
Important: Your server MUST return HTTP 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"
}
KeyTypeDescription
typeString"template" — indicates a template status notification
template.nameStringThe unique template name you assigned during creation
template.statusStringapproved or rejected
template.typeStringTemplate content type: text, card, or carousel
template.commentStringReview comment. For approved templates, this is typically "Ok". For rejected templates, it explains the rejection reason
Tip: Build automation around template status webhooks. When a template is approved, you can immediately enable it for campaign use. When rejected, log the comment and alert your team to revise and resubmit.
Important: Your server MUST return HTTP 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"
}
KeyTypeDescription
suggestion.typeString"reply" — the user tapped a suggested reply
suggestion.postbackStringThe postback value you set when creating the suggestion
suggestion.textStringThe 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"
}
KeyTypeDescription
location.latitudeStringLatitude of the shared location
location.longitudeStringLongitude of the shared location
Important: Your server MUST return HTTP 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"
}
KeyTypeDescription
typeString"typing" — user is typing a message
message_idStringMessage identifier associated with the typing event
Tip: When you receive a typing notification, send a typing indicator back to the user using POST /rcs/v1/indicators/typing. This creates a responsive conversational experience.
Important: Your server MUST return HTTP 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.