Download the PHP package sunucode/afripay without Composer
On this page you can find all versions of the php package sunucode/afripay. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package afripay
AfriPay - Unified Payment Gateway for Africa
Accept payments from Wave, Orange Money, PayDunya, PayTech, Stripe & PayPal in your Laravel app with a single, clean API.
English
Français
Pourquoi AfriPay ?
Les développeurs en Afrique de l'Ouest intègrent manuellement chaque passerelle de paiement dans chaque projet. Wave, Orange Money, PayDunya, PayTech... chacun avec son API, ses webhooks, ses signatures.
AfriPay unifie tout ca en une seule interface :
Changer de passerelle ? Une seule ligne :
Passerelles supportées
| Passerelle | Pays | Type | Statut |
|---|---|---|---|
| Wave | SN, CI, ML, BF | Mobile Money | Production |
| Orange Money | SN, CI, ML, BF, CM, GN | Mobile Money | Beta |
| PayDunya | SN, CI, BJ, TG, BF, ML | Multi-canal | Production |
| PayTech | SN | Multi-canal | Production |
| Stripe | Global | Carte bancaire | Production |
| PayPal | Global | International | Production |
Installation
Installation rapide (recommandé)
Une seule commande génère tout le nécessaire :
La commande crée :
config/afripay.php— configuration des passerellesapp/Http/Controllers/AfriPayController.php— controller avecsuccess()eterror()resources/views/payment/{success,pending,error}.blade.php— vues de retour (HTML simple, à intégrer dans votre layout)- Les routes
/payment/success/{reference}et/payment/error/{reference}dansroutes/web.php - Les event listeners dans
AppServiceProvider::boot()
Par défaut, le controller est créé dans app/Http/Controllers/. Pour le placer ailleurs :
Installation manuelle
Puis suivez les sections Gestion du retour ci-dessous.
Configuration
Ajoutez vos clés dans .env :
Utilisation
Initier un paiement
Lier à un modèle (polymorphic)
Passez payable_type et payable_id pour lier la transaction à n'importe quel modèle de votre application. C'est ce lien qui permet de router la logique métier dans vos listeners (voir section suivante).
Écouter les événements (le plus important)
Important : Laravel auto-découvre uniquement les listeners pour les events dans
App\Events\*. Les events d'un package vendor comme AfriPay (SunuCode\AfriPay\Events\*) ne sont jamais auto-découverts. Vous devez les enregistrer manuellement.
Si vous avez utilisé php artisan afripay:install, les listeners sont déjà enregistrés avec des // TODO à compléter. Sinon, ajoutez-les dans AppServiceProvider::boot().
Cas simple — une seule logique de paiement :
Cas courant — plusieurs logiques (abonnement, commande, recharge...) :
Le payable_type que vous passez au charge() permet de router automatiquement vers la bonne logique. Utilisez match() sur le type polymorphique :
Avec des classes Listener dédiées (recommandé pour les gros projets) :
Gestion du retour (success URL)
Quand l'utilisateur est redirigé vers votre success_url après le paiement, le webhook n'est pas forcément encore arrivé. Vous devez appeler verifyAndProcess() dans votre controller de retour pour confirmer le paiement :
Si vous avez utilisé php artisan afripay:install, le controller est déjà généré avec cette logique. Sinon, voici le code à ajouter dans votre controller de retour :
Sans cet appel, si le webhook arrive en retard (ou jamais en dev local), l'utilisateur verra une page de succès mais votre logique métier ne sera jamais exécutée.
Rembourser
Lister les passerelles actives
Mode webhook-only vs fallback (trust_webhook_only)
Quand trust_webhook_only=true, verifyAndProcess() vérifie le statut auprès de la passerelle mais ne dispatche aucun événement. Seul le webhook déclenche PaymentCompleted. C'est plus sûr car ça empêche un utilisateur de forger une URL de succès.
⚠️ Exigence de sécurité : avec trust_webhook_only=true, configurez le secret webhook de chaque passerelle active (ex: WAVE_WEBHOOK_SECRET) ; sinon la confirmation de paiement par webhook ne pourra pas être validée.
Quand trust_webhook_only=false, les deux chemins (webhook ET URL de retour) peuvent déclencher les événements. Utile en dev local quand les webhooks ne peuvent pas atteindre votre machine.
Piège courant en développement : Si vous développez en local sans tunnel (ngrok, Expose...), les webhooks ne peuvent pas atteindre votre machine. Avec
AFRIPAY_TRUST_WEBHOOK_ONLY=true(défaut),verifyAndProcess()ne déclenchera aucun event et vos paiements resteront enpending.Solution : Mettez
AFRIPAY_TRUST_WEBHOOK_ONLY=falsedans votre.envlocal. N'oubliez pas de remettretrueen production.
Ajouter une passerelle personnalisée
Webhooks
Les webhooks sont automatiquement enregistrés à :
Le chemin est configurable via AFRIPAY_WEBHOOK_PATH.
Chaque webhook :
- Vérifie la signature (HMAC-SHA256 pour Wave/Stripe/PayTech, master_key pour PayDunya)
- Vérifie le montant (tolérance +/- 1 unité)
- Utilise
lockForUpdate()pour éviter les doublons - Dispatche
PaymentCompletedouPaymentFailed
Sécurité
- Idempotence : Le champ
processed_atempêche le double-traitement - Verrouillage DB :
lockForUpdate()sur chaque transaction pendant le webhook - Vérification de montant : Tolérance +/- 1 unité avant d'accepter
- Anti-replay : Timestamps vérifiés (Wave, Stripe) avec tolérance de 5 min
- Zero-decimal : XOF/XAF gérés automatiquement (pas de x100 pour Stripe)
- Orange Money : Contre-vérification API obligatoire (pas de signature webhook)
Événements disponibles
| Événement | Quand | Données |
|---|---|---|
PaymentInitiated |
Après charge() |
$transaction, $gateway |
PaymentCompleted |
Webhook confirmé | $transaction |
PaymentFailed |
Webhook échoué | $transaction |
PaymentRefunded |
Après refund() |
$transaction, $reason |
English
Why AfriPay?
West African developers manually integrate each payment gateway in every project. Wave, Orange Money, PayDunya, PayTech... each with its own API, webhooks, and signatures.
AfriPay unifies everything into a single interface:
Installation
To place the controller in a custom directory:
Or set up manually: php artisan vendor:publish --tag=afripay-config and follow the sections below.
Listening to Events
Important: Laravel only auto-discovers listeners for events in
App\Events\*. Events from a vendor package like AfriPay (SunuCode\AfriPay\Events\*) are never auto-discovered. You must register them manually.
If you used php artisan afripay:install, listeners are already registered with // TODO placeholders. Otherwise, add them in AppServiceProvider::boot().
Use the payable_type set during charge() to route to the right business logic:
Handling the Success URL
When the user is redirected to your success_url, the webhook may not have arrived yet. You must call verifyAndProcess() in your return controller:
AFRIPAY_TRUST_WEBHOOK_ONLY
Common pitfall in development: Without a tunnel (ngrok, Expose...), webhooks can't reach your local machine. With
AFRIPAY_TRUST_WEBHOOK_ONLY=true(default),verifyAndProcess()will not dispatch any events and your payments will staypending.Fix: Set
AFRIPAY_TRUST_WEBHOOK_ONLY=falsein your local.env. Remember to set it back totruein production.
Custom Gateways
Extend AfriPay with your own gateways:
Security
- Idempotent processing via atomic
processed_atflag - Database locking (
lockForUpdate) prevents race conditions - Amount verification with configurable tolerance
- Replay protection with timestamp validation (Wave, Stripe)
- Zero-decimal currencies (XOF, XAF) handled automatically
- Orange Money: Mandatory API counter-verification (no webhook signature)
Requirements
- PHP >= 8.2
- Laravel 11, 12, or 13
- A database supporting
lockForUpdate()(MySQL, PostgreSQL)
Contributing
Contributions are welcome! Please submit pull requests to the main branch.
Credits
- Built by Sunu Code — Software agency based in Dakar, Senegal
- Extracted from Semplio — Business management SaaS for African SMEs
License
MIT License. See LICENSE for details.
All versions of afripay with dependencies
illuminate/support Version ^11.0|^12.0|^13.0
illuminate/database Version ^11.0|^12.0|^13.0
illuminate/http Version ^11.0|^12.0|^13.0
illuminate/events Version ^11.0|^12.0|^13.0