Search by

pismile / pismile-php

raoufilokou

SDK serveur pismile pour PHP : bouton « Payer avec Alias PI-SPI », demandes de paiement et webhooks.

Package info

github.com/getpismile/pismile-php

pkg:composer/pismile/pismile-php

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0 2026-10-25 14:17 UTC

This package is not auto-updated.

Last update: 2026-11-09 13:29:24 UTC


README

Packagist Tests

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_secret ne 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)

  1. Modules : Encaissement activé, accès participant PI-SPI vérifié (AFA-Pay, MTN…).
  2. Domaines : votre domaine vérifié (l'adresse de retour du payeur doit y être).
  3. Applications → votre application → Paiements : adresse du webhook, puis copiez le secret whsec_….
  4. 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