welloo / payment-sdk
SDK PHP pour créer un paiement via redirection (checkout hébergé), initier un transfert, lister les transactions et consulter le solde avec le prestataire Welloo. Utilisable en PHP natif, Laravel, Symfony... ; ne jamais exposer côté navigateur.
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
This package is not auto-updated.
Last update: 2026-08-15 09:14:48 UTC
README
SDK PHP pour :
- accepter un paiement (page de sélection ou lien direct pour un opérateur) et obtenir une URL de paiement hébergée vers laquelle rediriger le client,
- transfert Mobile Money via Welloo
- liste des transactions
- consultation du solde
- vérifier la signature d'un webhook de confirmation.
Portage PHP/Composer du SDK Node.js welloo-payment-sdk —
mêmes endpoints, même comportement.
⚠️ Sécurité — à lire avant tout
Ce SDK manipule apiKey et serviceToken, des credentials secrets.
Il ne doit jamais être exécuté dans du code accessible côté client
(JS embarqué dans une page publique, etc.). Utilise-le uniquement côté
serveur : script PHP, Laravel, Symfony, etc. Ne mets jamais ces valeurs en
dur dans ton code ou ta documentation — passe-les toujours par des variables
d'environnement.
Le frontend doit appeler ton propre backend, qui utilise ce SDK pour parler au prestataire de paiement.
[Frontend] --(HTTP, sans secret)--> [Ton backend PHP/Laravel/Symfony] --(SDK, avec secrets)--> [Welloo]
Procédure d'installation
1. Prérequis
- PHP >= 8.1
- extensions
curletjson
2. Installer le package
composer require welloo/payment-sdk
En local, sans registre Composer privé, tu peux aussi le référencer via un
repository de type path dans ton composer.json :
{
"repositories": [
{ "type": "path", "url": "../payment-sdk-php" }
],
"require": {
"welloo/payment-sdk": "*"
}
}
3. Configurer les identifiants
Récupère apiKey et serviceToken auprès de Welloo, puis expose-les en
variables d'environnement (ex: fichier .env, jamais commité) :
API_KEY=...
SERVICE_TOKEN=...
WEBHOOK_SECRET=...
4. Instancier le SDK
<?php
use Welloo\PaymentSdk\PaymentSDK;
use Welloo\PaymentSdk\PaymentSDKConfig;
// Le SDK est instancié UNE FOIS, côté serveur, avec les secrets pris depuis .env
$sdk = new PaymentSDK(new PaymentSDKConfig(
apiKey: $_ENV['API_KEY'] ?? '',
serviceToken: $_ENV['SERVICE_TOKEN'] ?? '',
webhookSecret: $_ENV['WEBHOOK_SECRET'] ?? null,
));
PaymentSDK lève une PaymentSDKException si apiKey ou serviceToken est
manquant — instancie-le une seule fois au démarrage de l'application (ex:
service singleton Laravel/Symfony), pas à chaque requête.
Utilisation du SDK avec initPayment
initPayment crée une session de paiement auprès de Welloo et retourne
checkoutUrl : l'URL vers laquelle rediriger le navigateur du client.
Son comportement dépend du champ optionnel operator :
operatorabsent : retourne la page de paiement hébergée par Welloo, où le client choisit lui-même son opérateur Mobile Money et son numéro.operatorfourni ("welloo"ou"wave") : génère directement un lien de paiement pour cet opérateur (endpointPOST /api/v1/payment-link-sdk), sans passer par l'écran de sélection.
// Sans ?operator= -> page de sélection hébergée par Welloo
if ($path === '/api/v1/init-payment') {
try {
$payment = $sdk->initPayment(new InitPaymentPayload(
amount: 5, // montant en unité mineure du prestataire
returnUrl: 'https://monsite.com/panier', // lien de retour
operator: $_GET['operator'] ?? null, // optionnel : "welloo" | "wave"
metadata: [],
));
header('Location: ' . $payment->checkoutUrl, true, 302);
} catch (PaymentSDKException $e) {
error_log('Impossible de lancer le paiement : ' . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Impossible de lancer le paiement']);
}
exit;
}
Exemple complet :
examples/php-backend/public/index.php.
Champs de InitPaymentPayload
| Champ | Requis | Description |
|---|---|---|
amount | oui | Montant en unité mineure (ex: centimes) selon le prestataire |
returnUrl | oui | Cible du bouton "Retour" sur la page de paiement |
operator | non | "welloo" ou "wave" — génère un lien direct pour cet opérateur au lieu de la page de sélection |
description | non | Description du paiement (usage actuellement informatif côté Welloo) |
metadata | non | Tableau associatif transmis au prestataire. Toutes les valeurs doivent être des chaînes : un entier est rejeté par un 400 { "field": "metadata_<clé>", "message": "Doit etre une chaine de caracteres." }. Ignoré si operator est fourni. |
initPayment retourne un InitPaymentResult :
| Champ | Description |
|---|---|
checkoutUrl | URL vers laquelle rediriger (page de sélection ou lien direct selon operator) |
status | Statut initial de la session (ex: "active", "pending") |
Utilisation du SDK avec initTransfer
initTransfer initie un transfert et retourne l'URL de paiement hébergée
vers laquelle rediriger le client (endpoint POST /api/v1/init).
if ($path === '/api/v1/init-transfer') {
try {
$transfer = $sdk->initTransfer(new InitTransferPayload(
returnUrl: 'https://merchant.example.com/success',
));
header('Location: ' . $transfer->checkoutUrl, true, 302);
} catch (PaymentSDKException $e) {
error_log("Impossible d'initier le transfert : " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => "Impossible d'initier le transfert"]);
}
exit;
}
Champs de InitTransferPayload
| Champ | Description |
|---|---|
returnUrl | URL de retour après paiement |
initTransfer retourne un InitTransferResult avec un seul champ :
checkoutUrl (URL vers laquelle rediriger).
initPaymentrejette unamountinférieur à 5 (PaymentSDKException), avant même d'appeler l'API.
Utilisation du SDK avec getTransactions et getPaymentStatus
getTransactions liste les transactions du service authentifié (endpoint
GET /api/v1/payments). getPaymentStatus($reference) vérifie le statut
réel d'une transaction précise (endpoint GET /api/v1/payments/{reference}) —
la reference est le session_reference renvoyé dans chaque transaction.
// Sans ?reference= -> liste complète. Avec ?reference= -> statut d'une transaction.
if ($path === '/api/v1/transactions') {
try {
$reference = $_GET['reference'] ?? null;
if ($reference) {
$status = $sdk->getPaymentStatus($reference);
echo json_encode([
'reference' => $status->reference,
'status' => $status->status,
'raw' => $status->raw,
]);
exit;
}
echo json_encode($sdk->getTransactions());
} catch (PaymentSDKException $e) {
error_log('Impossible de récupérer les transactions : ' . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Impossible de récupérer les transactions']);
}
exit;
}
getTransactions retourne la liste des transactions brutes renvoyées par
Welloo (montant, devise, statut, opérateur, dates, etc.). getPaymentStatus
retourne un GetPaymentStatusResult :
| Champ | Description |
|---|---|
reference | La référence passée en paramètre |
status | Statut réel de la transaction (ex: "active", "completed", "expire") |
raw | Réponse brute complète du prestataire |
Ne te fie jamais uniquement à une URL de retour (returnUrl) pour
valider un paiement : revérifie toujours via getPaymentStatus() ou un
webhook signé.
Utilisation du SDK avec getSolde
getSolde récupère le solde du compte Welloo (endpoint GET /api/v1/solde).
if ($path === '/api/v1/solde') {
try {
$result = $sdk->getSolde();
echo json_encode(['currency' => $result->currency, 'solde' => $result->solde]);
} catch (PaymentSDKException $e) {
error_log('Impossible de récupérer le solde : ' . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Impossible de récupérer le solde']);
}
exit;
}
getSolde retourne un GetSoldeResult :
| Champ | Description |
|---|---|
currency | Devise du solde (ex: "XOF") |
solde | Montant disponible sur le compte |
raw | Réponse brute complète du prestataire |
Gérer les erreurs
Toutes les méthodes qui appellent l'API lèvent une PaymentSDKException en
cas d'échec, avec deux propriétés utiles pour distinguer une erreur
actionnable par l'appelant (ex: opérateur invalide) d'une vraie panne :
| Propriété | Description |
|---|---|
statusCode | Code HTTP renvoyé par Welloo (ex: 400, 401) — null pour une erreur réseau |
details | Corps JSON brut de la réponse d'erreur Welloo (['message' => ..., 'errors' => [...]]) |
Un pattern courant : exposer le vrai message pour les erreurs 4xx (actionnables), et rester générique pour les 5xx (pour ne pas fuiter de détail interne que l'appelant ne peut de toute façon pas corriger) :
function sendSdkError(PaymentSDKException $e, string $fallbackMessage): void
{
error_log((string) $e); // détail complet toujours loggé côté serveur
header('Content-Type: application/json');
if ($e->statusCode !== null && $e->statusCode < 500) {
http_response_code($e->statusCode);
$details = is_array($e->details) ? ($e->details['errors'] ?? null) : null;
$message = (is_array($e->details) ? ($e->details['message'] ?? null) : null) ?? $e->getMessage();
echo json_encode(['error' => $message, 'details' => $details]);
return;
}
http_response_code(500);
echo json_encode(['error' => $fallbackMessage]);
}
Vérifier un webhook
php://inputrenvoie toujours le corps brut exact de la requête, nécessaire au calcul HMAC — contrairement à$_POST, qui est déjà parsé. Sous Laravel/Symfony, utilise$request->getContent().
if ($path === '/api/v1/webhook') {
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$rawBody = file_get_contents('php://input'); // corps brut, nécessaire au calcul HMAC
if ($signature === '' || !$sdk->verifyWebhookSignature($rawBody, $signature)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
$event = json_decode($rawBody, true) ?: [];
// $event['status'] === 'paid' -> mettre à jour la commande en base
http_response_code(200);
exit;
}
API complète
| Méthode | Description |
|---|---|
initPayment(InitPaymentPayload $payload): InitPaymentResult | Crée une session de paiement et retourne checkoutUrl (page de sélection, ou lien direct si operator est fourni). |
initTransfer(InitTransferPayload $payload): InitTransferResult | Initie un transfert et retourne checkoutUrl. |
getTransactions(): array | Liste les transactions du service authentifié. |
getPaymentStatus(string $reference): GetPaymentStatusResult | Vérifie le statut réel d'une transaction précise. |
getSolde(): GetSoldeResult | Récupère le solde du compte Welloo. |
verifyWebhookSignature(string $rawBody, string $signature): bool | Vérifie la signature HMAC-SHA256 d'un webhook. |
Différences avec la version Node.js
- Les appels HTTP utilisent
curlnatif (pas de dépendance externe type Guzzle), avec un timeout de 30 s. - Les payloads/résultats sont des objets
readonlytypés (PHP 8.1+) plutôt que des interfaces TypeScript, mais avec la même forme de données. - Les erreurs sont des
PaymentSDKException(héritant deRuntimeException) au lieu dePaymentSDKError.