SMS YANU documentation home

Send to many numbers

POST /v1/messages/send-bulk sends one message to a contact list or a list of numbers, now, scheduled or at a set pace.

POST https://api.smsyanu.com/v1/messages/send-bulk
Authorization: Bearer yanu_live_YOUR_KEY
Content-Type: application/json

The whole batch is priced and charged when you send the request. Duplicate numbers are dropped, and numbers on your opt-out list are left out. Check the cost first with POST /v1/messages/bulk-precheck.

Request body

Pass contact_list_ids or recipients. If you pass both, recipients is used.

FieldTypeRequiredMeaning
contact_list_idsinteger arrayOne of the twoSaved contact lists to send to.
recipientsobject arrayOne of the twoNumbers given in the request. Each has to, and optionally name and vars.
textstringYesThe message. Merge fields are filled in for each person. See Merge fields.
sender_idstringNoSender name, up to 11 characters. It must be approved on your account. Without it, the route default is used.
schedule_modestringNonow (default), scheduled or drip.
scheduled_atstringWhen scheduledISO 8601 time with a time zone. At least 5 minutes and at most 7 days ahead.
drip_rateintegerWhen dripMessages per minute, 1 to 5000.
flashbooleanNoShow on the screen without saving on the phone.
validity_periodintegerNoMinutes (1 to 4320) before an undelivered message expires.
priorityintegerNo0 normal (default) to 3 highest.
skip_unavailablebooleanNoLeave out numbers that cannot be sent to, uncharged, instead of refusing the whole request.

A scheduled send needs a contact list. Use now or drip with recipients. Binary messages are not supported on bulk sends.

Send to a list of numbers

{
  "recipients": [
    { "to": "+265888123456", "name": "Chisomo", "vars": { "balance": "45,000" } },
    { "to": "0999123456", "name": "Thoko", "vars": { "balance": "12,500" } }
  ],
  "text": "Dear {first_name|parent}, your balance is MWK {balance}.",
  "sender_id": "YANU"
}

Schedule a contact list

{
  "contact_list_ids": [12],
  "text": "School fees for term 2 are due on Friday.",
  "sender_id": "YANU",
  "schedule_mode": "scheduled",
  "scheduled_at": "2026-12-01T08:00:00+02:00"
}

To send at a set pace instead, use "schedule_mode": "drip" with "drip_rate": 300.

Response

HTTP 200:

{
  "batch_id": "2d7f4a1e-8c33-4b1a-9c55-0e6f7a2b9d10",
  "total_recipients": 2,
  "estimated_cost": 40.0,
  "status": "sending"
}
FieldMeaning
batch_idUse it to read the batch or to cancel a scheduled batch.
total_recipientsNumbers that will be sent to, after duplicates and opt-outs are removed.
estimated_costWhat was charged, in your balance currency.
statussending, scheduled or dripping.

Merge fields

Write a field as {field}, or as {field|fallback} to give a value for anyone who has none. Fields come from the contact, or from vars and name in recipients.

If someone has no value and there is no fallback, the request is refused with missing_merge_field and nothing is charged. The answer names the field and an example number.

Merge fields change the length of each message, so people on one batch can use different numbers of segments. Each message is charged for its own segments.

Check the cost first

POST /v1/messages/bulk-precheck takes the same contact_list_ids or recipients, text and sender_id. It sends nothing and charges nothing.

{
  "total_contacts": 2,
  "total_segments": 2,
  "total_cost": 40.0,
  "wallet_currency": "MWK",
  "wallet_balance": 5000.0,
  "balance_after": 4960.0,
  "sufficient_balance": true,
  "invalid_count": 0,
  "suppressed_count": 0,
  "missing_fields": []
}

suppressed_count is how many numbers were left out because they opted out.

Send each batch once

Add an Idempotency-Key header with a unique value per batch. If you send the same key again, you get the first result back with "idempotent_replay": true, and you are not charged twice. While the first request is still running, a repeat answers 409 with idempotency_in_progress.

Follow and cancel

MethodPathWhat it does
GET/v1/messages/batch/{batch_id}Totals for the batch.
POST/v1/messages/batch/{batch_id}/cancelCancel a scheduled batch before it starts. The charge is refunded.

A message that fails is refunded when the gateway refuses it or its final report says it failed. Set up a webhook to hear about each one.

Limits and errors

  • Bulk requests are limited to 10 per minute by default. A batch can be large, so send one big request rather than many small ones.
  • A message can be at most 10 segments. A longer one is refused with message_too_long.
HTTPCodeWhat it means
400missing_merge_fieldSomeone has no value for a field. Add a fallback or fix the data.
400scheduled_needs_listA scheduled send was given recipients. Use contact_list_ids.
400sandbox_no_scheduleTest keys cannot schedule sends.
402insufficient_balanceYour balance does not cover the batch. Nothing was charged.
413message_too_longA message renders to more than 10 segments.
422destination_not_allowedA number is outside Malawi. Fix it, or set skip_unavailable.

See the common codes in Errors.

On this page