RCS Business Messaging delivers branded, verified messages with rich cards, carousels and suggested actions to the phone's native messaging app. You send every RCS message type through POST /rcs/message/sendbulk, a multipart endpoint where messageType selects the payload.
Before you send#
- A launched RCS agent. Your brand's verified sender (the agent) is registered with Google and the carriers by our team as part of onboarding. While the agent is in test, it only delivers to registered test numbers.
- Recipients in E.164 with a leading
+, for example+447700900123. RCS rejects numbers without the+at validation time, unlike the SMS API. - A fallback plan for users whose device or carrier does not support RCS (see below).
Message types#
messageType |
Required fields | Rules |
|---|---|---|
TEXT |
content |
Up to 3,072 characters. |
MEDIA |
mediaUrl |
HTTPS URL to an image, video, audio file or PDF. Optional caption, fileName. |
CARD |
cardsJson |
One rich card. Title up to 200 characters, description up to 2,000, media over HTTPS, up to 10 suggestions. |
CAROUSEL |
cardsJson |
2 to 10 cards, same per-card rules as CARD. |
CHOICE |
content, choicesJson |
Up to 10 suggested replies or actions; each needs non-empty text. |
LOCATION |
latitude, longitude |
Latitude between -90 and 90, longitude between -180 and 180. Optional locationName, locationAddress. |
TEMPLATE |
templateId |
Template ID in ULID format (26 characters), plus templateVersion, templateLanguage, parametersJson. |
Invalid requests are rejected up front with 400, rather than failing silently per recipient.
Common fields#
| Field | Type | Required | Description |
|---|---|---|---|
messageType |
string | Yes | One of the types above. |
destinationNo |
string | One of these two | One or more E.164 numbers with +, comma-separated. |
destinationFiles |
file | One of these two | File of recipients for bulk sends. |
recipientType |
string | No | PHONE. |
batchId |
string | No | 0 starts a new batch. |
campaignName |
string | No | Your label for reporting. |
allowDuplicate |
string | No | false removes duplicates. |
delay |
string | No | Throttle between messages. |
scheduled |
string | No | true to schedule. |
scheduleTime |
string | When scheduled | For example 2026-11-01 10:00:00.000. |
gmt |
string | When scheduled | GMT offset, for example +04:00. |
recurrence, repeatCount |
string | No | NONE, DAILY and so on, and how many times to repeat. |
Send a rich card#
A card has a title, a description, an image and up to 10 suggestions. A suggestion with a url opens a link, one with a phoneNumber starts a call, and one with only postbackData is a suggested reply that comes back to you when tapped.
cURL
curl -X POST https://api.broadnet.me/rcs/message/sendbulk \
-H "Authorization: Bearer $BROADNET_TOKEN" \
-F batchId=0 \
-F campaignName=autumn-launch \
-F destinationNo=+447700900123 \
-F messageType=CARD \
-F 'cardsJson={"title":"Autumn collection is here","description":"New arrivals with launch-week prices.","mediaUrl":"https://cdn.example.com/omnidemo/autumn.jpg","height":"MEDIUM","choices":[{"text":"Shop now","url":"https://example.com/autumn","postbackData":"SHOP"},{"text":"Call us","phoneNumber":"+447700900100","postbackData":"CALL"},{"text":"Not now","postbackData":"LATER"}]}'Node.js
const card = {
title: "Autumn collection is here",
description: "New arrivals with launch-week prices.",
mediaUrl: "https://cdn.example.com/omnidemo/autumn.jpg",
height: "MEDIUM",
choices: [
{ text: "Shop now", url: "https://example.com/autumn", postbackData: "SHOP" },
{ text: "Call us", phoneNumber: "+447700900100", postbackData: "CALL" },
{ text: "Not now", postbackData: "LATER" },
],
};
const form = new FormData();
form.append("batchId", "0");
form.append("campaignName", "autumn-launch");
form.append("destinationNo", "+447700900123");
form.append("messageType", "CARD");
form.append("cardsJson", JSON.stringify(card));
const res = await fetch("https://api.broadnet.me/rcs/message/sendbulk", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.BROADNET_TOKEN}` },
body: form,
});
console.log(res.status, await res.text());Python
import json
import os
import requests
card = {
"title": "Autumn collection is here",
"description": "New arrivals with launch-week prices.",
"mediaUrl": "https://cdn.example.com/omnidemo/autumn.jpg",
"height": "MEDIUM",
"choices": [
{"text": "Shop now", "url": "https://example.com/autumn", "postbackData": "SHOP"},
{"text": "Call us", "phoneNumber": "+447700900100", "postbackData": "CALL"},
{"text": "Not now", "postbackData": "LATER"},
],
}
fields = {
"batchId": "0",
"campaignName": "autumn-launch",
"destinationNo": "+447700900123",
"messageType": "CARD",
"cardsJson": json.dumps(card),
}
r = requests.post(
"https://api.broadnet.me/rcs/message/sendbulk",
headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
files={k: (None, v) for k, v in fields.items()},
timeout=30,
)
print(r.status_code, r.text)Send a carousel#
A carousel is a JSON array of 2 to 10 cards in cardsJson:
cURL
curl -X POST https://api.broadnet.me/rcs/message/sendbulk \
-H "Authorization: Bearer $BROADNET_TOKEN" \
-F batchId=0 \
-F destinationNo=+447700900123 \
-F messageType=CAROUSEL \
-F 'cardsJson=[{"title":"Classic","description":"Best seller","mediaUrl":"https://cdn.example.com/omnidemo/a.jpg","height":"MEDIUM","choices":[{"text":"Buy","url":"https://example.com/a","postbackData":"BUY_A"}]},{"title":"Premium","description":"New arrival","mediaUrl":"https://cdn.example.com/omnidemo/b.jpg","height":"MEDIUM","choices":[{"text":"Buy","url":"https://example.com/b","postbackData":"BUY_B"}]}]'Send suggested replies#
CHOICE sends a text with tappable suggestions:
cURL
curl -X POST https://api.broadnet.me/rcs/message/sendbulk \
-H "Authorization: Bearer $BROADNET_TOKEN" \
-F batchId=0 \
-F destinationNo=+447700900123 \
-F messageType=CHOICE \
-F "content=How was your delivery today?" \
-F 'choicesJson=[{"text":"Great","postbackData":"CSAT_5"},{"text":"OK","postbackData":"CSAT_3"},{"text":"Poor","postbackData":"CSAT_1"}]'Suggestions can also carry a url (open a link, or add an event to a calendar) or latitude and longitude (share a location).
Send a template#
RCS templates are created with POST /rcs/template/create and sent by ID with their parameters:
cURL
curl -X POST https://api.broadnet.me/rcs/message/sendbulk \
-H "Authorization: Bearer $BROADNET_TOKEN" \
-F batchId=0 \
-F destinationNo=+447700900123 \
-F recipientType=PHONE \
-F messageType=TEMPLATE \
-F templateId=01ARZ3NDEKTSV4RRFFQ69G5FAV \
-F templateVersion=1 \
-F templateLanguage=en \
-F 'parametersJson={"name":"Sara","otp":"482913"}' \
-F campaignName=login-otpRelated endpoints: POST /rcs/template/list, GET /rcs/template/name, GET /rcs/template/grouped, PUT /rcs/template/{RCS_TEMPLATE_ID} and DELETE /rcs/template/{RCS_TEMPLATE_ID}.
Check capability and plan fallback#
Not every device or carrier supports RCS. Plan what happens for those users.
- Platform fallback. Channel fallback (for example WhatsApp, then RCS, then SMS) is configured per use case with our team, and delivery statuses come back in one webhook format.
- Your own fallback. If you orchestrate channels yourself, check capability first and send SMS through
POST /sms/sendSmswhen RCS is not available. You can also fall back when a webhook reportsFAILEDfor an RCS message.
POST /rcs/capability/query submits a capability lookup for a number and returns a request ID for tracking:
cURL
curl -X POST "https://api.broadnet.me/rcs/capability/query?recipient=%2B447700900123" \
-H "Authorization: Bearer $BROADNET_TOKEN"URL-encode the + as %2B in query strings.
Test, track and control batches#
| Method | Path | Description |
|---|---|---|
| POST | /rcs/message/test?to=…&text=… |
Single text smoke test. While your agent is in test, it only reaches test numbers. |
| POST | /rcs/message/batches |
List batches (JSON body with page, size, status and date filters). |
| GET | /rcs/message/about?batchId=… |
Batch details. |
| GET | /rcs/message/pause?batchId=… |
Pause a PENDING or INPROGRESS batch. |
| GET | /rcs/message/resume?batchId=… |
Resume a paused batch. |
| DELETE | /rcs/message/abort?batchId=… |
Abort a batch. |
| POST | /rcs/message/typing |
Show a typing indicator. |
Note that RCS batch endpoints take batchId, while SMS, WhatsApp, Messenger, Instagram, Telegram and Email take batch_Id.
Batch statuses are PENDING, INPROGRESS, PAUSED, DONE, ABORTED and FAILED. Per-recipient delivery statuses arrive on your webhook.
Next steps#
- Webhooks: receive RCS statuses and postback replies.
- SMS API: the fallback channel for non-RCS devices.
- WhatsApp API: rich messaging on WhatsApp.
- Errors and limits: handle validation errors and retries.
Ready to send your first message?
Request test credentials. An engineer sets up your account, and test sends go to your own verified numbers.
Request test access