pismile

Référence technique des connecteurs

L'API v1 des connecteurs, les événements, la signature des webhooks et les codes d'erreur, pour les développeurs et intégrateurs.

6 min de lecture · Mis à jour le · API v1

Connectez-vous pour voir vos propres identifiants sandbox dans les exemples.

Cette page s'adresse aux développeurs et intégrateurs. Si vous utilisez le module Odoo, vous n'en avez pas besoin : le module fait tout cela pour vous. Elle sert à comprendre ce que fait le module, à diagnostiquer un problème, ou à brancher un logiciel qui n'a pas encore de connecteur.

Adresse et authentification#

Texte
https://pismile.com/api/connect/v1

Chaque requête porte la clé de l'installation dans l'en-tête Authorization :

HTTP
Authorization: Bearer pmc_test_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Préfixe

Mode

Effet

pmc_test_

test

Aucune demande réelle. Résultat simulé en une dizaine de secondes. Jamais facturé.

pmc_live_

production

Vraies demandes PI-SPI, avec l'accès participant de l'organisation. Organisation vérifiée requise.

Toutes les réponses sont en JSON, en UTF-8. Les montants sont des entiers en F CFA. Les dates sont au format ISO 8601 en UTC.

Vérifier la clé — GET /moi#

Renvoie ce que la clé permet. C'est ce qu'appelle le bouton Tester la connexion d'Odoo.

curl https://pismile.com/api/connect/v1/moi \
  -H "Authorization: Bearer $PISMILE_CLE"

encaissementsInclus est absent si l'offre est illimitée.

Créer une demande — POST /demandes#

Champ

Obligatoire

Description

reference

oui

Numéro de facture. 1 à 64 caractères : lettres, chiffres et . _ : / -. Unique par connecteur et par mode (test ou production).

montant

oui

Entier en F CFA, de 1 à 5 000 000.

payeurAlias

oui

Alias PI-SPI du client : téléphone (+22890123456), SHID…

payeurNom

non

Nom du client dans votre logiciel (affichage dans la console).

motif

non

Texte affiché dans la banque du client, après le nom de l'organisation. Par défaut « Facture <reference> ».

echeance

non

Date limite : 2026-10-31 ou 2026-10-31T18:00:00Z. Au moins 5 minutes, au plus 7 jours. Par défaut 72 heures.

metadonnees

non

Jusqu'à 20 paires clé/valeur libres, renvoyées telles quelles dans les événements.

curl -X POST https://pismile.com/api/connect/v1/demandes \
  -H "Authorization: Bearer $PISMILE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "FAC/2026/00001",
    "montant": 35000,
    "payeurAlias": "+22890123456",
    "payeurNom": "Kofi Mensah",
    "metadonnees": { "odoo_move_id": "42" }
  }'

Lire une demande#

Terminal
# Par identifiant pismile
curl https://pismile.com/api/connect/v1/demandes/3f6c2a1e-9b7d-4c58-a0e2-7d41b9c86f15 -H "Authorization: Bearer $PISMILE_CLE"

# Par votre référence
curl "https://pismile.com/api/connect/v1/demandes?reference=FAC/2026/00001" -H "Authorization: Bearer $PISMILE_CLE"

Statuts#

statut

Signification

Final

EN_ATTENTE

Envoyée, en attente de la réponse du client.

non

PAYE

Payée. payeLe et referencePispi sont renseignés.

oui

REFUSE

Refusée par le client ou sa banque. raison explique.

oui

ANNULE

Annulée avant paiement.

oui

EXPIRE

Date limite dépassée sans réponse.

oui

ECHEC

Refusée par le participant avant l'envoi au client.

oui

referencePispi est l'identifiant de bout en bout PI-SPI : c'est lui qui figure sur le relevé bancaire, utilisez-le pour le rapprochement.

Les événements#

Un événement est émis quand une demande atteint un statut final, et quand vous cliquez sur Envoyer un test dans la console.

type

Quand

demande.payee

Le client a payé.

demande.refusee

Le client ou sa banque a refusé.

demande.annulee

La demande a été annulée.

demande.expiree

La date limite est passée.

test

Bouton « Envoyer un test » de la console.

JSON
{
  "id": "evt_5m2q8k1x9p3a",
  "type": "demande.payee",
  "creeLe": "2026-10-16T09:12:41Z",
  "test": true,
  "donnees": {
    "id": "3f6c2a1e-9b7d-4c58-a0e2-7d41b9c86f15",
    "reference": "FAC/2026/00001",
    "montant": 35000,
    "devise": "XOF",
    "statut": "PAYE",
    "payeLe": "2026-10-16T09:12:40Z",
    "referencePispi": "E2E20261016091240XXXX",
    "metadonnees": { "odoo_move_id": "42" },
    "test": true
  }
}

Le champ donnees a le même format que la réponse de GET /demandes/{id}.

Recevoir par webhook#

Configurez l'adresse dans la console : installation → Événements. pismile envoie un POST JSON avec ces en-têtes :

En-tête

Contenu

Pismile-Evenement

Le type, par exemple demande.payee.

Pismile-Livraison

L'identifiant de l'événement.

Pismile-Signature

t=<horodatage>,v1=<signature>

Répondez par un code 2xx en moins de 10 secondes. Sinon pismile réessaie après 1 min, 5 min, 30 min, 2 h, 6 h, 12 h et 24 h. L'adresse doit être en https et joignable depuis Internet.

Vérifier la signature#

v1 vaut HMAC-SHA256(secret, t + "." + corps) en hexadécimal, où secret est le whsec_… de l'installation et corps le corps brut de la requête, avant tout décodage JSON. Refusez un horodatage de plus de 5 minutes.

import hashlib, hmac, time

def signature_valide(secret: str, entete: str, corps_brut: bytes) -> bool:
    parties = dict(p.split("=", 1) for p in (entete or "").split(",") if "=" in p)
    try:
        t = int(parties["t"])
    except (KeyError, ValueError):
        return False
    if abs(time.time() - t) > 300:
        return False
    attendu = hmac.new(secret.encode(), f"{t}.".encode() + corps_brut, hashlib.sha256).hexdigest()
    return hmac.compare_digest(attendu, parties.get("v1", ""))

Relire par curseur — GET /evenements#

Utile si votre logiciel n'est pas joignable depuis Internet, et comme filet de sécurité derrière le webhook (le module Odoo le fait toutes les 5 minutes).

Paramètre

Description

apres

Le curseur suivant reçu au dernier appel. 0 ou absent au premier appel.

limite

Nombre d'événements par page : 50 par défaut, 200 au plus.

curl "https://pismile.com/api/connect/v1/evenements?apres=0&limite=50" \
  -H "Authorization: Bearer $PISMILE_CLE"

Enregistrez suivant après avoir traité les événements, et renvoyez-le au prochain appel. Si plus vaut true, rappelez tout de suite. La lecture par curseur demande la fonctionnalité « Facture payée » dans l'offre.

Erreurs#

Toutes les erreurs ont la même forme :

JSON
{ "erreur": "trop_de_demandes_en_attente", "message": "Ce client a déjà 3 demandes en attente de validation." }

Le champ erreur est un code stable, à utiliser dans votre code. Le message est en français, destiné à être affiché à l'utilisateur.

HTTP

erreur

Que faire

400

corps_invalide, reference_invalide, reference_manquante, montant_invalide, alias_invalide, motif_invalide, echeance_invalide, metadonnees_invalides, curseur_invalide, payeur_beneficiaire

Corrigez la requête, le message indique le champ.

401

authentification

Clé absente, invalide, révoquée ou remplacée.

403

abonnement_absent

Pas d'abonnement en cours pour ce connecteur : Plan et usage.

403

fonctionnalite_non_incluse

Fonction absente de l'offre.

403

module_encaissement_requis

Activez le module Encaissement dans la console.

403

organisation_non_verifiee

Clé pmc_live_ sur une organisation non vérifiée.

403

organisation_inactive

Organisation désactivée : contactez le support.

404

demande_introuvable

Identifiant ou référence inconnus pour votre organisation.

409

reference_deja_utilisee

Même référence avec un montant ou un client différent : nouvelle référence.

409

reference_en_cours

Une requête identique est en cours : relisez avec GET ?reference=.

409

acces_participant_non_verifie

Enregistrez et testez l'accès participant dans la console.

409

quota_atteint

Quota mensuel de l'offre atteint (offre plafonnée).

429

trop_de_demandes_en_attente

Déjà 3 demandes en attente pour ce client.

429

limite_journaliere

Déjà 10 demandes à ce client en 24 heures.

502

participant_refus

Votre banque ou mobile money a refusé la demande : voir le message.

503

connecteur_indisponible, service_suspendu

Service momentanément indisponible : réessayez plus tard.

Mode test : résultats simulés#

Montant se terminant par

Résultat après ~10 s

13

REFUSE

99

EXPIRE

autre

PAYE

Cette page vous a-t-elle aidé ?