API Documentation
Base URL: https://api.bulksmsrates.com
Format: JSON • Encoding: UTF-8
All endpoints require authentication unless noted. Responses include standard HTTP status codes.
Quick Navigation
Authentication
All API requests require a Bearer token in the Authorization header. Get your API key from the dashboard.
Authorization: Bearer bsr_live_abc123def456...
API keys start with bsr_live_ (production) or bsr_test_ (sandbox). Test keys send to a simulated network — no messages are delivered and no balance is charged.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /v1/messages | Send single or batch SMS |
| GET | /v1/messages/{id} | Get message status and DLR |
| GET | /v1/messages | List messages with filters and pagination |
| DELETE | /v1/messages/{id} | Cancel a scheduled message |
| GET | /v1/balance | Check account balance |
| POST | /v1/webhooks | Create delivery report webhook |
| GET | /v1/webhooks | List configured webhooks |
| PUT | /v1/webhooks/{id} | Update a webhook |
| DELETE | /v1/webhooks/{id} | Delete a webhook |
| POST | /v1/templates | Create message template |
| GET | /v1/templates | List templates |
| PUT | /v1/templates/{id} | Update a template |
| DELETE | /v1/templates/{id} | Delete a template |
| GET | /v1/rates | List all country rates |
| GET | /v1/rates/{country} | Get per-network rates for a country |
| POST | /v1/verify | Validate a phone number |
| GET | /v1/account | Get account details and usage |
Sending Messages
Single message
POST /v1/messages
{
"to": "+447700900000",
"body": "Hi {{name}}, your code is {{code}}",
"from": "MyBrand",
"merge_fields": { "name": "Sarah", "code": "482910" },
"callback_url": "https://yourapp.com/dlr",
"idempotency_key": "order-confirm-4821"
}Batch send (up to 10,000)
POST /v1/messages
{
"messages": [
{ "to": "+447700900001", "body": "Hi Alice, sale ends tonight!" },
{ "to": "+447700900002", "body": "Hi Bob, sale ends tonight!" }
],
"from": "MyBrand"
}Response
{
"id": "msg_abc123",
"to": "+447700900000",
"from": "MyBrand",
"body": "Hi Sarah, your code is 482910",
"status": "queued",
"segments": 1,
"cost": 0.032,
"currency": "GBP",
"created_at": "2024-01-15T10:29:55Z"
}Delivery Reports
Query message status via the API or receive real-time updates via webhooks.
GET /v1/messages/msg_abc123
{
"id": "msg_abc123",
"status": "delivered", // queued | sent | delivered | failed | expired | rejected
"status_code": "DELIVRD", // SMPP status code
"error_code": null,
"submitted_at": "2024-01-15T10:29:55Z",
"delivered_at": "2024-01-15T10:30:00Z",
"network": "EE",
"country": "GB"
}See the Delivery Reports guide for full status code reference and webhook setup.
Webhooks
Configure webhook endpoints to receive real-time delivery reports and inbound SMS. Webhooks are signed with HMAC-SHA256 for security.
POST /v1/webhooks
{
"url": "https://yourapp.com/sms-webhook",
"events": ["delivered", "failed", "expired", "inbound"],
"secret": "whsec_your_secret_key"
}
// Verify webhook signature:
// X-BSR-Signature: sha256=HMAC(payload, secret)Webhooks retry 3 times with exponential backoff (5s, 30s, 5min) on non-2xx responses. Failed webhooks are logged and visible in the dashboard.
Error Codes
| Code | Name | Description |
|---|---|---|
| 400 | Bad Request | The request body is malformed or missing required fields. |
| 401 | Unauthorized | API key is missing, invalid, or expired. |
| 402 | Payment Required | Insufficient account balance to send the message(s). |
| 404 | Not Found | The requested resource (message, webhook, template) doesn't exist. |
| 409 | Conflict | Duplicate request or resource already exists. |
| 422 | Unprocessable Entity | Validation failed (e.g. invalid phone number, empty body, sender ID too long). |
| 429 | Too Many Requests | Rate limit exceeded. |
| 500 | Internal Server Error | Something went wrong on our end. |
| 503 | Service Unavailable | Temporary maintenance or overload. |
// Error response format
{
"error": {
"code": "validation_error",
"message": "Invalid phone number format",
"details": [
{ "field": "to", "message": "Must be E.164 format (e.g. +447700900000)" }
]
}
}Rate Limits
| Plan | Requests/sec | Batch size |
|---|---|---|
| Free trial | 10 | 100 |
| Pay-as-you-go | 100 | 10,000 |
| Enterprise | 1,000+ | 100,000 |
Rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
Idempotency
Prevent duplicate sends by including an idempotency_key in your POST requests. If we receive the same key within 24 hours, we return the original response without re-sending.
POST /v1/messages
{
"to": "+447700900000",
"body": "Your OTP is 482910",
"idempotency_key": "otp-user-123-attempt-1"
}Official SDKs
Python
pip install bulksmsratesv1.2.0
Node.js
npm install bulksmsratesv1.1.0
PHP
composer require bulksmsrates/sdkv1.0.3
Ruby
gem install bulksmsratesv1.0.1