Splashify SMS

Docs

Open panel
Panel

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

  1. Upload the recipients

    POST /broadcasts with 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.

  2. Start it

    POST /broadcasts/{id}/start. Only now does anything leave.

  3. Watch it

    GET /broadcasts/{id} returns sent, failed and total while it runs.

  4. Read the failures

    GET /broadcasts/{id}/failures lists the recipients that were not sent to, and why.

Upload a list

POST

/api/v1/sms/broadcasts

Session

A multipart/form-data request. Creates a draft and sends nothing.

The CSV

For a template reading Hi {#var#}, get {#var#} off until {#var#}.:

csv
number,name,discount,until
9876543210,Rahul,20%,31 Dec
9123456789,Priya,25%,31 Dec

Column 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.

bash
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

json
{
  "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

POST

/api/v1/sms/broadcasts/{broadcast_id}/start

Session

Moves a draft into the queue. Sending begins within a few seconds.

json
{ "success": true, "message": "Sending has started." }

A broadcast that has already been started cannot be started again.

Check progress

GET

/api/v1/sms/broadcasts/{broadcast_id}

API key or session
json
{
  "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

GET

/api/v1/sms/broadcasts

API key or session

Newest first. limit defaults to 50 and caps at 100.

Read the failures

GET

/api/v1/sms/broadcasts/{broadcast_id}/failures

API key or session
json
{
  "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

POST

/api/v1/sms/broadcasts/{broadcast_id}/cancel

Session
json
{ "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.