Send Cascade Messages
Send a batch of messages across Telegram bot, Viber bot, Viber Business Messages, RCS and SMS with one request. The exact schema is published in the Swagger specification (LegacyMessageDataDTO).
Endpoint
POST https://restapi.smsbat.com/api/CascadeMessage/send_message_async
send_message_async accepts the batch and returns immediately; delivery statuses arrive through callbacks. A synchronous POST /api/CascadeMessage/send_message exists too, and POST /api/CascadeMessage/send_message/omni-smsbat/tg-viber/async runs the cascade with Telegram → Viber priority.
Headers
Content-Type: application/json
X-Authorization-Key: <organization key from omni.smsbat.com>
X-Viber-Auth-Token: <viber bot token> # when the message goes through a Viber bot
X-Tg-Bot-Key: <telegram bot token> # when the message goes through a Telegram bot
The organization key for Cascade is generated in omni.smsbat.com and differs from the key used for /bat/messagelist. Bot tokens identify the bot: an organization can have several, so the token is required for bot delivery.
Request body
The body is a JSON array of message objects.
Message object
| Field | Type | Description |
|---|---|---|
id | string | Your tracking identifier. Returned as trackinId in the response and as track_id in callbacks. |
callbackUrl | string | HTTPS URL that receives the delivery statuses of this message. The query string is kept as is. |
fromName | string | Sender name (alpha name) for Viber Business / SMS. |
toPhone | string | Recipient phone: international format, digits only, no + (380501234567). Optional: without it the message is delivered to the bot only and Viber Business / SMS are not used. |
messageType | string | transaction, promo, viber_survey, flashcall. See Message Types. |
ttl | integer | Time-to-live in seconds. After it expires the message gets the expired status. |
viberMessage | object | Viber part of the message, see below. |
tgMessage | object | Telegram part of the message, see below. |
emailMessage, pushMessage | object | Email and push parts, see Swagger. |
customerData | any | Your own payload stored with the message. |
flashcallText, buttonText, buttonAction | string | Flash call text and a button for channels that support it. |
viberMessage
| Field | Type | Description |
|---|---|---|
receiver | string | Viber bot user id. Use it when the bot runs on your side and you store the ids yourself. |
type | string | text, picture, video, file, contact, location, sticker. |
sender.name, sender.avatar | string | Sender shown in the bot. |
text | string | Message text, up to 7000 characters. |
media, thumbnail, video, fileName, size, duration | Media attributes for the non-text types. | |
keyboard | object | Viber keyboard. |
trackingData | string | Viber tracking data. |
fallbackText | string | Text used by the fallback channels when they have no own text. |
fallbacks | array | Fallback channels in the order they are tried, see below. |
tgMessage
| Field | Type | Description |
|---|---|---|
chatId | integer (int64) | Telegram chat id of the recipient in your bot. |
text | string | Message text. |
photoUrl, photoBase64, videoUrl | string | Media. |
buttons | array of { "text", "action" } | Inline buttons. |
fallbacks[]
Each element describes the next channel to try. Fields set here override the message-level values for that channel.
| Field | Type | Description |
|---|---|---|
messageType | string | Channel/type of the fallback, for example sms. |
toPhone | string | Phone for this fallback (digits only, no +). May differ from the message toPhone. |
fromName | string | Sender name for this fallback. |
ttl | integer | TTL for this fallback in seconds. |
text | string | Text for this fallback. |
media, thumbnail, video, fileName, size, duration, contact, location, buttonText, buttonAction | Optional attributes for rich fallbacks. |
Example: Viber bot with SMS fallback and a callback URL
curl --request POST \
--url https://restapi.smsbat.com/api/CascadeMessage/send_message_async \
--header 'Content-Type: application/json' \
--header 'X-Authorization-Key: 61192c5***' \
--header 'X-Viber-Auth-Token: 5646dd4***' \
--data '[
{
"callbackUrl": "https://example.com/smsbat/status?channel=viber-bot",
"id": "DEVELOPER-TEST-SDFLW122",
"fromName": "YourBrand",
"toPhone": "380509180617",
"messageType": "transaction",
"ttl": 60,
"viberMessage": {
"type": "text",
"sender": { "name": "YourBrand" },
"text": "That is the Viber text",
"fallbacks": [
{
"messageType": "sms",
"toPhone": "380509180617",
"fromName": "YourBrand",
"ttl": 60,
"text": "SMS text for YourBrand"
}
]
}
}
]'
Example: bot only, recipient by bot id
Without toPhone the message is delivered only to the bot; add viberMessage.receiver (Viber) or tgMessage.chatId (Telegram).
[
{
"id": "ORDER-12345",
"callbackUrl": "https://example.com/smsbat/status?channel=telegram-bot",
"messageType": "transaction",
"ttl": 3600,
"tgMessage": {
"chatId": 123456789,
"text": "Your order #12345 has been shipped"
}
}
]
Response
200 OK — the batch is accepted. One object per message, in the same order:
[
{ "messageId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "trackinId": "DEVELOPER-TEST-SDFLW122" }
]
| Field | Description |
|---|---|
messageId | SMSBAT message GUID. Comes back as message_id in callbacks; use it with GET /api/CascadeMessage/status_guid/{guid}. |
trackinId | Your id. Comes back as track_id in callbacks; use it with GET /api/CascadeMessage/status_id/{id}. |
400 Bad Request — the batch is rejected as a whole and the reason is in the response body. If one element is invalid, none of the elements is sent, so the corrected batch can be resubmitted without duplicates. Other codes: 401 (invalid key), 5xx (our side, retry later).
Delivery statuses
The response only confirms acceptance. Delivery, read, expiry and failure events are posted to the message callbackUrl (or to the organization-level URL when the message has none). Format and statuses: Delivery Callbacks. Polling: GET /api/CascadeMessage/status_guid/{guid} or GET /api/CascadeMessage/status_id/{id}.
Limits
- Request body up to 10 MB. There is no validation of the number of elements in the array; the body size is the only limit.
- No per-second or per-minute request limits for the Cascade API. Batch messages instead of sending one request per message.
Best practices
- Use a unique
idper message and keep it under 255 characters; it is the key you will correlate callbacks with. - Put the same
callbackUrlon every message of an integration, and vary its query string if your receiver needs to distinguish bots or flows. - Choose TTL by use case: minutes for codes, hours for transactional messages, days for promotions.
- Send the cheapest channel first and keep SMS as the last fallback.