PHP Integration

Complete guide to integrate NestSMS into your PHP applications with practical examples using cURL for sending SMS, handling responses, and tracking delivery status.

Setup

Environment Variables

Create a .env file or use php.ini:

<?php
// config.php
define('NESTSMS_API_KEY', 'nsms_live_your_api_key_here');
define('NESTSMS_BASE_URL', 'https://api.nestsms.com/api/v1');
define('NESTSMS_SENDER_ID', 'YourBrand');
?>

PHP Examples

Send SMS

<?php
// send_sms.php
require_once 'config.php';

function sendSMS($phoneNumber, $message, $senderName = 'YourBrand') {
    $url = NESTSMS_BASE_URL . '/sms/send';

    $data = array(
        'to' => $phoneNumber,
        'message' => $message,
        'sender_id' => $senderName,
        'message_type' => 'transactional'
    );

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'X-API-Key: ' . NESTSMS_API_KEY,
        'Content-Type: application/json'
    ));

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $result = json_decode($response, true);

    if ($httpCode === 200 && $result['success']) {
        echo "✓ SMS sent successfully!\n";
        echo "Job ID: " . $result['job_id'] . "\n";
        echo "Cost: " . $result['cost'] . "\n";
        return $result;
    } else {
        echo "✗ Error: " . $result['error'] . "\n";
        echo "Code: " . $result['code'] . "\n";
        return false;
    }
}

// Usage
sendSMS('9840123456', 'Hello from NestSMS API!');
?>

Send Bulk SMS

<?php
// send_bulk_sms.php
function sendBulkSMS($recipients, $message, $senderName = 'YourBrand') {
    if (!is_array($recipients) || count($recipients) > 1000) {
        die("Recipients must be an array (max 1000)\n");
    }

    $url = NESTSMS_BASE_URL . '/sms/send';

    $data = array(
        'to' => $recipients,
        'message' => $message,
        'sender_id' => $senderName,
        'message_type' => 'promotional'
    );

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'X-API-Key: ' . NESTSMS_API_KEY,
        'Content-Type: application/json'
    ));

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $result = json_decode($response, true);

    if ($httpCode === 200 && $result['success']) {
        echo "✓ Bulk SMS sent to " . $result['recipients_count'] . " recipients\n";
        echo "Total cost: " . $result['cost'] . "\n";
        return $result;
    } else {
        echo "✗ Error: " . $result['error'] . "\n";
        return false;
    }
}

// Usage
$recipients = array('9840123456', '9851234567', '9861345678');
sendBulkSMS($recipients, 'Special offer! Get 50% off today.');
?>

Check SMS Status

<?php
// check_status.php
function checkSMSStatus($messageId) {
    $url = NESTSMS_BASE_URL . '/sms/status/' . $messageId;

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'X-API-Key: ' . NESTSMS_API_KEY
    ));

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $result = json_decode($response, true);

    if ($httpCode === 200 && $result['success']) {
        echo "Status: " . $result['status'] . "\n";
        echo "Sent at: " . $result['sent_at'] . "\n";
        echo "Delivered at: " . ($result['delivered_at'] ?? 'N/A') . "\n";
        return $result;
    } else {
        echo "✗ Error: " . $result['error'] . "\n";
        return false;
    }
}

// Usage
checkSMSStatus('550e8400-e29b-41d4-a716-446655440000');
?>

Get Account Balance

<?php
// get_balance.php
function getBalance() {
    $url = NESTSMS_BASE_URL . '/sms/balance';

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'X-API-Key: ' . NESTSMS_API_KEY
    ));

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $result = json_decode($response, true);

    if ($httpCode === 200 && $result['success']) {
        echo "Balance: " . $result['balance'] . " " . $result['currency'] . "\n";
        echo "SMS sent today: " . $result['sms_sent_today'] . "\n";
        echo "SMS sent this month: " . $result['sms_sent_this_month'] . "\n";
        return $result;
    } else {
        echo "✗ Error: " . $result['error'] . "\n";
        return false;
    }
}

// Usage
getBalance();
?>

PHP Client and Framework Integration

Complete PHP Client Class

<?php
// NestSMSClient.php
class NestSMSClient {
    private $apiKey;
    private $baseUrl;

    public function __construct($apiKey, $baseUrl = 'https://api.nestsms.com/api/v1') {
        $this->apiKey = $apiKey;
        $this->baseUrl = $baseUrl;
    }

    public function sendSMS($to, $message, $options = array()) {
        $url = $this->baseUrl . '/sms/send';

        $data = array_merge(array(
            'to' => $to,
            'message' => $message,
            'sender_id' => 'YourBrand',
            'message_type' => 'transactional'
        ), $options);

        return $this->makeRequest('POST', $url, $data);
    }

    public function sendBulkSMS($recipients, $message, $options = array()) {
        if (!is_array($recipients) || count($recipients) > 1000) {
            throw new Exception('Recipients must be an array (max 1000)');
        }

        $url = $this->baseUrl . '/sms/send';

        $data = array_merge(array(
            'to' => $recipients,
            'message' => $message,
            'sender_id' => 'YourBrand',
            'message_type' => 'promotional'
        ), $options);

        return $this->makeRequest('POST', $url, $data);
    }

    public function checkStatus($messageId) {
        $url = $this->baseUrl . '/sms/status/' . $messageId;
        return $this->makeRequest('GET', $url);
    }

    public function getBalance() {
        $url = $this->baseUrl . '/sms/balance';
        return $this->makeRequest('GET', $url);
    }

    private function makeRequest($method, $url, $data = null) {
        $ch = curl_init($url);

        $headers = array(
            'X-API-Key: ' . $this->apiKey,
            'Content-Type: application/json'
        );

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            $error = curl_error($ch);
            curl_close($ch);
            throw new Exception('cURL Error: ' . $error);
        }

        curl_close($ch);

        $result = json_decode($response, true);

        if ($httpCode >= 400) {
            throw new Exception(
                'API Error (' . $httpCode . '): ' .
                ($result['error'] ?? 'Unknown error') .
                ' [' . ($result['code'] ?? 'N/A') . ']'
            );
        }

        return $result;
    }
}

// Usage Example
$client = new NestSMSClient(NESTSMS_API_KEY);

try {
    // Send SMS
    $result = $client->sendSMS('9840123456', 'Hello from PHP!');
    print_r($result);

    // Get balance
    $balance = $client->getBalance();
    print_r($balance);

} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
}
?>

Laravel Configuration

<?php
// config/nestsms.php
return [
    'api_key' => env('NESTSMS_API_KEY'),
    'base_url' => env('NESTSMS_BASE_URL', 'https://api.nestsms.com/api/v1'),
    'sender_id' => env('NESTSMS_SENDER_ID', 'YourBrand'),
];
?>

Laravel Service Class

<?php
// app/Services/SMSService.php
namespace App\Services;

use Illuminate\Support\Facades\Http;

class SMSService {
    protected $apiKey;
    protected $baseUrl;
    protected $senderId;

    public function __construct() {
        $this->apiKey = config('nestsms.api_key');
        $this->baseUrl = config('nestsms.base_url');
        $this->senderId = config('nestsms.sender_id');
    }

    public function sendSMS($phoneNumber, $message, $messageType = 'transactional') {
        $response = Http::withHeaders([
            'X-API-Key' => $this->apiKey,
            'Content-Type' => 'application/json'
        ])->post($this->baseUrl . '/sms/send', [
            'to' => $phoneNumber,
            'message' => $message,
            'sender_id' => $this->senderId,
            'message_type' => $messageType
        ]);

        if ($response->failed()) {
            throw new \Exception('Failed to send SMS: ' . $response->json('error'));
        }

        return $response->json();
    }

    public function sendBulkSMS($recipients, $message) {
        if (!is_array($recipients) || count($recipients) > 1000) {
            throw new \Exception('Recipients must be an array (max 1000)');
        }

        $response = Http::withHeaders([
            'X-API-Key' => $this->apiKey,
            'Content-Type' => 'application/json'
        ])->post($this->baseUrl . '/sms/send', [
            'to' => $recipients,
            'message' => $message,
            'sender_id' => $this->senderId,
            'message_type' => 'promotional'
        ]);

        if ($response->failed()) {
            throw new \Exception('Failed to send bulk SMS: ' . $response->json('error'));
        }

        return $response->json();
    }

    public function checkStatus($messageId) {
        $response = Http::withHeaders([
            'X-API-Key' => $this->apiKey
        ])->get($this->baseUrl . '/sms/status/' . $messageId);

        if ($response->failed()) {
            throw new \Exception('Failed to check status: ' . $response->json('error'));
        }

        return $response->json();
    }

    public function getBalance() {
        $response = Http::withHeaders([
            'X-API-Key' => $this->apiKey
        ])->get($this->baseUrl . '/sms/balance');

        if ($response->failed()) {
            throw new \Exception('Failed to get balance: ' . $response->json('error'));
        }

        return $response->json();
    }
}
?>

Laravel Controller

<?php
// app/Http/Controllers/SMSController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\SMSService;

class SMSController extends Controller {
    protected $smsService;

    public function __construct(SMSService $smsService) {
        $this->smsService = $smsService;
    }

    public function send(Request $request) {
        $request->validate([
            'to' => 'required|string',
            'message' => 'required|string|max:720'
        ]);

        try {
            $result = $this->smsService->sendSMS(
                $request->input('to'),
                $request->input('message')
            );

            return response()->json([
                'success' => true,
                'job_id' => $result['job_id'],
                'cost' => $result['cost']
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage()
            ], 500);
        }
    }

    public function bulk(Request $request) {
        $request->validate([
            'recipients' => 'required|array|max:1000',
            'message' => 'required|string|max:720'
        ]);

        try {
            $result = $this->smsService->sendBulkSMS(
                $request->input('recipients'),
                $request->input('message')
            );

            return response()->json([
                'success' => true,
                'job_id' => $result['job_id'],
                'recipients_count' => $result['recipients_count'],
                'cost' => $result['cost']
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage()
            ], 500);
        }
    }

    public function status($messageId) {
        try {
            $result = $this->smsService->checkStatus($messageId);

            return response()->json([
                'success' => true,
                'status' => $result['status'],
                'sent_at' => $result['sent_at'],
                'delivered_at' => $result['delivered_at'] ?? null
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage()
            ], 500);
        }
    }
}
?>

Laravel Routes

<?php
// routes/api.php
use App\Http\Controllers\SMSController;

Route::prefix('sms')->group(function () {
    Route::post('/send', [SMSController::class, 'send']);
    Route::post('/bulk', [SMSController::class, 'bulk']);
    Route::get('/status/{messageId}', [SMSController::class, 'status']);
});
?>

OTP Verification

OTP Service

<?php
// OTPService.php
class OTPService {
    private $smsClient;

    public function __construct($smsClient) {
        $this->smsClient = $smsClient;
    }

    public function generateOTP() {
        return str_pad(rand(0, 999999), 6, '0', STR_PAD_LEFT);
    }

    public function sendOTP($phoneNumber) {
        $otp = $this->generateOTP();

        // Store OTP in session or database
        $_SESSION['otp_' . $phoneNumber] = array(
            'code' => $otp,
            'expires_at' => time() + 300 // 5 minutes
        );

        // Send SMS
        $message = "Your verification code is $otp. Valid for 5 minutes.";
        $result = $this->smsClient->sendSMS(
            $phoneNumber,
            $message,
            array('message_type' => 'otp')
        );

        return array(
            'success' => true,
            'job_id' => $result['job_id']
        );
    }

    public function verifyOTP($phoneNumber, $enteredOTP) {
        $key = 'otp_' . $phoneNumber;

        if (!isset($_SESSION[$key])) {
            return array(
                'success' => false,
                'error' => 'OTP not found or expired'
            );
        }

        $stored = $_SESSION[$key];

        if (time() > $stored['expires_at']) {
            unset($_SESSION[$key]);
            return array(
                'success' => false,
                'error' => 'OTP expired'
            );
        }

        if ($stored['code'] !== $enteredOTP) {
            return array(
                'success' => false,
                'error' => 'Invalid OTP'
            );
        }

        // Clear OTP after successful verification
        unset($_SESSION[$key]);

        return array(
            'success' => true,
            'message' => 'OTP verified successfully'
        );
    }
}

// Usage
session_start();
$otpService = new OTPService(new NestSMSClient(NESTSMS_API_KEY));

// Send OTP
$otpService->sendOTP('9840123456');

// Verify OTP
$result = $otpService->verifyOTP('9840123456', '123456');
?>

Responses and Error Handling

Successful Response

{
  "success": true,
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "message": "SMS queued successfully",
  "recipients_count": 1,
  "cost": 1.5
}

Error Response

{
  "success": false,
  "error": "Insufficient balance",
  "code": "INSUFFICIENT_BALANCE"
}

Error Handling

<?php
function sendSMSWithRetry($phoneNumber, $message, $maxRetries = 3) {
    $attempt = 0;

    while ($attempt < $maxRetries) {
        try {
            $result = sendSMS($phoneNumber, $message);
            return $result;

        } catch (Exception $e) {
            $attempt++;
            echo "Attempt $attempt failed: " . $e->getMessage() . "\n";

            if ($attempt >= $maxRetries) {
                throw new Exception('Max retries exceeded');
            }

            // Exponential backoff
            sleep(pow(2, $attempt));
        }
    }
}
?>

Best Practices

  1. Never expose API keys in client-side code
  2. Use environment variables for sensitive data
  3. Implement proper error handling with try-catch blocks
  4. Store session data securely (use Redis for production OTP storage)
  5. Validate phone numbers before sending
  6. Log SMS activities for audit trails
  7. Implement rate limiting to prevent abuse

Next Steps