SDK PHP
xaalis/xaalis-php encapsule l’API pour les serveurs PHP 8.1+. Aucune dépendance à l’exécution en dehors de ext-curl
et ext-json ; licence MIT. En attendant sa publication sur Packagist (composer require xaalis/xaalis-php),
téléchargez xaalis-php-0.1.0.zip dans un dossier (ici packages/) et laissez Composer
l’installer depuis ce dossier :
{ "repositories": [{ "type": "artifact", "url": "packages/" }], "require": { "xaalis/xaalis-php": "^0.1" }}Sans Composer, décompressez-le dans xaalis-php/ et faites require 'xaalis-php/autoload.php';. Toutes les versions : Téléchargements.
require __DIR__ . '/vendor/autoload.php';
$xaalis = new Xaalis\Client(getenv('XAALIS_SECRET_KEY'), ['base_url' => 'https://sandbox-api.xaalis.org']);
$payment = $xaalis->payments->create( [ 'amount' => 15000, // int, XOF — jamais un float ni une chaîne 'description' => 'Commande #1042', 'client_reference' => 'order_1042', 'success_url' => 'https://shop.example/merci', 'metadata' => ['order_id' => '1042'], ], ['idempotency_key' => 'payment:order_1042'],);
header('Location: ' . $payment['checkout_url']); // page de paiement hébergéeLes réponses sont des tableaux associatifs avec les mêmes champs que l’API (objet paiement).
| Service | Méthodes |
|---|---|
payments |
create, retrieve, list, all (générateur sur toutes les pages) |
payouts |
create, retrieve, list, all |
balance |
retrieve |
account |
retrieve, update(['webhook_url' => 'https://…']) |
webhookDeliveries |
list(['limit' => 20]) |
testHelpers |
simulatePayment($id, 'succeeded' | 'failed') — clés de test uniquement |
Xaalis\Webhook::constructEvent($raw, $header, $secret) |
vérifie et décode un webhook |
| Option | Valeur par défaut | |
|---|---|---|
base_url |
selon la clé | https://sandbox-api.xaalis.org pour une clé sk_test_…, https://api.xaalis.org pour sk_live_…. Refusés : une clé de production sur http:// ou vers sandbox-api.xaalis.org, une clé de test vers api.xaalis.org ou http://sandbox-api.xaalis.org, et toute URL avec identifiants, paramètres de requête ou fragment. Les autres hôtes (un proxy, http://localhost:4000) sont acceptés. Le SDK 0.1.0 utilisait https://api.xaalis.sn pour toutes les clés, qui ne répond pas, et ne refuse aucun de ces hôtes : en 0.1.0, passez toujours le base_url qui correspond à votre clé |
timeout |
30 |
secondes par tentative |
max_retries |
2 |
nouvelles tentatives après la première |
http |
curl | fn($method, $url, $headers, $body, $timeout) qui renvoie ['status', 'body', 'headers'] — pour les tests |
La clé doit être de la forme sk_test_… / sk_live_… (40 caractères après le préfixe) ; elle n’apparaît jamais dans
les messages d’exception ni dans var_dump($xaalis). $xaalis->testMode vaut true pour les clés de test.
Ce qu’il fait pour vous
Section intitulée « Ce qu’il fait pour vous »- Idempotence : chaque
createenvoie uneIdempotency-Key— un UUID v4 aléatoire si vous ne passez pasidempotency_key— et la réutilise à chaque nouvelle tentative. Passez la vôtre (votre numéro de commande) pour rester protégé même en cas de redémarrage du processus. Voir Idempotence. - Nouvelles tentatives : erreurs réseau,
429et5xx, avec un délai exponentiel et prise en compte deRetry-After— uniquement quand rejouer la requête est sans risque :GET,PATCH, ou une création accompagnée de sa clé. Un4xxn’est jamais relancé. - Entiers uniquement :
amountdoit être unintPHP ;150.5,15000.0et"15000"lèvent\InvalidArgumentExceptionavant tout envoi.
use Xaalis\Exception\ApiException;use Xaalis\Exception\ConnectionException;
try { $xaalis->payouts->create(['amount' => 5000, 'provider' => 'wave', 'recipient' => ['phone' => '+221770000001']]);} catch (ApiException $e) { if ($e->getErrorCode() === 'insufficient_funds') { // afficher « solde insuffisant » } else { throw $e; }} catch (ConnectionException $e) { // résultat inconnu : réessayer plus tard avec la MÊME idempotency_key}| Exception | Quand |
|---|---|
Xaalis\Exception\XaalisException |
classe de base des trois suivantes |
ApiException |
l’API a répondu par une erreur : getStatus(), getErrorCode() (stable, voir Erreurs), getMessage(), getDetails() |
ConnectionException |
panne réseau ou délai dépassé après les nouvelles tentatives |
SignatureException |
un webhook n’a pas passé la vérification — répondez 400 |
Webhooks
Section intitulée « Webhooks »$raw = file_get_contents('php://input'); // les octets exacts, jamais un tableau ré-encodétry { $event = Xaalis\Webhook::constructEvent($raw, $_SERVER['HTTP_XAALIS_SIGNATURE'] ?? null, getenv('XAALIS_WEBHOOK_SECRET'));} catch (Xaalis\Exception\SignatureException $e) { http_response_code(400); exit;}
if ($event['livemode'] !== $expectLive || alreadyProcessed($event['id'])) { // test et production partagent une URL ; au moins une fois http_response_code(200); exit;}if ($event['type'] === 'payment.succeeded') { $payment = $event['data']['object']; // comparer $payment['amount'] et $payment['metadata'] à votre commande, puis la traiter une seule fois}http_response_code(200);constructEvent rejette un en-tête absent ou mal formé, un horodatage éloigné de plus de 300 s de l’heure actuelle
(rejeux), et une signature qui ne correspond à aucun v1 (comparaison avec hash_equals).
integrations/sdk-php/tests/docker-test.sh exécute php -l et la suite de tests dans php:8.3-cli. Si ADMIN_TOKEN
est défini dans le .env à la racine du dépôt, il exécute aussi un parcours réel contre l’API locale : création d’un
commerçant, d’un paiement de 15 000 (frais de 225), simulation de la réussite, vérification que le solde vaut 14 775,
et vérification qu’un versement de 99 000 000 échoue avec insufficient_funds.
Pour les boutiques WooCommerce, utilisez plutôt l’extension WooCommerce — elle ne nécessite pas Composer.