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.

Maintainers

Package info

gitlab.com/Cedric_Assoumou/welloo-sdk-php

Issues

pkg:composer/welloo/payment-sdk

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

v1.0.0 2026-08-14 10:56 UTC

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 curl et json

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 :

  • operator absent : 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.
  • operator fourni ("welloo" ou "wave") : génère directement un lien de paiement pour cet opérateur (endpoint POST /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

ChampRequisDescription
amountouiMontant en unité mineure (ex: centimes) selon le prestataire
returnUrlouiCible du bouton "Retour" sur la page de paiement
operatornon"welloo" ou "wave" — génère un lien direct pour cet opérateur au lieu de la page de sélection
descriptionnonDescription du paiement (usage actuellement informatif côté Welloo)
metadatanonTableau 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 :

ChampDescription
checkoutUrlURL vers laquelle rediriger (page de sélection ou lien direct selon operator)
statusStatut 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

ChampDescription
returnUrlURL de retour après paiement

initTransfer retourne un InitTransferResult avec un seul champ : checkoutUrl (URL vers laquelle rediriger).

initPayment rejette un amount infé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 :

ChampDescription
referenceLa référence passée en paramètre
statusStatut réel de la transaction (ex: "active", "completed", "expire")
rawRé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 :

ChampDescription
currencyDevise du solde (ex: "XOF")
soldeMontant disponible sur le compte
rawRé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
statusCodeCode HTTP renvoyé par Welloo (ex: 400, 401) — null pour une erreur réseau
detailsCorps 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://input renvoie 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éthodeDescription
initPayment(InitPaymentPayload $payload): InitPaymentResultCrée une session de paiement et retourne checkoutUrl (page de sélection, ou lien direct si operator est fourni).
initTransfer(InitTransferPayload $payload): InitTransferResultInitie un transfert et retourne checkoutUrl.
getTransactions(): arrayListe les transactions du service authentifié.
getPaymentStatus(string $reference): GetPaymentStatusResultVérifie le statut réel d'une transaction précise.
getSolde(): GetSoldeResultRécupère le solde du compte Welloo.
verifyWebhookSignature(string $rawBody, string $signature): boolVérifie la signature HMAC-SHA256 d'un webhook.

Différences avec la version Node.js

  • Les appels HTTP utilisent curl natif (pas de dépendance externe type Guzzle), avec un timeout de 30 s.
  • Les payloads/résultats sont des objets readonly typé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 de RuntimeException) au lieu de PaymentSDKError.