wpay-bj / php-sdk
WPay PHP SDK -Vérification de transactions WebcoomPay
Requires
- php: ^8.1
- ext-hash: *
- ext-json: *
- guzzlehttp/guzzle: ^7.5
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.50
- phpunit/phpunit: ^10.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
SDK PHP officiel pour l'API WPay - vérification de transactions, orders et webhooks.
Installation
composer require wpay-bj/php-sdk
Prérequis : PHP 8.1+ avec les extensions json et hash.
Configuration
Tout ce dont vous avez besoin pour démarrer :
use WPay\WPay;
WPay::setSecretKey($_ENV['WPay_SECRET_KEY']);
C'est tout. Le SDK cible la production par défaut.
Environnements
Chaque environnement regroupe l'URL de l'API et celle du modal de paiement.
WPay::useProduction(); // défaut
WPay::useSandbox(); // avec une clé sandbox (sk_test_xxx)
WPay::useLocal(); // API http://localhost:8000, modal http://localhost:3000
// API et modal ailleurs, ex. depuis un téléphone sur le même Wi-Fi
WPay::useLocal('http://192.168.1.20:8000', 'http://192.168.1.20:3000');
WPay::environment()->name; // 'production' | 'sandbox' | 'local' | 'custom' (setBaseUrl)
WPay::environment()->apiUrl;
WPay::environment()->checkoutUrl;
HTTPS est obligatoire, sauf en local : HTTP est accepté uniquement pour localhost,
*.test, *.localhost, 127.0.0.0/8 et les réseaux privés 10.0.0.0/8, 172.16.0.0/12,
192.168.0.0/16. Toute autre adresse (publique, CGNAT, métadonnées cloud...) exige HTTPS :
la secret key ne circule jamais en clair hors de votre réseau.
WPay::setBaseUrl()etWPay::getBaseUrl()restent disponibles mais sont dépréciés : utilisezWPay::useLocal()etWPay::environment()->apiUrl.
Variables d'environnement recommandées
# Obligatoires
WPay_SECRET_KEY=sk_live_xxxxxxxxxxxx
WPay_WEBHOOK_SECRET=whsec_xxxxxxxxxxxx
# Liens de paiement
WPay_PUBLIC_KEY=pk_live_xxxxxxxxxxxx
# Optionnel : production (défaut) | sandbox | local
WPay_ENV=production
match ($_ENV['WPay_ENV'] ?? 'production') {
'sandbox' => WPay::useSandbox(),
'local' => WPay::useLocal(),
default => WPay::useProduction(),
};
🔒 Stockez toujours la
secret keydans un.env(jamais en dur dans le code, jamais dans git).
Transactions
// Récupérer une transaction
$tx = WPay::transaction()->retrieve('01kmryyv98aw0mja47zp6h55tk');
$tx->status; // 'init' | 'pending' | 'success' | 'failed' | 'free'
$tx->amount; // montant marchand (float), hors frais
$tx->totalAmount; // montant débité au client, frais inclus
$tx->payment->method; // 'mtn-bj', 'moov-bj', 'celtiis', ...
$tx->payment->phone;
$tx->metadata; // custom_metadata transmis au SDK JS
$tx->invoice->pdf;
// ✅ Vérification complète d'un paiement (statut + montant)
$valid = WPay::transaction()->verifyPayment($txId, expectedAmount: 5000);
// Vérifications séparées
$ok = WPay::transaction()->isSuccessful($txId);
$amountOk = WPay::transaction()->verifyAmount($txId, 5000.00);
// Liste paginée
$list = WPay::transaction()->list([
'status' => 'success',
'from' => '2026-01-01',
'per_page' => 20,
]);
Rattacher un paiement à votre commande
Passez votre référence dans custom_metadata côté SDK JS, puis vérifiez côté serveur
le statut, le montant et la référence avant de valider la commande :
WPay.init({
public_key: "pk_live_xxx",
transaction: { amount: 5000, description: "Commande #42", custom_metadata: { order_id: "42" } },
onComplete: (result) => fetch(`/orders/42/payment-confirmation`, {
method: "POST",
body: JSON.stringify({ transactionId: result.transaction_id }),
}),
});
$tx = WPay::transaction()->retrieve($transactionId);
if ($tx->isValidPayment($order->amount) && $tx->belongsTo((string) $order->id)) {
// ✅ Paiement confirmé pour cette commande
}
Ne validez jamais une commande sur la seule base du callback
onComplete: vérifiez la transaction côté serveur ou attendez le webhook.
Liens de paiement
Créez la commande côté serveur et envoyez au client un lien qui ouvre le modal de paiement en pleine page (comme le QR code des ventes) : SMS, WhatsApp, e-mail, facture...
WPay::setSecretKey($_ENV['WPay_SECRET_KEY']);
WPay::setPublicKey($_ENV['WPay_PUBLIC_KEY']); // pk_live_xxx, requise pour les liens de paiement
$link = WPay::paymentLink()->create([
'amount' => 5000,
'description' => 'Commande #42',
'metadata' => ['order_id' => '42'], // conservé sur la commande WPay
'customer' => ['firstname' => 'Jean', 'phone' => '0197000000'], // optionnel, pré-remplit le modal
]);
$link->url; // https://app.webcoompay.com/modal?order=... (selon l'environnement)
$link->orderId; // à conserver pour renvoyer le lien
$link->transactionId; // à rapprocher du webhook
| Paramètre | Requis | Description |
|---|---|---|
amount | oui | Montant en FCFA (sauf si articles) | |
description | oui | Libellé affiché au client |
quantity | non | Quantité (défaut : 1) |
metadata | non | Données libres, retournées dans le webhook |
articles | non | Articles de votre catalogue : [['id' => '...', 'qty' => 1]] |
customer | non | firstname, lastname, email, phone |
Renvoyer le lien d'une commande existante, sans en créer une nouvelle :
$url = WPay::paymentLink()->url($orderId);
Le paiement se confirme comme pour le SDK JS : webhook ou WPay::transaction()->retrieve().
Le moyen de paiement et les pays proposés sont ceux activés sur votre offre.
Webhooks - vérification de signature
use WPay\Exceptions\WebhookSignatureException;
use WPay\Resources\Webhook;
try {
$event = Webhook::construct(
file_get_contents('php://input'),
$_SERVER['HTTP_X_WPAY_SIGNATURE'] ?? null,
$_ENV['WPay_WEBHOOK_SECRET'],
);
} catch (WebhookSignatureException $e) {
http_response_code(400);
exit;
}
if ($event->isSuccess() && $event->transaction?->isValidPayment($expectedAmount)) {
$orderId = $event->metadata['order_id'] ?? null; // custom_metadata du SDK JS
// ✅ Marquer la commande comme payée (de façon idempotente : le webhook peut être renvoyé)
}
http_response_code(200);
Avec Laravel, lisez le corps brut via $request->getContent() et l'en-tête via
$request->header('X-WPay-Signature'), et excluez la route du contrôle CSRF.
Champs utiles de WebhookEvent : ref, status, amount, paymentMethod, paymentPhone,
metadata, customer, order, transaction (TransactionObject), transactionId(), invoiceUrl().
Le SDK supporte deux formats de signature dans l'en-tête X-WPay-Signature :
| Format | Header | Anti-replay |
|---|---|---|
| Horodaté (recommandé) | t=1715610000,v1=<hex_hmac> | ✅ rejette les requêtes > 5 min |
| Legacy | <hex_hmac> | ❌ |
Exceptions
| Exception | Code | Cause |
|---|---|---|
AuthenticationException | 401/403 | Secret key invalide ou révoquée |
NotFoundException | 404 | Ressource introuvable |
WebhookSignatureException | 400 | Signature HMAC invalide, manquante ou expirée |
WPay | variable | Autre erreur (5xx, réseau, etc.) |
Toutes héritent de WPay qui hérite elle-même de RuntimeException - un seul catch (WPay $e) capture tout.
Sécurité
- ✅ HMAC SHA-256 avec
hash_equals(timing-safe) - ✅ Anti-replay via timestamp signé (tolérance 5 min)
- ✅ Vérification SSL forcée
- ✅ Retry exponentiel sur erreurs réseau transitoires
Pour signaler une vulnérabilité : security@webcoompay.com
Licence
MIT - voir LICENSE.
Versionnage & mises à jour
Ce SDK suit le Semantic Versioning (MAJOR.MINOR.PATCH) :
- MAJOR - changement non rétrocompatible (signature modifiée, comportement changé)
- MINOR - nouvelle fonctionnalité, rétrocompatible
- PATCH - correction de bug, aucun changement d'API
Mettre à jour le SDK dans votre projet
# Récupère la dernière version compatible avec votre contrainte actuelle
composer update wpay-bj/php-sdk
# Passer à une nouvelle version majeure (changement volontaire)
composer require wpay-bj/php-sdk:^2.0
Nous recommandons de fixer votre contrainte sur le MAJOR uniquement (^1.0) dans votre
composer.json, pour recevoir automatiquement les correctifs et nouvelles fonctionnalités
sans risque de casse :
"require": {
"wpay-bj/php-sdk": "^1.0"
}
Voir les changements
Consultez CHANGELOG.md avant toute mise à jour majeure - les changements non rétrocompatibles y sont documentés avec un guide de migration.