andydefer / php-pawapay
PHP SDK for integrating Pawapay Mobile Money payments (pay-ins, pay-outs, and webhooks) across African markets
Requires
- php: ^8.2
- andydefer/php-client: ^0.6.0
- andydefer/php-services: ^1.5.5
- ramsey/uuid: ^4.9
Requires (Dev)
- guzzlehttp/guzzle: ^7.8
- larastan/larastan: ^3.8
- laravel/pint: ^1.26
- phpunit/phpunit: ^12.5
- rector/rector: *
- symfony/var-dumper: ^7.0
- vimeo/psalm: ^6.14
README
SDK PHP pour l'intégration des paiements Mobile Money Pawapay à travers les marchés africains.
📖 Introduction
Qu'est-ce que Pawapay ?
Pawapay est une plateforme de paiement qui permet d'accepter des paiements via Mobile Money (M-Pesa, MTN MoMo, Orange Money, etc.) dans plus de 15 pays africains.
Ce que fait ce SDK
Ce SDK transforme les appels HTTP bruts vers l'API Pawapay en objets PHP typés, validés et documentés.
Pourquoi l'utiliser ?
| Sans SDK | Avec SDK |
|---|---|
json_decode() manuel |
Objets PHP typés (DepositDataStruct) |
| Validation manuelle | Value Objects (PhoneNumberVO, UuidVO) |
| String magiques | Enums (Provider::MTN_MOMO_ZMB) |
| Code répétitif | Builders fluides |
🚀 Installation
composer require andydefer/php-pawapay
⚙️ Configuration
Créer le client
<?php use AndyDefer\PhpPawapay\PawapayClient; use AndyDefer\PhpPawapay\Enums\PawaPayBaseUrl; $client = new PawapayClient( apiToken: 'eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ...', // Votre token API baseUrl: PawaPayBaseUrl::SANDBOX // ou PRODUCTION );
💰 1. Initier un dépôt (Initiate Deposit)
Ce que fait cette route
Elle permet à un client de payer avec son Mobile Money. Vous envoyez le numéro de téléphone, le montant et le fournisseur, et Pawapay initie le paiement.
Endpoint
POST /v2/deposits
Étape 1 : Créer les Value Objects
<?php use AndyDefer\PhpPawapay\ValueObjects\UuidVO; use AndyDefer\PhpPawapay\ValueObjects\PhoneNumberVO; use AndyDefer\PhpPawapay\ValueObjects\AmountVO; use AndyDefer\PhpPawapay\ValueObjects\ReferenceVO; use AndyDefer\PhpPawapay\ValueObjects\MessageVO; use AndyDefer\PhpPawapay\ValueObjects\PayerVO; use AndyDefer\PhpPawapay\ValueObjects\AccountDetailsVO; use AndyDefer\PhpPawapay\ValueObjects\InitiateDepositVO; use AndyDefer\PhpPawapay\Enums\Currency; use AndyDefer\PhpPawapay\Enums\Provider; use AndyDefer\PhpPawapay\Enums\PayerType; // 1. Identifiant unique du dépôt (UUID v4) $depositId = new UuidVO('f4401bd2-1568-4140-bf2d-eb77d2b2b639'); // 2. Numéro de téléphone du client (format international sans le +) $phoneNumber = new PhoneNumberVO('260763456789'); // Zambie // 3. Montant $amount = new AmountVO(15.00); // 4. Détails du compte Mobile Money $accountDetails = new AccountDetailsVO( phoneNumber: $phoneNumber, provider: Provider::MTN_MOMO_ZMB // MTN MoMo Zambie ); // 5. Payeur $payer = new PayerVO( type: PayerType::MMO, // Mobile Money Operator accountDetails: $accountDetails ); // 6. Créer le dépôt $deposit = new InitiateDepositVO( depositId: $depositId, payer: $payer, amount: $amount, currency: Currency::ZMW, clientReferenceId: new ReferenceVO('INV-123456'), customerMessage: new MessageVO('Payment for order #123456') );
Étape 2 : Envoyer la requête
$response = $client->initiateDeposit($deposit);
Étape 3 : Traiter la réponse
if ($response->isSuccess()) { // Succès (status 200) if ($response->isAccepted()) { echo "✅ Dépôt accepté !\n"; echo "ID: " . $response->getDepositId() . "\n"; // f4401bd2-1568-... echo "Statut: " . $response->getStatus()->value; // ACCEPTED echo "Créé: " . $response->getCreated(); // 2020-10-19T11:17:01Z } elseif ($response->isDuplicateIgnored()) { echo "⚠️ Dépôt dupliqué ignoré\n"; } } else { // Échec echo "❌ Échec du dépôt\n"; echo "Statut: " . $response->getStatus()->value; // REJECTED if ($response->hasFailureReason()) { $failure = $response->getFailureReason(); echo "Code: " . $failure->failureCode; // INVALID_PHONE_NUMBER echo "Message: " . $failure->failureMessage; // The phone number '2607634'... } }
Avec le Builder (recommandé)
Le builder rend le code plus lisible et réduit les erreurs :
$deposit = InitiateDepositBuilder::create() ->withAutoGeneratedDepositId() // UUID automatique ->withPhoneNumber('260763456789') ->withProvider(Provider::MTN_MOMO_ZMB) ->withAmount(15.00) ->withCurrency(Currency::ZMW) ->withClientReferenceId('INV-123456') ->withCustomerMessage('Payment for order #123456') ->withMetadataKey('orderId', 'ORD-123456789') ->build();
🔍 2. Vérifier le statut d'un dépôt
Ce que fait cette route
Elle permet de savoir où en est un dépôt : accepté, en cours, terminé ou échoué.
Endpoint
GET /v2/deposits/{depositId}
Utilisation
<?php use AndyDefer\PhpPawapay\Builders\CheckDepositStatusBuilder; $response = CheckDepositStatusBuilder::create('your-api-token') ->withDepositId('60bd6a3d-177e-4ec2-a65c-d622ede29c99') ->execute(); if ($response->isFound()) { $data = $response->getDepositData(); echo "Statut: " . $data->status->value; // COMPLETED, PROCESSING, FAILED... if ($data->status->isCompleted()) { echo "✅ Le paiement a été confirmé !"; } elseif ($data->status->isPending()) { echo "⏳ En attente de confirmation..."; } elseif ($data->status->isFailed()) { echo "❌ Le paiement a échoué."; if ($data->failureReason !== null) { echo "Raison: " . $data->failureReason->failureMessage; } } } else { echo "❌ Dépôt non trouvé"; }
Les statuts possibles
| Statut | Signification |
|---|---|
ACCEPTED |
Dépôt accepté, en attente |
PROCESSING |
En cours de traitement |
IN_RECONCILIATION |
En réconciliation |
COMPLETED |
✅ Terminé avec succès |
FAILED |
❌ Échoué |
REJECTED |
❌ Rejeté |
🔄 3. Renvoyer un callback de dépôt
Ce que fait cette route
Si votre serveur n'a pas reçu le webhook de confirmation, vous pouvez demander à Pawapay de le renvoyer.
Endpoint
POST /v2/deposits/resend-callback/{depositId}
Utilisation
<?php use AndyDefer\PhpPawapay\Builders\ResendDepositCallbackBuilder; $response = ResendDepositCallbackBuilder::create('your-api-token') ->withDepositId('9b724dbf-32a7-4e63-96bb-59a4747e43ca') ->execute(); if ($response->isAccepted()) { echo "✅ Callback renvoyé avec succès !"; } else { echo "❌ Échec"; $failure = $response->getFailureReason(); echo "Code: " . $failure->failureCode; // NOT_FOUND ou INVALID_STATE echo "Message: " . $failure->failureMessage; }
📄 4. Créer une page de paiement
Ce que fait cette route
Elle génère une URL vers une page de paiement Pawapay que vous pouvez rediriger votre client vers.
Endpoint
POST /v2/paymentpage
Utilisation
<?php use AndyDefer\PhpPawapay\Builders\CreatePaymentPageBuilder; use AndyDefer\PhpPawapay\Enums\Currency; use AndyDefer\PhpPawapay\Enums\Country; use AndyDefer\PhpPawapay\Enums\Language; $response = CreatePaymentPageBuilder::create('your-api-token') ->withAutoGeneratedDepositId() ->withPhoneNumber('243827833329') // RDC ->withAmount(24.60) ->withCurrency(Currency::USD) ->withReturnUrl('https://example.com/success') ->withLanguage(Language::FR) ->withCountry(Country::COD) ->withCustomerMessage('Paiement commande') ->withReason('Commande #12345') ->execute(); if ($response->isSuccess()) { $redirectUrl = $response->getRedirectUrl(); // Rediriger le client vers cette URL header('Location: ' . $redirectUrl); exit; }
🧩 Les Value Objects
Les Value Objects sont des classes qui valident les données au moment de leur création.
| VO | Validation | Exemple |
|---|---|---|
UuidVO |
Format UUID v4 | new UuidVO('f4401bd2-...') |
PhoneNumberVO |
Format E.164 sans + | new PhoneNumberVO('260763456789') |
AmountVO |
Positif, numérique | new AmountVO(15.00) |
ReferenceVO |
String | new ReferenceVO('INV-123456') |
MessageVO |
String, max 22 caractères | new MessageVO('Payment') |
MetadataVO |
10 champs max, valeurs scalaires | new MetadataVO($data) |
🌍 Enums disponibles
| Enum | Valeurs | Exemple |
|---|---|---|
Provider |
Fournisseurs Mobile Money | Provider::MTN_MOMO_ZMB |
Currency |
Devises | Currency::ZMW, Currency::USD |
Country |
Pays | Country::ZMB, Country::COD |
Language |
Langues | Language::EN, Language::FR |
DepositStatus |
Statuts de dépôt | DepositStatus::COMPLETED |
PawaPayBaseUrl |
URL de base | PawaPayBaseUrl::SANDBOX |
❌ Gestion des erreurs
Exemple complet
try { $response = $client->initiateDeposit($deposit); if ($response->isSuccess()) { // Traitement du succès return; } if ($response->hasFailureReason()) { $failure = $response->getFailureReason(); // Gestion par code d'erreur switch ($failure->failureCode) { case 'INVALID_PHONE_NUMBER': // Demander à l'utilisateur de corriger son numéro break; case 'AUTHENTICATION_ERROR': // Vérifier votre token API break; case 'PROVIDER_TEMPORARILY_UNAVAILABLE': // Réessayer plus tard break; default: // Erreur inconnue break; } } } catch (Exception $e) { // Erreur réseau ou exception inattendue Log::error('Pawapay error: ' . $e->getMessage()); }
📝 Exemples concrets par pays
Zambie - MTN MoMo
$deposit = InitiateDepositBuilder::create() ->withAutoGeneratedDepositId() ->withPhoneNumber('260763456789') ->withProvider(Provider::MTN_MOMO_ZMB) ->withAmount(15.00) ->withCurrency(Currency::ZMW) ->build();
RDC - Vodacom MPesa (USD)
$deposit = InitiateDepositBuilder::create() ->withAutoGeneratedDepositId() ->withPhoneNumber('243812345678') ->withProvider(Provider::VODACOM_MPESA_COD) ->withAmount(25.50) ->withCurrency(Currency::USD) ->build();
Kenya - M-Pesa
$deposit = InitiateDepositBuilder::create() ->withAutoGeneratedDepositId() ->withPhoneNumber('254712345678') ->withProvider(Provider::MPESA_KEN) ->withAmount(100.00) ->withCurrency(Currency::KES) ->build();
Nigeria - MTN MoMo
$deposit = InitiateDepositBuilder::create() ->withAutoGeneratedDepositId() ->withPhoneNumber('2348034567890') ->withProvider(Provider::MTN_MOMO_NGA) ->withAmount(5000.00) ->withCurrency(Currency::NGN) ->build();
📄 Licence
MIT © Andy Defer