Developer documentation
সেন্টারসমূহ
History and tracking
Every send creates a batch (bat_…) with one message (msg_…) per recipient. Poll batches for progress and messages for per-recipient status. All tracking endpoints need the bulk-sms:read scope, and a key only sees rows of its own mode.
Message lifecycle
queued ──▶ sending ──▶ sent
└──▶ failed ──▶ refunded
| Status | Meaning |
|---|---|
queued | Accepted and waiting to be sent. A 202 send response always reports queued. |
sending | Being handed to the SMS provider. |
sent | Final. The provider accepted the message. It is charged. |
failed | Final. The message could not be sent; error explains why. It is refunded to your wallet exactly once, and refunded becomes true. |
Status is final at sent: handset delivery reports are not tracked.
Failure reasons
A failed message carries error.code and a readable error.message. Codes are stable; new ones may be added, so treat an unknown code like rejected. Raw operator responses are never exposed.
| Code | Meaning |
|---|---|
provider_unavailable | The SMS operator was unavailable after retries. Sending again later usually works. |
delivery_unconfirmed | The operator never confirmed the message, so it was treated as not sent and refunded. |
submit_failed | The message could not be handed to the operator. |
payment_mismatch | Web sends only: the payment did not match the order, so it was refunded. |
test_failure | Test mode only: numbers ending in 0000 always fail. |
service_restricted | The account was restricted from SMS after the batch was queued, so the unsent messages were refunded. |
rejected | The operator rejected the message. |
Batch statuses
| Status | Meaning |
|---|---|
queued | Accepted; no message has been sent yet. |
processing | Messages are being sent. |
completed | Every message was sent. |
partially_failed | Some messages failed and were refunded. |
failed | Every message failed and the batch was refunded. |
Endpoints
bulk-sms:read
List your batches, newest first. Paginated.
| Name | Type | Required | Description |
|---|---|---|---|
status |
string | No | A batch status. |
type |
string | No | single, broadcast, personalized or group. |
channel |
string | No | api or web. |
group_id |
string | No | Only batches sent to this group. |
from_date |
date | No | Created on or after this date. |
to_date |
date | No | Created on or before this date. |
page, per_page |
integer | No | See Pagination. |
curl -X GET https://e-amarseba.com/api/v1/bulk-sms/batches \
-H "Authorization: Bearer $AMARSEBA_API_KEY" \
-H "Accept: application/json"
use Illuminate\Support\Facades\Http;
$response = Http::withToken(config('services.amarseba.key'))
->acceptJson()
->get('https://e-amarseba.com/api/v1/bulk-sms/batches');
$result = $response->json();
const response = await fetch("https://e-amarseba.com/api/v1/bulk-sms/batches", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AMARSEBA_API_KEY}`,
Accept: "application/json",
},
});
const result = await response.json();
import os
import requests
response = requests.get(
"https://e-amarseba.com/api/v1/bulk-sms/batches",
headers={
"Authorization": f"Bearer {os.environ['AMARSEBA_API_KEY']}",
"Accept": "application/json",
},
)
result = response.json()
bulk-sms:read
A batch summary with message counts per status, cost and refunded amount.
curl -g -X GET https://e-amarseba.com/api/v1/bulk-sms/batches/{batch_id} \
-H "Authorization: Bearer $AMARSEBA_API_KEY" \
-H "Accept: application/json"
use Illuminate\Support\Facades\Http;
$response = Http::withToken(config('services.amarseba.key'))
->acceptJson()
->get('https://e-amarseba.com/api/v1/bulk-sms/batches/{batch_id}');
$result = $response->json();
const response = await fetch("https://e-amarseba.com/api/v1/bulk-sms/batches/{batch_id}", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AMARSEBA_API_KEY}`,
Accept: "application/json",
},
});
const result = await response.json();
import os
import requests
response = requests.get(
"https://e-amarseba.com/api/v1/bulk-sms/batches/{batch_id}",
headers={
"Authorization": f"Bearer {os.environ['AMARSEBA_API_KEY']}",
"Accept": "application/json",
},
)
result = response.json()
{
"success": true,
"message": "Request successful",
"data": {
"batch_id": "bat_01j8z3k6q9w2m4n7p5r8t1v3x6",
"type": "broadcast",
"channel": "api",
"mode": "live",
"status": "partially_failed",
"sender": "Amarseba",
"is_masking": false,
"body": "Your OTP is 4821. It expires in 5 minutes.",
"group_id": null,
"recipient_count": 3,
"total_parts": 3,
"total_cost": "0.90",
"refunded_amount": "0.30",
"counts": {
"queued": 0,
"sending": 0,
"sent": 2,
"failed": 1
},
"created_at": "2026-09-26T10:00:00.000000Z",
"completed_at": "2026-09-26T10:00:08.000000Z"
},
"code": 200,
"timestamp": "2026-09-26T10:01:00.000000Z"
}
bulk-sms:read
The messages of one batch, in send order. Paginated.
| Name | Type | Required | Description |
|---|---|---|---|
status |
string | No | queued, sending, sent or failed. |
phone |
string | No | A recipient number in any accepted format. |
from_date |
date | No | Created on or after this date. |
to_date |
date | No | Created on or before this date. |
per_page |
integer | No | From 1 to 100. See Pagination. |
curl -g -X GET https://e-amarseba.com/api/v1/bulk-sms/batches/{batch_id}/messages \
-H "Authorization: Bearer $AMARSEBA_API_KEY" \
-H "Accept: application/json"
use Illuminate\Support\Facades\Http;
$response = Http::withToken(config('services.amarseba.key'))
->acceptJson()
->get('https://e-amarseba.com/api/v1/bulk-sms/batches/{batch_id}/messages');
$result = $response->json();
const response = await fetch("https://e-amarseba.com/api/v1/bulk-sms/batches/{batch_id}/messages", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AMARSEBA_API_KEY}`,
Accept: "application/json",
},
});
const result = await response.json();
import os
import requests
response = requests.get(
"https://e-amarseba.com/api/v1/bulk-sms/batches/{batch_id}/messages",
headers={
"Authorization": f"Bearer {os.environ['AMARSEBA_API_KEY']}",
"Accept": "application/json",
},
)
result = response.json()
bulk-sms:read
Search messages across all batches. Paginated.
| Name | Type | Required | Description |
|---|---|---|---|
phone |
string | No | A recipient number in any accepted format. |
status |
string | No | queued, sending, sent or failed. |
batch_id |
string | No | Only messages of this batch. |
from_date |
date | No | Created on or after this date. |
to_date |
date | No | Created on or before this date. |
curl -X GET https://e-amarseba.com/api/v1/bulk-sms/messages \
-H "Authorization: Bearer $AMARSEBA_API_KEY" \
-H "Accept: application/json"
use Illuminate\Support\Facades\Http;
$response = Http::withToken(config('services.amarseba.key'))
->acceptJson()
->get('https://e-amarseba.com/api/v1/bulk-sms/messages');
$result = $response->json();
const response = await fetch("https://e-amarseba.com/api/v1/bulk-sms/messages", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AMARSEBA_API_KEY}`,
Accept: "application/json",
},
});
const result = await response.json();
import os
import requests
response = requests.get(
"https://e-amarseba.com/api/v1/bulk-sms/messages",
headers={
"Authorization": f"Bearer {os.environ['AMARSEBA_API_KEY']}",
"Accept": "application/json",
},
)
result = response.json()
bulk-sms:read
One message with its timeline, error and refund state. This example is a test-mode number ending in 0000.
curl -g -X GET https://e-amarseba.com/api/v1/bulk-sms/messages/{message_id} \
-H "Authorization: Bearer $AMARSEBA_API_KEY" \
-H "Accept: application/json"
use Illuminate\Support\Facades\Http;
$response = Http::withToken(config('services.amarseba.key'))
->acceptJson()
->get('https://e-amarseba.com/api/v1/bulk-sms/messages/{message_id}');
$result = $response->json();
const response = await fetch("https://e-amarseba.com/api/v1/bulk-sms/messages/{message_id}", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AMARSEBA_API_KEY}`,
Accept: "application/json",
},
});
const result = await response.json();
import os
import requests
response = requests.get(
"https://e-amarseba.com/api/v1/bulk-sms/messages/{message_id}",
headers={
"Authorization": f"Bearer {os.environ['AMARSEBA_API_KEY']}",
"Accept": "application/json",
},
)
result = response.json()
{
"success": true,
"message": "Request successful",
"data": {
"message_id": "msg_01j8z3k6qa4b8c2d6e0f3g7h1j",
"batch_id": "bat_01j8z3k6q9w2m4n7p5r8t1v3x6",
"to": "8801712340000",
"body": "Your OTP is 4821. It expires in 5 minutes.",
"encoding": "gsm7",
"parts": 1,
"cost": "0.30",
"status": "failed",
"error": {
"code": "test_failure",
"message": "Simulated failure for test numbers ending in 0000"
},
"refunded": true,
"timeline": {
"queued_at": "2026-09-26T10:00:00.000000Z",
"sent_at": null,
"failed_at": "2026-09-26T10:00:05.000000Z",
"refunded_at": "2026-09-26T10:00:08.000000Z"
}
},
"code": 200,
"timestamp": "2026-09-26T10:01:00.000000Z"
}