Skip to content

Search for a complete word or an exact phrase.

Schedule an SMS batch

One text and timestamp for multiple recipients

Section titled “One text and timestamp for multiple recipients”

POST /api/sms/v2/message-batches/ requires sms.schedule and an Idempotency-Key header. All recipients share text, send_at and, when supplied, sender_name. send_at is required and must be in the future, with an explicit timezone.

recipients contains 1 to 1000 unique numbers in Madagascar mobile E.164 format. A duplicate is rejected; it is not removed automatically. This contract does not provide an immediate batch or a different text for each recipient.

Set BEFIANA_SMS_API_KEY as in the quickstart. Replace the demonstration timestamp and numbers.

Terminal window
curl --include --request POST 'https://api.befiana.cloud/api/sms/v2/message-batches/' \
--header "Authorization: Bearer $BEFIANA_SMS_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: event-0001-reminder-batch' \
--data '{"recipients":["+261340000000","+261320000000"],"text":"Your event starts tomorrow.","send_at":"2030-01-15T09:00:00+03:00"}'

Example HTTP 202 response with illustrative identifiers and timestamps:

HTTP/1.1 202 Accepted
Content-Type: application/json
Location: /api/sms/v2/message-batches/363e02d3-04ce-434b-951f-c9d034f86d5e/
{
"id": "363e02d3-04ce-434b-951f-c9d034f86d5e",
"recipient_count": 2,
"credits_reserved": 2,
"send_at": "2030-01-15T06:00:00Z",
"created_at": "2030-01-14T12:00:00Z",
"counts": {
"scheduled": 2,
"processing": 0,
"accepted": 0,
"delivered": 0,
"undeliverable": 0,
"blocked": 0,
"failed": 0,
"unknown": 0
}
}

Two recipients each receiving a one-segment text require two credits. credits_reserved preserves that initial reservation; it does not represent the remaining reservations after processing. Read the balance for current values.

Validation, message creation and credit reservation form one admission. An invalid number, duplicate or insufficient credits does not produce partial batch acceptance. A 202 response means the entire batch was admitted, not that every message will be delivered.

After admission, each message has its own outcome. Counts from GET /message-batches/{batch_id}/ reflect current states. An idempotent replay of the POST instead returns the original response.

The delivery.read permission allows batch and message lookups.

Terminal window
export BATCH_ID='REPLACE_WITH_RETURNED_UUID'
curl "https://api.befiana.cloud/api/sms/v2/message-batches/$BATCH_ID/" \
--header "Authorization: Bearer $BEFIANA_SMS_API_KEY"
curl "https://api.befiana.cloud/api/sms/v2/message-batches/$BATCH_ID/messages/" \
--header "Authorization: Bearer $BEFIANA_SMS_API_KEY"

The list returns results and next_cursor. It contains at most 100 messages in the order of the submitted recipients. Each message has its own public id.

If next_cursor is not null, pass its unchanged value as the cursor parameter for the same batch:

Terminal window
export NEXT_CURSOR='REPLACE_WITH_RETURNED_NEXT_CURSOR'
curl --get "https://api.befiana.cloud/api/sms/v2/message-batches/$BATCH_ID/messages/" \
--header "Authorization: Bearer $BEFIANA_SMS_API_KEY" \
--data-urlencode "cursor=$NEXT_CURSOR"

The cursor is opaque and is not a URL. Do not decode or increment it, or reuse it for another batch. null marks the end. Statuses may change between pages; pagination is not a frozen snapshot of delivery outcomes.

Retain the same key, recipient order and body when retrying after a network failure. Do not recreate the batch to retrieve updated progress. Use the pagination recipe, idempotency and statuses to distinguish a technical retry from a new business operation.