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.
Create the batch
Section titled “Create the batch”Set BEFIANA_SMS_API_KEY as in the quickstart. Replace the demonstration timestamp and numbers.
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 AcceptedContent-Type: application/jsonLocation: /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.
Understand atomic admission
Section titled “Understand atomic admission”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.
Retrieve and paginate
Section titled “Retrieve and paginate”The delivery.read permission allows batch and message lookups.
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:
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.
Handle a retry
Section titled “Handle a retry”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.