SMS API Integration Guide: PHP, Laravel, Node.js, Python & Flutter
Complete developer guide to sending SMS via REST API — copy-paste examples for PHP, Laravel, Node.js, Python, and Flutter OTP integration.
Short answer: To send SMS via API, POST JSON to https://api.smsprovider.net/api/send-sms with yourapi_key, approved sender_id, Bangladesh phone number, and message text. Every language below follows the same REST contract — only the HTTP client differs.
SMS Provider uses a single REST endpoint for transactional SMS, OTP, and alerts in Bangladesh. This guide covers production-ready examples for PHP, Laravel,Node.js, Python, and a Flutter OTP flow where your backend holds the API key.
Prerequisites: Verified account, API key fromDashboard → API Key, approved sender ID, and sufficient balance. See the full API documentation for parameters and error codes.
How to Send SMS Using PHP
PHP is widely used for Bangladeshi e-commerce, billing, and OTP systems. The simplest approach iscURL with JSON — no extra packages required on most hosting.
- Store
SMS_API_KEYin your environment or.envfile — never commit it to Git. - Validate the phone number before calling the API (must start with
01and be 11 digits). - POST to
https://api.smsprovider.net/api/send-smsand persist the returnedmessage_id. - Handle 402 (low balance) and 429 (rate limit) with retry logic.
<?php
function sendSms(string $phone, string $message, string $senderId = 'YourBrand'): array
{
$payload = [
'api_key' => getenv('SMS_API_KEY'),
'sender_id' => $senderId,
'phone' => $phone,
'message' => $message,
];
$ch = curl_init('https://api.smsprovider.net/api/send-sms');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 15,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($response, true) ?? [];
if ($status === 200 && ($data['success'] ?? false)) {
return ['ok' => true, 'message_id' => $data['message_id']];
}
return ['ok' => false, 'error' => $data['message'] ?? 'SMS request failed'];
}
// Send OTP
$result = sendSms('01712345678', 'Your verification code is 482910. Valid for 5 minutes.');Laravel SMS API Guide
In Laravel, wrap the HTTP call in a dedicated service class. Use config() for credentials and Laravel's built-in Http facade for clean, testable code.
1. Configure credentials
# config/services.php
'sms' => [
'endpoint' => env('SMS_ENDPOINT', 'https://api.smsprovider.net/api/send-sms'),
'api_key' => env('SMS_API_KEY'),
'sender_id' => env('SMS_SENDER_ID', 'YourBrand'),
],2. Create an SmsService
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class SmsService
{
public function send(string $phone, string $message, ?string $senderId = null): string
{
$response = Http::acceptJson()
->timeout(15)
->post(config('services.sms.endpoint'), [
'api_key' => config('services.sms.api_key'),
'sender_id' => $senderId ?? config('services.sms.sender_id'),
'phone' => $phone,
'message' => $message,
]);
if ($response->successful() && $response->json('success')) {
return $response->json('message_id');
}
Log::warning('SMS failed', [
'phone' => $phone,
'status' => $response->status(),
'body' => $response->json(),
]);
throw new \RuntimeException($response->json('message', 'SMS delivery failed'));
}
}Inject SmsService into your auth controller. For OTP, generate the code server-side, send via SMS, and store in Cache::put() with a 300-second TTL. Rate-limit the/send-otp route to prevent abuse.
Node.js SMS API
Node.js fits microservices, serverless functions, and Express/Fastify backends. Use the nativefetch API (Node 18+) or axios in older versions.
- Keep
SMS_API_KEYin process environment — use AWS Secrets Manager or similar in production. - Return generic errors to clients; log detailed SMS API responses server-side only.
- Respect the 60 requests/minute rate limit per API key.
import 'dotenv/config';
const SMS_ENDPOINT = process.env.SMS_ENDPOINT ?? 'https://api.smsprovider.net/api/send-sms';
export async function sendSms(phone, message, senderId = 'YourBrand') {
const response = await fetch(SMS_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
api_key: process.env.SMS_API_KEY,
sender_id: senderId,
phone,
message,
}),
});
const data = await response.json();
if (!response.ok || !data.success) {
throw new Error(data.message ?? `SMS failed (${response.status})`);
}
return data.message_id;
}
// Express route — always send OTP from your server, never from the app
app.post('/auth/send-otp', async (req, res) => {
const otp = String(Math.floor(100000 + Math.random() * 900000));
await storeOtp(req.body.phone, otp);
const messageId = await sendSms(req.body.phone, `Your code is ${otp}. Expires in 5 min.`);
res.json({ ok: true, message_id: messageId });
});Python SMS API
Python integrations commonly run on Django, FastAPI, or Flask. The requests library is sufficient for synchronous OTP sends; use httpx for async FastAPI routes.
import os
import requests
SMS_ENDPOINT = os.getenv("SMS_ENDPOINT", "https://api.smsprovider.net/api/send-sms")
def send_sms(phone: str, message: str, sender_id: str = "YourBrand") -> str:
response = requests.post(
SMS_ENDPOINT,
json={
"api_key": os.environ["SMS_API_KEY"],
"sender_id": sender_id,
"phone": phone,
"message": message,
},
headers={"Accept": "application/json"},
timeout=15,
)
data = response.json()
if response.status_code == 200 and data.get("success"):
return data["message_id"]
raise RuntimeError(data.get("message", "SMS request failed"))
# Django view example
def send_otp_view(request):
otp = f"{random.randint(100000, 999999):06d}"
message_id = send_sms(request.POST["phone"], f"Your code is {otp}. Valid 5 minutes.")
cache.set(f"otp:{request.POST['phone']}", otp, timeout=300)
return JsonResponse({"ok": True, "message_id": message_id})For high-volume batch sending, queue messages with Celery or Redis and process them with exponential backoff on 429 responses.
Flutter OTP SMS Tutorial
Flutter apps must never contain your SMS API key. Mobile binaries can be decompiled; exposing the key allows anyone to send SMS on your balance.
Recommended architecture
- User enters phone number in the Flutter app.
- App calls your backend (
POST /auth/send-otp). - Backend generates OTP, stores it in Redis/database, calls SMS Provider API.
- App receives success response and shows OTP input screen.
- User submits OTP → backend verifies against stored value.
// Flutter calls YOUR backend — never embed the SMS API key in the app.
// Dart (client)
Future<void> requestOtp(String phone) async {
final res = await http.post(
Uri.parse('https://your-api.com/auth/send-otp'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'phone': phone}),
);
if (res.statusCode != 200) throw Exception('Could not send OTP');
}Optional: use SMS autofill on Android/iOS for better UX, but always validate OTP on the server. See our OTP best practices guide for security details.
Frequently asked questions
How do I send SMS using PHP?
Use PHP cURL or Guzzle to POST JSON to your SMS provider's /send-sms endpoint with api_key, sender_id, phone, and message. Store the API key in environment variables, validate Bangladesh phone format (01XXXXXXXXX), and log the returned message_id for delivery tracking.
Can I call the SMS API directly from Flutter?
No — never put your SMS API key in a Flutter or mobile app. Build a backend endpoint that generates the OTP, calls the SMS API server-side, and returns only a success/failure status to the app.
What phone number format does the SMS API accept?
Bangladesh mobile numbers in local format (01712345678) or international format (8801712345678). Invalid numbers return a 400 error before any balance is charged.
How do I send OTP SMS with Laravel?
Create an SmsService class using Laravel's HTTP client, store credentials in config/services.php, generate a 6-digit OTP in your controller, send it via the service, and store the OTP in cache or database with a 5-minute expiry.
Ready to integrate? Read the full API documentation, create a free account, or contact us on WhatsApp.