# BulkSMSRates PHP SDK

Official PHP client for the [BulkSMSRates](https://bulksmsrates.com) REST API.

## Requirements

- PHP **8.0+**
- `ext-curl`
- `ext-json`

## Installation

```bash
# Copy BulkSMSRates.php to your project (Composer package coming soon)
cp BulkSMSRates.php /your/project/lib/
```

```php
require_once 'lib/BulkSMSRates.php';
```

## Quick Start

```php
<?php
require_once 'BulkSMSRates.php';

$client = new BulkSMSRates(
    apiKey: $_ENV['BULKSMS_API_KEY'],
    apiSecret: $_ENV['BULKSMS_API_SECRET']
);

// Send a single SMS
$result = $client->sendSms('+447700900123', 'Hello from BulkSMSRates!');
echo "Message ID: {$result['id']}, Status: {$result['status']}\n";

// Check balance
$balance = $client->getBalance();
echo "Balance: £" . ($balance['balance'] / 100) . " {$balance['currency']}\n";
```

## Authentication

### API Key + Secret (recommended)

```php
$client = new BulkSMSRates('bsms_live_abc123', 'sk_live_xyz789');
```

### JWT Bearer Token

```php
$client = new BulkSMSRates(accessToken: 'eyJhbGci...');

// Or login with email/password:
$client = new BulkSMSRates('placeholder', 'placeholder');
$tokens = $client->login('user@example.com', 'password');
// Access token is automatically stored in the client
```

## Sandbox Mode

```php
$client = new BulkSMSRates(
    apiKey: 'bsms_test_...',
    apiSecret: 'sk_test_...',
    sandbox: true
);

$result = $client->sendSms('+447700900123', 'Test message');
echo $result['id'];       // Fake message ID
echo $result['sandbox'];  // true

$client->resetSandbox();  // Clear sandbox messages
```

## Send SMS

```php
// Basic
$result = $client->sendSms('+447700900123', 'Hello!');

// With all options
$result = $client->sendSms(
    destination: '+447700900123',
    message: 'Hi {{name}}, your code is {{code}}!',
    senderId: 'MyApp',
    scheduledAt: '2026-03-15T09:00:00Z',
    clientRef: 'order-123',
    variables: ['name' => 'Alice', 'code' => '1234']
);
echo "ID: {$result['id']}\n";
```

## Bulk SMS

```php
$result = $client->sendBulk(
    recipients: ['+447700900001', '+447700900002', '+447700900003'],
    message: 'Flash sale! 30% off today only.',
    senderId: 'MyShop'
);

echo "Batch: {$result['batch_id']}\n";
echo "Accepted: {$result['accepted']}, Rejected: {$result['rejected']}\n";
```

## Campaigns

```php
// Create
$campaign = $client->createCampaign(
    name: 'Spring Sale 2026',
    message: 'Hi {{name}}, get 30% off this weekend!',
    senderId: 'MyShop',
    scheduledAt: '2026-03-15T08:00:00Z'
);
$campaignId = $campaign['id'];

// Submit for sending
$client->submitCampaign($campaignId);

// Monitor progress
$status = $client->getCampaign($campaignId);
echo "Progress: {$status['sent']}/{$status['total']}\n";

// Control
$client->pauseCampaign($campaignId);
$client->resumeCampaign($campaignId);
$client->cancelCampaign($campaignId);
```

## Contacts

```php
// Create a contact
$contact = $client->createContact(
    phone: '+447700900123',
    name: 'Alice Smith',
    email: 'alice@example.com',
    customFields: ['tier' => 'VIP']
);

// List contacts
$result = $client->listContacts(page: 1, perPage: 50, search: 'Alice');
foreach ($result['data'] as $c) {
    echo "{$c['name']}: {$c['phone']}\n";
}

// Update
$client->updateContact($contact['id'], ['name' => 'Alice Jones']);

// Delete
$client->deleteContact($contact['id']);

// Groups
$group = $client->createGroup('VIP Customers');
$client->addGroupMembers($group['id'], [$contact['id']]);

// Tags
$tag = $client->createTag('Newsletter', '#0066cc');
```

## Billing

```php
$balance = $client->getBalance();
echo "Available: £" . ($balance['available'] / 100) . " {$balance['currency']}\n";

$txns = $client->listTransactions(page: 1, perPage: 20);
foreach ($txns['data'] as $t) {
    $amount = $t['amount'] / 100;
    echo "{$t['type']}: £{$amount} — {$t['created_at']}\n";
}
```

## Error Handling

```php
use function array_key_exists;

try {
    $result = $client->sendSms('+447700900123', 'Hello!');
} catch (InsufficientBalanceException $e) {
    echo "Top up required! Balance too low.\n";
    var_dump($e->details);
} catch (RateLimitException $e) {
    echo "Rate limited. Retry in {$e->retryAfter}s\n";
    sleep($e->retryAfter);
} catch (AuthException $e) {
    echo "Auth failed [{$e->errorCode}]: {$e->getMessage()}\n";
} catch (ValidationException $e) {
    echo "Invalid params: {$e->getMessage()}\n";
} catch (BulkSMSRatesException $e) {
    echo "API error {$e->statusCode} [{$e->errorCode}]: {$e->getMessage()}\n";
} catch (\RuntimeException $e) {
    echo "Network error: {$e->getMessage()}\n";
}
```

## Rate Limit Info

```php
$result = $client->sendSms('+447700900123', 'Hello!');

echo "Limit: {$client->rateLimit->limit}\n";
echo "Remaining: {$client->rateLimit->remaining}\n";
echo "Reset: {$client->rateLimit->reset}\n";
```

## Pagination

```php
// Automatic pagination via generator
foreach ($client->paginate('/sms', ['status' => 'delivered']) as $msg) {
    echo "{$msg['id']}: {$msg['status']}\n";
}

// Manual pagination
$page = 1;
do {
    $result = $client->listMessages(page: $page, perPage: 100);
    foreach ($result['data'] as $msg) {
        // process $msg
    }
    $page++;
} while (count($result['data']) === 100);
```

## Auto-Retry

```php
// Retry up to 5 times with 2s base backoff
$client = new BulkSMSRates(
    apiKey: '...',
    apiSecret: '...',
    maxRetries: 5,
    retryBackoff: 2.0
);

// Disable retries
$client = new BulkSMSRates(apiKey: '...', apiSecret: '...', maxRetries: 0);
```

## API Reference

| Method | Description |
|--------|-------------|
| `sendSms($dest, $msg, ...)` | Send a single SMS |
| `sendBulk($recipients, $msg, ...)` | Send to multiple recipients |
| `getMessage($id)` | Get message status |
| `listMessages($page, $perPage, $status)` | List messages |
| `getBalance()` | Get wallet balance |
| `listTransactions($page, $perPage)` | Transaction history |
| `createCampaign($name, $msg, ...)` | Create campaign |
| `listCampaigns($page, $perPage)` | List campaigns |
| `getCampaign($id)` | Campaign details + progress |
| `submitCampaign($id)` | Submit for sending |
| `pauseCampaign($id)` | Pause campaign |
| `resumeCampaign($id)` | Resume campaign |
| `cancelCampaign($id)` | Cancel campaign |
| `createContact($phone, ...)` | Create contact |
| `listContacts($page, $perPage, ...)` | List contacts |
| `updateContact($id, $updates)` | Update contact |
| `deleteContact($id)` | Delete contact |
| `createGroup($name, $desc)` | Create group |
| `addGroupMembers($gId, $ids)` | Add contacts to group |
| `createTag($name, $color)` | Create tag |
| `me()` | Get current user |
| `login($email, $password)` | Login and store token |
| `paginate($path, $params, $perPage)` | Generator over pages |
| `resetSandbox()` | Reset sandbox state |

## License

MIT

## Support

- 📧 support@bulksmsrates.com
- 📖 https://bulksmsrates.com/docs
