RCS Omnichannel API
RCS transforms business messaging with interactive experiences — images, videos, carousels, and CTAs — beyond traditional SMS and WhatsApp. When RCS is not supported on the recipient's device, an automatic SMS fallback can be configured.
To send RCS messages you need to:
- Register your Brand with Exotel
- Have RCS templates configured for your brand
- Get your Brand and bot verified
Contact your Account Manager or fill out the RCS Early Access form to get started.
Send RCS Template Message
POST https://<api_key>:<api_token><subdomain>/v2/accounts/<account_sid>/messages
| Subdomain | Region |
|---|---|
@api.exotel.com | Singapore |
@api.in.exotel.com | Mumbai |
POST Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
custom_data | String | Optional | Custom metadata passed at the request level. Returned in callbacks. |
status_callback | String (URL) | Optional | Webhook URL for delivery status events. |
rcs | Channel Object | Optional | RCS channel configuration. |
Channel Object
| Parameter | Type | Required | Description |
|---|---|---|---|
custom_data | String | Optional | Custom metadata at the channel level. |
status_callback | String (URL) | Optional | Webhook URL for channel-level delivery events. |
messages | []Message Object | Mandatory | Array of messages to send. |
Message Object
| Parameter | Type | Required | Description |
|---|---|---|---|
custom_data | String | Optional | Custom metadata at the message level. |
status_callback | String (URL) | Optional | Webhook URL for this specific message. |
from | String | Mandatory | BotID to send from (provided by Exotel during onboarding). |
to | String | Mandatory | Recipient phone number in E.164 format (e.g., +919888888888). |
content | Template Message Object | Mandatory | RCS message body. |
fallback | Fallback Object | Optional | SMS fallback sent if RCS delivery fails. |
Template Message Object
| Parameter | Type | Required | Description |
|---|---|---|---|
type | String | Mandatory | Must be "template". |
template | Object | Mandatory | Template details. |
template.name | String | Mandatory | Name of the pre-approved RCS template. |
template.variables | Variables Object | Mandatory | Key-value pairs for template variable substitution. |
Variables Object
| Parameter | Type | Required | Description |
|---|---|---|---|
TemplateParam1 | String | Optional | Value for the first template variable. |
TemplateParam2 | String | Optional | Value for the second template variable. |
TemplateParam3 | String | Optional | Value for additional template variables. |
Fallback Object
| Parameter | Type | Required | Description |
|---|---|---|---|
from | String | Mandatory | SMS Sender ID to use for the fallback message. |
content | SMS Body Object | Mandatory | SMS message body. |
SMS Body Object
| Parameter | Type | Required | Description |
|---|---|---|---|
text | String | Mandatory | SMS message body text. |
sms_type | String | Mandatory | transactional, transactional_opt_in, or promotional. |
dlt_entity_id | String | Optional (Mandatory for India) | Entity ID registered on the DLT portal (required for Indian business → Indian number SMS). |
dlt_template_id | String | Optional | DLT Content Template ID for the SMS body. |
encoding_type | String | Optional | plain or unicode. |
priority | String | Optional | normal or high. Use high for OTP SMS only. |
shorten_url | Boolean | Optional | Whether to shorten URLs in the SMS. Chargeable feature. |
shorten_url_params | Shorten URL Params Object | Optional | Configuration for URL shortening. |
Shorten URL Params Object
| Parameter | Type | Required | Description |
|---|---|---|---|
custom_domain | String | Optional | Custom domain for short URLs (defaults to exo.tl if omitted). |
tracking | Boolean | Optional | Track URL clicks. Requires shorten_url: true. |
click_tracking_callback_url | String (URL) | Optional | Webhook for click events on shortened URLs. |
Code Examples
- cURL — RCS only
- cURL — with SMS Fallback
curl -XPOST "https://<api_key>:<api_token><subdomain>/v2/accounts/<your_sid>/messages" \
-H "Content-Type: application/json" \
-d '{
"custom_data": "ORDER123456",
"status_callback": "https://your-server.com/callback",
"rcs": {
"messages": [
{
"from": "IifqFxxxxxxx6fp",
"to": "+91xxxxxxxxx987",
"content": {
"type": "template",
"template": {
"name": "order_confirmation",
"variables": {
"TemplateParam1": "Rahul",
"TemplateParam2": "ORD-12345"
}
}
}
}
]
}
}'
curl -XPOST "https://<api_key>:<api_token><subdomain>/v2/accounts/<your_sid>/messages" \
-H "Content-Type: application/json" \
-d '{
"custom_data": "ORDER123456",
"status_callback": "https://your-server.com/callback",
"rcs": {
"messages": [
{
"from": "IifqFxxxxxxx6fp",
"to": "+91xxxxxxxxx987",
"content": {
"type": "template",
"template": {
"name": "order_confirmation",
"variables": {
"TemplateParam1": "Rahul",
"TemplateParam2": "ORD-12345"
}
}
},
"fallback": {
"from": "EXOTEL",
"content": {
"text": "Hi Rahul, your order ORD-12345 has been confirmed.",
"sms_type": "transactional",
"dlt_entity_id": "1234567890",
"dlt_template_id": "0987654321"
}
}
}
]
}
}'
Response
HTTP 202 Accepted
{
"request_id": "b434e927a5844175b23059cd96feea3d",
"method": "POST",
"http_code": 202,
"metadata": {
"failed": 0,
"total": 1,
"success": 1
},
"response": {
"rcs": {
"messages": [
{
"code": 202,
"error_data": null,
"status": "success",
"data": {
"sid": "2FdiiEQUosckPhpZfuVwfjxiSlc16a4"
}
}
]
}
}
}
Response Parameters
| Parameter | Type | Description |
|---|---|---|
request_id | String | Unique ID of the request. Useful for debugging. |
method | String | HTTP method (e.g., POST). |
http_code | Integer | HTTP status code (e.g., 202). |
metadata | Metadata Object | Count of total, successful, and failed messages. |
response | Response Object | Per-message response details. |
Metadata Object: total (Integer), success (Integer), failed (Integer)
Response Object: rcs → ChannelResponseObject → messages → []CreateMessageResponseObject
CreateMessageResponseObject:
| Parameter | Type | Description |
|---|---|---|
code | Integer | HTTP response code for this message. |
error_data | Error Response Object | Error details (if failed). |
status | String | success or failure. |
data.sid | String | Unique message identifier. |
Error Response Object: code (Numeric), message (String), description (String)
HTTP Error Codes
| Code | Description |
|---|---|
| 202 | Accepted — request accepted. |
| 400 | Bad Request — malformed header/body, or more than 100 messages in one request. |
| 401 | Unauthorized — credentials missing or invalid. |
| 402 | Payment Required — feature not on your plan or usage limit exceeded. |
| 403 | Access denied — valid credentials but no access to this resource. |
| 404 | Not Found — the object does not exist. |
| 5xx | Server Error — retry the request. |
RCS Status Callback
Exotel sends delivery events to the status_callback URL provided in the API request (or the default URL configured during onboarding).
- If
status_callbackis set in the API request → callbacks go to that URL. - If not set → callbacks go to the default URL (if configured).
- If SMS fallback was triggered → both
rcsandsmsobjects appear in the callback.
Any callback can be received only at one status callback URL at a time.
Callback Parameters
| Parameter | Type | Description |
|---|---|---|
rcs | Message DLR Object | Delivery report for the RCS channel. |
sms | SMS DLR Object | Delivery report for the SMS fallback (present only if fallback was triggered). |
Message DLR Object
| Parameter | Type | Description |
|---|---|---|
messages | []RCS Message DLR Object | Delivery reports for each message. |
RCS Message DLR Object
| Parameter | Type | Description |
|---|---|---|
callback_type | String | dlr or icm |
sid | String | Unique message identifier. |
to | String | Recipient phone number. |
exo_status_code | Integer | ExoStatus code (see table below). |
exo_detailed_status | String | Detailed status name. |
description | String | Human-readable description of the status. |
timestamp | String | ISO 8601 timestamp of the event. |
custom_data | String | Custom data passed in the original API request. |
SMS DLR Object
| Parameter | Type | Description |
|---|---|---|
messages | []SMS Message DLR Object | Delivery reports for the SMS fallback. |
SMS Message DLR Object
| Parameter | Type | Description |
|---|---|---|
callback_type | String | dlr |
sid | String | Unique identifier of the SMS fallback message. |
channel_sid | String | SID of the fallback channel. null if fallback triggering failed. |
to | String | Recipient phone number. |
exo_status_code | Integer | ExoStatus code for the SMS. |
exo_detailed_status | String | Detailed status name. |
description | String | Human-readable description. |
sms_units | Integer | Number of SMS units sent. null if fallback triggering failed. |
timestamp | String | ISO 8601 timestamp of the event. |
custom_data | String | Custom data from the original request. |
RCS ExoStatus Codes
| Code | Status | Description |
|---|---|---|
| 40001 | EX_MESSAGE_SENT | Message transmitted to the user. |
| 40002 | EX_MESSAGE_DELIVERED | Message successfully delivered. |
| 40003 | EX_MESSAGE_SEEN | Message seen/read by the user. |
| 40004 | EX_SYSTEM_ERROR | Delivery failed (auth/permission/service issue). |
For SMS fallback ExoStatus codes, see SMS API — Status Codes.
Callback Samples
- RCS Delivered
- RCS Seen
- SMS Fallback — Success
- SMS Fallback — Failed
{
"rcs": {
"messages": [
{
"callback_type": "dlr",
"sid": "2FdiiEQUosckPhpZfuVwfjxiSlc16a4",
"to": "+91xxxxxxxxx987",
"exo_status_code": 40002,
"exo_detailed_status": "EX_MESSAGE_DELIVERED",
"description": "Message delivered",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"custom_data": "ORDER123456"
}
]
}
}
{
"rcs": {
"messages": [
{
"callback_type": "dlr",
"sid": "2FdiiEQUosckPhpZfuVwfjxiSlc16a4",
"to": "+91xxxxxxxxx987",
"exo_status_code": 40003,
"exo_detailed_status": "EX_MESSAGE_SEEN",
"description": "Message seen by user",
"timestamp": "2024-12-07T17:01:30.000+05:30",
"custom_data": "ORDER123456"
}
]
}
}
{
"rcs": {
"messages": [
{
"callback_type": "dlr",
"sid": "2FdiiEQUosckPhpZfuVwfjxiSlc16a4",
"to": "+91xxxxxxxxx987",
"exo_status_code": 40004,
"exo_detailed_status": "EX_SYSTEM_ERROR",
"description": "RCS delivery failed; SMS fallback triggered",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"custom_data": "ORDER123456"
}
]
},
"sms": {
"messages": [
{
"callback_type": "dlr",
"sid": "SMSsid123456",
"channel_sid": "CHsid123456",
"to": "+91xxxxxxxxx987",
"exo_status_code": 25002,
"exo_detailed_status": "EX_MESSAGE_DELIVERED",
"description": "SMS fallback delivered",
"sms_units": 1,
"timestamp": "2024-12-07T17:00:05.000+05:30",
"custom_data": "ORDER123456"
}
]
}
}
{
"rcs": {
"messages": [
{
"callback_type": "dlr",
"sid": "2FdiiEQUosckPhpZfuVwfjxiSlc16a4",
"to": "+91xxxxxxxxx987",
"exo_status_code": 40004,
"exo_detailed_status": "EX_SYSTEM_ERROR",
"description": "RCS delivery failed; SMS fallback also failed",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"custom_data": "ORDER123456"
}
]
},
"sms": {
"messages": [
{
"callback_type": "dlr",
"sid": null,
"channel_sid": null,
"to": "+91xxxxxxxxx987",
"exo_status_code": 25004,
"exo_detailed_status": "EX_SYSTEM_ERROR",
"description": "SMS fallback triggering failed",
"sms_units": null,
"timestamp": "2024-12-07T17:00:05.000+05:30",
"custom_data": "ORDER123456"
}
]
}
}
Receive RCS Incoming Message
Configure a webhook to receive messages sent by users (replies or user-initiated messages). Pass the webhook URL in status_callback in the send API, or configure a default URL with the Exotel team during onboarding.
- If
status_callbackis set in the send API → user replies go to that URL. - If not set → replies go to the default URL.
- All user-initiated conversations (not replies to a business message) go to the default URL.
Any incoming message can be received only at one webhook URL at a time.
Webhook Parameter
| Parameter | Type | Description |
|---|---|---|
rcs | Message ICM Object | Incoming message callback for RCS. |
Message ICM Object
| Parameter | Type | Description |
|---|---|---|
messages | []RCS Message ICM Object | Array of incoming messages. |
RCS Message ICM Object
| Parameter | Type | Description |
|---|---|---|
callback_type | String | incoming_message |
sid | String | Unique identifier of the incoming message. |
from | String | Phone number of the end user. |
to | String | Business bot ID that received the message. |
timestamp | String | ISO 8601 timestamp when the message was sent. |
content | Content Object | Message content. |
Content Object
| Parameter | Type | Description |
|---|---|---|
type | String | Message type: text, file, location, suggested, or error. |
text | String | Message body. Mandatory when type is text. |
file | File ICM Object | Media details. Mandatory when type is file. |
location | Location ICM Object | Location details. Mandatory when type is location. |
suggested | Suggested ICM Object | Suggested reply/action response. Mandatory when type is suggested. |
error | Message ICM Error Object | Error details. Present when type is error. |
File ICM Object
| Parameter | Type | Description |
|---|---|---|
url | String | URL to download the media file. |
name | String | Filename (for documents). |
type | String | MIME type of the file. |
size | Integer | File size in bytes. |
thumbnail_url | String | URL of the thumbnail (optional). |
thumbnail_type | String | MIME type of the thumbnail (optional). |
thumbnail_size | Integer | Size of the thumbnail in bytes (optional). |
Location ICM Object
| Parameter | Type | Description |
|---|---|---|
latitude | Float | Latitude of the shared location. |
longitude | Float | Longitude of the shared location. |
Suggested ICM Object
| Parameter | Type | Description |
|---|---|---|
response | Suggested Response ICM Object | The user's response to a suggested reply or action. |
Suggested Response ICM Object: reply (Reply Object) or action (Action Object)
Incoming Message Samples
- Text
- File
- Location
- Suggested Reply
- Suggested Action
- Error
{
"rcs": {
"messages": [
{
"callback_type": "incoming_message",
"sid": "ICM123456",
"from": "+91xxxxxxxxx001",
"to": "IifqFxxxxxxx6fp",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"content": {
"type": "text",
"text": "This is a text message from the user"
}
}
]
}
}
{
"rcs": {
"messages": [
{
"callback_type": "incoming_message",
"sid": "ICM123456",
"from": "+91xxxxxxxxx001",
"to": "IifqFxxxxxxx6fp",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"content": {
"type": "file",
"file": {
"url": "https://media.exotel.com/rcs/file123.jpg",
"name": "photo.jpg",
"type": "image/jpeg",
"size": 204800,
"thumbnail_url": "https://media.exotel.com/rcs/thumb_file123.jpg",
"thumbnail_type": "image/jpeg",
"thumbnail_size": 4096
}
}
}
]
}
}
{
"rcs": {
"messages": [
{
"callback_type": "incoming_message",
"sid": "ICM123456",
"from": "+91xxxxxxxxx001",
"to": "IifqFxxxxxxx6fp",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"content": {
"type": "location",
"location": {
"latitude": 12.9716,
"longitude": 77.5946
}
}
}
]
}
}
{
"rcs": {
"messages": [
{
"callback_type": "incoming_message",
"sid": "ICM123456",
"from": "+91xxxxxxxxx001",
"to": "IifqFxxxxxxx6fp",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"content": {
"type": "suggested",
"suggested": {
"response": {
"reply": {
"text": "Yes, confirm my order",
"postback_data": "confirm_order_123"
}
}
}
}
}
]
}
}
{
"rcs": {
"messages": [
{
"callback_type": "incoming_message",
"sid": "ICM123456",
"from": "+91xxxxxxxxx001",
"to": "IifqFxxxxxxx6fp",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"content": {
"type": "suggested",
"suggested": {
"response": {
"action": {
"postback_data": "track_order_123",
"action_type": "open_url"
}
}
}
}
}
]
}
}
{
"rcs": {
"messages": [
{
"callback_type": "incoming_message",
"sid": "ICM123456",
"from": "+91xxxxxxxxx001",
"to": "IifqFxxxxxxx6fp",
"timestamp": "2024-12-07T17:00:00.000+05:30",
"content": {
"type": "error",
"error": {
"code": 40004,
"description": "Incoming message could not be processed"
}
}
}
]
}
}