# PHP SDK

Official PHP client with retries, idempotency and webhook verification


The official PHP SDK wraps the same REST API documented here. It only needs
`ext-curl` and `ext-json` and adds retries, idempotency keys, auto-pagination and
webhook signature verification.

> **Status:** the package is not on Packagist yet. Until the first release lands you
> can install it from the repository, or use the plain REST examples in the other
> articles.

## Install

```bash
composer require southbill/southbill-php
```

Requires PHP 7.4 or newer.

## Create a checkout session

```php
use Southbill\Southbill;

$southbill = new Southbill(['api_key' => getenv('SOUTHBILL_API_KEY')]);

$session = $southbill->checkout->sessions->create([
    'amount' => 4900,
    'currency' => 'EUR',
    'customer_email' => 'ada@acme.com',
    'success_url' => 'https://acme.com/thanks',
]);

echo $session['checkout_url'];
```

All merchant API keys are live keys (`sk_live_...`). Southbill has no test mode.
`$southbill->isLivemode()` is `false` for them.

## Resources

| Namespace | Methods |
| --- | --- |
| `checkout->sessions` | `create`, `retrieve`, `all`, `expire` |
| `customers` | `create`, `retrieve`, `update`, `all`, `delete` |
| `invoices` | `create`, `retrieve`, `update`, `all`, `send`, `void`, `markPaid` |
| `products` | `create`, `retrieve`, `update`, `all` |
| `payments` | `retrieve`, `all` |
| `refunds` | `create` |
| `subscriptions` | `create`, `retrieve`, `all`, `cancel` |
| `events` | `retrieve`, `all`, `replay` |

Payouts, bank details, KYC and API-key management stay merchant-controlled in the
dashboard and are intentionally not part of the API surface.

## Idempotency

Every `POST` sends an `Idempotency-Key` header (random UUID). Pass your own for
safe retries across processes:

```php
$southbill->invoices->create($params, "inv-{$orderId}");
```

## Pagination

```php
foreach ($southbill->invoices->autoPagingEach(['status' => 'open']) as $invoice) {
    echo $invoice['id'];
}
```

## Errors and retries

Network errors, `429` and `5xx` are retried twice with exponential backoff
(configurable via `max_retries`). Everything else throws `Southbill\SouthbillError`:

```php
use Southbill\SouthbillError;

try {
    $southbill->refunds->create(['payment' => 'pi_123', 'amount' => 500]);
} catch (SouthbillError $e) {
    error_log("{$e->status} {$e->type} {$e->param} {$e->requestId}");
}
```

## Webhooks

Verify the raw request body — never a re-serialized array.

```php
use Southbill\Webhooks;
use Southbill\SouthbillSignatureError;

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_SOUTHBILL_SIGNATURE'] ?? '';

try {
    $event = Webhooks::constructEvent($payload, $signature, getenv('SOUTHBILL_WEBHOOK_SECRET'));
} catch (SouthbillSignatureError $e) {
    http_response_code(400);
    exit;
}

if ($event['type'] === 'invoice.paid') {
    // handle it
}

http_response_code(200);
```

Signature scheme: `Southbill-Signature: t=<unix seconds>,v1=<hex>` where the hex
digest is `HMAC-SHA256(secret, "<timestamp>.<raw body>")`. Default clock tolerance
is 300 seconds.

## Configuration

```php
new Southbill([
    'api_key' => getenv('SOUTHBILL_API_KEY'),
    'base_url' => 'https://api.southbill.com',
    'timeout' => 30,
    'max_retries' => 2,
]);
```

