sebpay / sebpay-php
Official PHP SDK for Sebpay hosted checkout — create a checkout session, redirect your customer, confirm the payment and verify webhooks.
Requires
- php: ^8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Official PHP SDK for Sebpay hosted checkout. It does four things:
- create a checkout session;
- redirect your customer to the Sebpay payment page;
- confirm the payment when they come back;
- verify Sebpay's webhooks.
It has no dependency besides ext-curl and ext-json. Direct collections, payouts and reference data are not part of the SDK. They remain available over plain HTTP: see docs/SEBPAY_PUBLIC_API.md.
Install
Not yet published on Packagist. For now, require it as a local path repository:
{
"repositories": [
{ "type": "path", "url": "../sebpay/sdks/php" }
],
"require": {
"sebpay/sebpay-php": "*"
}
}
Usage
1. Create a session and redirect your customer
use Sebpay\SebpayClient; // Keys from your dashboard (API développeur): pk_test_ keys go to the sandbox server, pk_live_ keys to live. $sebpay = new SebpayClient(getenv('SEBPAY_PUBLIC_KEY'), getenv('SEBPAY_SECRET_KEY')); $session = $sebpay->checkoutSessions->create([ 'amount' => 5000, 'currency' => 'XOF', 'redirect_url' => 'https://yoursite.com/orders/return', 'external_reference' => $order->id, // your order id: sending it again returns the same session 'callback_url' => 'https://yoursite.com/webhook/sebpay', 'metadata' => ['order_id' => $order->id], ]); header('Location: ' . $session['checkout_url']);
2. Confirm the payment when your customer comes back
Your redirect_url receives ?checkout_session_id=<id>. Coming back proves nothing, so ask Sebpay before you deliver:
$session = $sebpay->checkoutSessions->retrieve($_GET['checkout_session_id']); if ($session['transaction_status'] === 'approved') { // Paid: deliver the order ($session['external_reference'], $session['metadata']). }
retrieve() also accepts your external_reference.
3. Verify the webhook
Sebpay POSTs the final status (approved or rejected) to your callback_url. For a checkout, the request also carries checkout_session_id and your metadata.
use Sebpay\Webhooks\WebhookVerifier; $rawBody = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_SEBPAY_SIGNATURE'] ?? null; // header WebhookVerifier::SIGNATURE_HEADER if (!WebhookVerifier::verify($rawBody, $signature, getenv('SEBPAY_SECRET_KEY'))) { http_response_code(401); exit; } $payload = json_decode($rawBody, true); // $payload['status']: "approved" | "rejected"
- Always pass the raw request body. Re-serializing the decoded payload can reorder keys and break the signature.
- A missing header returns
false.
Options
new SebpayClient($publicKey, $secretKey, baseUrl: 'http://localhost:8000/api/v1', // only to test against a local API; otherwise chosen from the keys timeout: 10, // seconds, default 30 );
$sebpay->baseUrl tells which server the client talks to.
Errors
Every failed call throws a Sebpay\Exceptions\SebpayApiException, with three properties:
httpStatus: the HTTP status, or 0 when no response came back;errorCode: the API'serrors.code, or one of the SDK's own codes. Examples:EXTERNAL_REFERENCE_CONFLICT,RATE_LIMITED,WRONG_ENVIRONMENT,NETWORK_ERROR,TIMEOUT,INVALID_RESPONSE. It isnullotherwise;errorBody: the decoded response.
use Sebpay\Exceptions\SebpayApiException; try { $sebpay->checkoutSessions->create([...]); } catch (SebpayApiException $e) { if ($e->errorCode === 'EXTERNAL_REFERENCE_CONFLICT') { // This order id was already used with other parameters. } }
Examples
See examples/. Run composer install, set SEBPAY_PUBLIC_KEY and SEBPAY_SECRET_KEY, then:
php examples/create-checkout.phpcreates a session and prints itscheckout_url;php -S 127.0.0.1:3003 examples/webhook-server.phpserves the webhook and the return page.
For local testing, also set SEBPAY_BASE_URL.
Tests
composer test (or php tests/run.php) runs the SDK's offline tests. They cover the transport, against a local php -S started by the script, and the shared signature vectors.
Requirements
PHP 8.1+ with ext-curl and ext-json.