Broadcasts
A broadcast sends one promotional template to a list of recipients, paced on our side. Use it instead of looping over Send a message: that endpoint is rate limited to 60 requests a minute because it is interactive, and a campaign is not.
Promotional templates only
Transactional and service templates answer something the recipient did. Sending a campaign on one is the misuse that gets a whole DLT registration suspended, so a broadcast on a non-promotional template is refused.
Session only
These endpoints need a panel session, not an API key. Uploading a list of people to send a promotion to is a decision taken by a person. Everything else on this page is readable with either.
The shape of it
Upload the recipients
POST /broadcastswith a CSV. Nothing is sent and nothing is charged. You get back how many rows were valid, every line that was not, and what it will cost.Start it
POST /broadcasts/{id}/start. Only now does anything leave.Watch it
GET /broadcasts/{id}returnssent,failedandtotalwhile it runs.Read the failures
GET /broadcasts/{id}/failureslists the recipients that were not sent to, and why.
Upload a list
/api/v1/sms/broadcasts
A multipart/form-data request. Creates a draft and sends nothing.
The CSV
For a template reading Hi {#var#}, get {#var#} off until {#var#}.:
number,name,discount,until
9876543210,Rahul,20%,31 Dec
9123456789,Priya,25%,31 DecColumn 2 fills the first {#var#}, column 3 the second, and so on. A template
with no variables needs only the number column.
Lines are skipped, not guessed at, when the number is not an Indian mobile, when it is a duplicate of an earlier line in the same file, when a value is blank, or when there are fewer values than the template needs. Every skipped line comes back with its line number.
curl -X POST https://api.splashifypro.com/api/v1/sms/broadcasts \
-H "Authorization: Bearer your_session_token" \
-F "name=Diwali offer" \
-F "dlt_template_id=1234567890123456789" \
-F "[email protected]"Response
{
"success": true,
"broadcast": {
"broadcast_id": "8f14e45f-ceea-467a-9e58-1b2c3d4e5f60",
"name": "Diwali offer",
"dlt_template_id": "1234567890123456789",
"header": "SPLASH",
"category": "promotional",
"status": "draft",
"total": 2,
"sent": 0,
"failed": 0,
"charged": 0,
"created_at": "2026-09-24T10:15:00Z"
},
"valid": 2,
"error_count": 1,
"errors": [
{ "line": 4, "value": "12345", "reason": "not an Indian mobile number" }
],
"price_per_part": 0.16,
"estimated_cost": 0.32,
"wallet_balance": 500,
"enough_balance": true,
"variable_count": 3
}The cost is quoted at one part per message
A message over 160 characters, or one containing any character outside the GSM alphabet, is more than one part and costs proportionally more. You are billed on the part count the operator reports, never on this estimate.
Start sending
/api/v1/sms/broadcasts/{broadcast_id}/start
Moves a draft into the queue. Sending begins within a few seconds.
{ "success": true, "message": "Sending has started." }A broadcast that has already been started cannot be started again.
Check progress
/api/v1/sms/broadcasts/{broadcast_id}
{
"success": true,
"broadcast": {
"broadcast_id": "8f14e45f-ceea-467a-9e58-1b2c3d4e5f60",
"name": "Diwali offer",
"status": "running",
"total": 10000,
"sent": 3412,
"failed": 8,
"charged": 545.92,
"started_at": "2026-09-24T10:16:04Z"
}
}Statuses
List your broadcasts
/api/v1/sms/broadcasts
Newest first. limit defaults to 50 and caps at 100.
Read the failures
/api/v1/sms/broadcasts/{broadcast_id}/failures
{
"success": true,
"failed": 8,
"rows": [
{ "line": 41, "value": "919876543299", "reason": "That mobile number does not look valid." }
]
}Capped at 200 rows. When thousands failed, the reason is the same on all of them and the first page tells you what it is.
Stop one
/api/v1/sms/broadcasts/{broadcast_id}/cancel
{ "success": true, "message": "Stopped. Messages already sent cannot be recalled." }Takes effect within a few seconds. Messages already handed to the operator are gone and are still charged.
What stops a broadcast
An empty wallet stops it. Sending checks your balance before each message and
stops with a stop_reason rather than sending messages it cannot charge for.
Add funds and start a new broadcast for the remainder; the recipients already
sent to are recorded, so you can build the remaining list from the failures and
the total.
A rejected message does not stop it. Each recipient is independent: one bad
number is counted in failed and the rest continue.