pismile / pismile-php
SDK serveur pismile pour PHP : bouton « Payer avec Alias PI-SPI », demandes de paiement et webhooks.
Requires
- php: >=8.1
- ext-hash: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^10.5
Suggests
- ext-curl: Transport HTTP recommandé (sinon : flux PHP avec allow_url_fopen)
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-11-09 13:29:24 UTC
README
SDK serveur pismile pour PHP 8.1+ : encaissez avec le bouton « Payer avec Alias PI-SPI », envoyez des demandes de paiement à vos utilisateurs « Se connecter avec pismile », et vérifiez les webhooks.
- Aucune dépendance : PHP simple, Laravel, Symfony, WordPress…
- L'argent arrive directement sur le compte de votre organisation, avec votre accès participant PI-SPI.
- Le payeur valide chaque demande dans sa banque. Il peut payer seul ou partager sur plusieurs comptes.
À utiliser uniquement côté serveur : le
client_secretne doit jamais aller dans une page web ni une appli mobile.
Installation
composer require pismile/pismile-php
Sans Composer : copiez le dossier src/ et chargez les fichiers (require 'pismile/src/Pismile.php';, etc.).
Prérequis (console pismile, une fois)
- Modules : Encaissement activé, accès participant PI-SPI vérifié (AFA-Pay, MTN…).
- Domaines : votre domaine vérifié (l'adresse de retour du payeur doit y être).
- Applications → votre application → Paiements : adresse du webhook, puis copiez le secret
whsec_…. - Pour une application de production : organisation vérifiée.
# .env
PISMILE_CLIENT_ID=votre_client_id
PISMILE_CLIENT_SECRET=votre_client_secret
PISMILE_WEBHOOK_SECRET=whsec_...
Le bouton « Payer avec Alias PI-SPI »
Le client clique, paie sur pismile.com (sans compte), puis revient sur votre site. Trois morceaux :
1. Le bouton (page commande ou produit)
<script src="https://pismile.com/kit/v1/pismile-button.js" defer></script> <pismile-button text="pay" href="/payer.php?commande=42"></pismile-button>
2. payer.php : créer la page de paiement et y envoyer le client
<?php require 'vendor/autoload.php'; use Pismile\Pismile; $pismile = Pismile::depuisEnvironnement(); $commande = trouverCommande((int) $_GET['commande']); // votre code (vérifiez qu'elle appartient au client) $page = $pismile->sessions()->creer( $commande['total'], // montant en F CFA 'cmd-' . $commande['id'], // votre référence : la renvoyer renvoie la même page 'https://votre-site.com/merci.php?commande=' . $commande['id'], // domaine vérifié 'Commande ' . $commande['id'], // motif affiché au payeur ); header('Location: ' . $page->url, true, 303); // https://pismile.com/payer/cs_…
Au retour, l'adresse reçoit ?pismile_session=cs_…&statut=payee. Ce n'est pas une preuve (n'importe qui peut
ouvrir cette adresse) : confirmez avec le webhook, ou relisez $pismile->sessions()->lire($_GET['pismile_session']).
3. webhook.php : la preuve de paiement
<?php require 'vendor/autoload.php'; use Pismile\Pismile; use Pismile\PismileException; $pismile = Pismile::depuisEnvironnement(); try { $evenement = $pismile->webhooks()->verifier( file_get_contents('php://input'), // corps BRUT $_SERVER['HTTP_PISMILE_SIGNATURE'] ?? null, ); } catch (PismileException $e) { http_response_code(400); exit; } if ($evenement->estSessionPayee()) { marquerPayee($evenement->reference()); // « cmd-42 » ; sans effet si déjà payée } http_response_code(200);
pismile réessaie un webhook non acquitté (2xx en moins de 10 s) : 1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h.
Un même événement peut arriver deux fois : dédoublonnez avec $evenement->id.
| Événement | Quand |
|---|---|
session.payee |
La page est entièrement payée : livrez |
session.expiree |
30 min sans paiement complet ; $evenement->session()->montantPaye indique un éventuel paiement partiel |
paiement.paye · paiement.refuse · paiement.annule · paiement.expire |
Demandes aux utilisateurs connectés (ci-dessous) |
test |
Bouton « Envoyer un test » de la console |
Laravel
// AppServiceProvider::register() $this->app->singleton(\Pismile\Pismile::class, fn () => \Pismile\Pismile::depuisEnvironnement()); // routes/web.php Route::get('/commandes/{commande}/payer', function (Commande $commande, \Pismile\Pismile $pismile) { $page = $pismile->sessions()->creer($commande->total, 'cmd-' . $commande->id, route('commandes.merci', $commande), 'Commande ' . $commande->id); return redirect()->away($page->url); }); Route::post('/webhooks/pismile', function (Request $request, \Pismile\Pismile $pismile) { try { $e = $pismile->webhooks()->verifier($request->getContent(), $request->header('Pismile-Signature')); } catch (\Pismile\PismileException) { return response('', 400); } if ($e->estSessionPayee()) { Commande::marquerPayee($e->reference()); } return response('', 200); })->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
WordPress
// webhook : https://votre-site.com/wp-json/pismile/v1/webhook add_action('rest_api_init', function () { register_rest_route('pismile/v1', '/webhook', [ 'methods' => 'POST', 'permission_callback' => '__return_true', // la signature fait office d'authentification 'callback' => function (WP_REST_Request $r) { $pismile = new \Pismile\Pismile(PISMILE_CLIENT_ID, PISMILE_CLIENT_SECRET, ['webhookSecret' => PISMILE_WEBHOOK_SECRET]); try { $e = $pismile->webhooks()->verifier($r->get_body(), $r->get_header('pismile_signature')); } catch (\Pismile\PismileException) { return new WP_REST_Response(null, 400); } if ($e->estSessionPayee()) { do_action('pismile_paiement_recu', $e->reference(), $e); } return new WP_REST_Response(null, 200); }, ]); });
Demander un paiement à un utilisateur connecté
Si vos utilisateurs se connectent avec « Se connecter avec pismile » et le scope pismile:payment, vous pouvez leur
envoyer une demande sans les rediriger (abonnement, facture…). Le sub est celui reçu à la connexion.
$p = $pismile->paiements()->creer($sub, 5000, 'facture-2026-10', 'Abonnement octobre'); $p->statut; // EN_ATTENTE → PAYE, REFUSE, ANNULE ou EXPIRE (webhooks paiement.*)
Erreurs
Toutes les erreurs sont des Pismile\PismileException : codeErreur() (stable), statut() (HTTP), getMessage().
| Code | Que faire |
|---|---|
authentification |
client_id ou client_secret incorrect |
retour_domaine_non_verifie |
ajoutez et vérifiez votre domaine (console → Domaines) |
reference_deja_utilisee |
référence déjà prise par un autre montant |
module_encaissement_requis · acces_participant_non_verifie · organisation_non_verifiee |
voir la console |
autorisation_absente |
(demandes) reconnecter l'utilisateur avec pismile:payment |
reseau · delai_depasse |
pismile injoignable : réessayez avec la même référence |
Le SDK réessaie déjà de lui-même après une coupure réseau ou une erreur serveur temporaire : sans risque, la référence empêche tout double paiement.
Options
$pismile = new Pismile($clientId, $clientSecret, [ 'webhookSecret' => 'whsec_...', 'issuer' => 'https://pismile.com', 'delai' => 15, // secondes par appel 'essais' => 2, // nouveaux essais (coupure réseau, erreur serveur temporaire) ]);
curl est utilisé s'il est disponible, sinon les flux PHP (allow_url_fopen).
Tests
composer install
composer test
Documentation
Guides complets (liens de paiement, bouton, webhooks, référence de l'API) : pismile.com/docs/paiements.
Licence
MIT