Pour les développeurs
Ajoutez les paiements Mobile Money à votre site ou votre application.
LonghoPay donne à votre serveur une requête pour créer une page de paiement hébergée, des webhooks signés pour connaître le résultat, et un bac à sable qui se comporte comme les vrais réseaux. Vos clients paient par MTN Mobile Money ou Orange Money, et l’argent arrive à l’entreprise pour laquelle vous développez.
Aucune entreprise marchande, aucun numéro de versement ni aucune vérification n’est nécessaire pour commencer. Le bac à sable ne coûte rien.
Commande 1001
Deux billets pour le départ de samedi.
Montant du paiement
5 000
Numéro mobile money
655010010
Votre nom
Aisha N.
Infos facultatives E-mail pour votre reçu
Ce que vous obtenez
Page de paiement hébergée
Une requête authentifiée renvoie une URL de paiement. La page LonghoPay gère le numéro de téléphone, les frais et la validation sur le téléphone du client.
Webhooks signés
Les événements de paiement réussi, échoué, en cours et expiré, signés en HMAC-SHA256, retentés avec délai croissant et renvoyables depuis le portail.
Un vrai bac à sable
Une clé d’accès bac à sable atteint un simulateur. Le numéro du payeur choisit le résultat, pour répéter un refus ou une absence de réponse sans vrai téléphone.
Journaux, usage et état
Journal des requêtes, historique des livraisons et usage de l’API par application, plus une lecture d’état pour les moments où un webhook tarde.
Comment les pièces se parlent
Quatre appels et un webhook. Les deux flèches en pointillé sont celles qui ne prouvent jamais un paiement à elles seules.
- 1. Créer la session de paiement
- 2. Rediriger vers checkout_url
- 3. Validation sur le téléphone
- 4. Webhook signé
- – Retour vers votre site (pas une preuve de paiement)
- – Lecture d’état si un webhook tarde (pas une preuve de paiement)
Ce que votre serveur envoie
La même requête dans trois langages. Gardez la clé d’accès sur le serveur ; le navigateur ne reçoit jamais que checkout_url.
curl -X POST https://api.longhopay.com/api/v1/developer/v1/checkout-sessions \
-H "Authorization: Bearer lp_sandbox_<key-id>_<secret>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Request-ID: 6f0d2c1e-order-1001" \
-H "Idempotency-Key: order-1001-checkout-1" \
-d '{
"external_reference": "ORDER-1001",
"amount": 5000,
"currency": "XAF",
"description": "Order 1001",
"return_url": "https://shop.example.com/payments/return",
"expires_in_seconds": 900,
"metadata": { "order_id": "1001" }
}'Du compte au premier paiement
Inscrivez-vous et vérifiez votre adresse e-mail.
Ouvrez votre espace et soumettez une application bac à sable.
Un administrateur de la plateforme l’examine et l’approuve.
Créez une clé d’accès serveur et un point de réception webhook.
Intégrez, répétez dans le bac à sable, puis passez en production avec une application de production.
Guide d’intégration, pas à pas
D’un compte vide à un paiement réel. Chaque étape nomme l’écran ou la requête concernée, et rien ne suppose qu’une entreprise marchande existe déjà.
1. Créez votre compte développeur et ouvrez un espace
Inscrivez-vous avec votre nom et votre adresse e-mail, ouvrez le lien de vérification et choisissez un mot de passe. Ouvrez ensuite le portail développeur, puis votre espace. Aucune entreprise marchande, aucun numéro de versement ni aucune vérification d’entreprise n’est nécessaire à ce stade.
Une même personne peut détenir un compte marchand et un espace développeur, mais chacun est autorisé séparément : s’inscrire comme développeur ne donne accès aux paiements d’aucune entreprise.
2. Soumettez une application et attendez son approbation
Dans Applications, soumettez une application par environnement. Commencez par une application bac à sable : elle atteint un réseau simulé, donc rien de ce que vous en faites ne déplace d’argent.
- Nom et description : ce que l’administrateur de la plateforme lit pour examiner votre demande.
- Type d’intégration : page de paiement hébergée pour un site ou une application qui envoie le client vers une page LonghoPay ; API serveur pour un backend qui appelle seulement l’API.
- Domaines de retour : les hôtes HTTPS de vos URL de retour, par exemple boutique.example.com. Une page de paiement dont l’URL de retour est sur un autre hôte est refusée.
Un administrateur de la plateforme examine chaque application, bac à sable comme production. Tant qu’elle n’est pas approuvée, vous ne pouvez ni créer de clé d’accès ni enregistrer de webhook. Modifier le type d’intégration, les domaines de retour ou les restrictions d’adresse IP retire l’approbation et demande un nouvel examen.
3. Créez une clé d’accès serveur
Une fois l’application approuvée, ouvrez Clés d’accès API et créez une clé avec les seules portées dont votre serveur a besoin. Pour une page de paiement hébergée, ce sont payments:create, payments:read et webhooks:manage.
La forme d’une clé d’accès lp_sandbox_<key-id>_<secret>4. Créez une session de paiement depuis votre serveur
Votre site ou votre application demande à votre serveur de lancer un paiement. Votre serveur enregistre la commande, puis demande une session de paiement à LonghoPay. Chaque requête porte la clé d’accès en jeton Bearer, un X-Request-ID unique et une Idempotency-Key que vous conservez avec la commande.
Créer une session de paiement curl -X POST https://api.longhopay.com/api/v1/developer/v1/checkout-sessions \ -H "Authorization: Bearer lp_sandbox_<key-id>_<secret>" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -H "X-Request-ID: 6f0d2c1e-order-1001" \ -H "Idempotency-Key: order-1001-checkout-1" \ -d '{ "external_reference": "ORDER-1001", "amount": 5000, "currency": "XAF", "description": "Order 1001", "return_url": "https://shop.example.com/payments/return", "expires_in_seconds": 900, "metadata": { "order_id": "1001" } }'- external_reference
- Obligatoire. Votre propre identifiant, 120 caractères au plus, unique par tentative de paiement.
- amount
- Obligatoire. Un entier positif en francs : 5000 signifie 5 000 XAF. Pas de décimales.
- currency
- Facultatif. XAF, qui est aussi la valeur par défaut.
- description
- Obligatoire, 255 caractères au plus. Affiché au client sur la page de paiement.
- return_url
- Obligatoire. Une URL HTTPS sur l’un des domaines approuvés de l’application, 1 000 caractères au plus.
- expires_in_seconds
- Facultatif, de 60 à 86 400. 900 par défaut, plafonné au maximum du déploiement.
- metadata
- Objet facultatif renvoyé dans les webhooks. N’y mettez jamais de secret ni de donnée personnelle.
La réponse est un 201 avec la session sous data. Conservez id, external_reference, amount, currency, expires_at et checkout_url. Le statut commence à OPEN ; payment_status et status_token restent null tant qu’un client n’a pas commencé à payer.
La réponse, abrégée { "success": true, "responseCode": 201, "data": { "id": "01J9X3M7Q2K8R5T1V4W6Y8Z0AB", "external_reference": "ORDER-1001", "amount": 5000, "currency": "XAF", "status": "OPEN", "payment_status": null, "status_token": null, "expires_at": "2026-09-16T12:15:00Z", "checkout_url": "https://longhopay.com/checkout/<token>" }, "request_id": "01J9X3M7Q2K8R5T1V4W6Y8Z0AC" }Réessayer est sans risque. La même clé avec le même corps renvoie la session existante, de nouveau en 201. La même clé avec un montant, une référence, une URL de retour ou des métadonnées différents est refusée par un 409 IDEMPOTENCY_KEY_CONFLICT. Après un délai dépassé, réessayez avec la clé et le corps d’origine, jamais avec une nouvelle référence tant que l’originale n’est pas résolue.
5. Envoyez le client vers la page de paiement
Redirigez le navigateur du client vers checkout_url. La page LonghoPay affiche le montant et les frais, demande le nom du client et son numéro MTN ou Orange, et envoie la demande d’approbation sur son téléphone. Votre clé d’accès n’est jamais utilisée par le navigateur.
Une fois le paiement réussi ou échoué, la page propose un bouton vers votre URL de retour, complétée de longhopay_reference=<identifiant de session>. Un client qui arrive sur cette page n’est pas une preuve de paiement : retrouvez la commande dans vos propres enregistrements et affichez ce que votre serveur sait.
6. Recevez les webhooks et vérifiez leur signature
Dans Webhooks, ajoutez un point de réception HTTPS abonné au moins à payment.succeeded et payment.failed ; ajoutez payment.processing et payment.expired pour suivre tout le cycle de vie. Le secret de signature n’est affiché qu’une fois, comme une clé d’accès.
En-têtes de chaque livraison X-MobilePay-Event-Id: evt_01J9X3M7Q2K8R5T1V4W6Y8Z0AD X-MobilePay-Timestamp: 1789560000 X-MobilePay-Signature: t=1789560000,v1=<hex-hmac-sha256> webhook-id: evt_01J9X3M7Q2K8R5T1V4W6Y8Z0AD webhook-timestamp: 1789560000 webhook-signature: v1,<base64-hmac-sha256>Lisez les octets bruts avant d’analyser le JSON. X-MobilePay-Signature est un HMAC-SHA256 de <horodatage>.<corps brut>, avec pour clé le secret de signature entier, préfixe whsec_ compris. Comparez en temps constant, rejetez un horodatage périmé, et enregistrez l’identifiant d’événement sous une contrainte d’unicité pour qu’une nouvelle livraison reste sans effet. Répondez 2xx rapidement et faites le vrai travail depuis votre propre file d’attente.
Un vérificateur Node.js const crypto = require('node:crypto'); // rawBody is a Buffer of the exact bytes received; parse JSON only after this returns true. function verifyLonghoPay(rawBody, timestamp, signatureHeader, secret, nowSeconds = Math.floor(Date.now() / 1000)) { if (!Buffer.isBuffer(rawBody) || !/^\d+$/.test(timestamp ?? '')) return false; const ts = Number(timestamp); if (!Number.isSafeInteger(ts) || Math.abs(nowSeconds - ts) > 300) return false; const parts = String(signatureHeader ?? '').split(',').map((s) => s.trim()); if (!parts.includes(`t=${timestamp}`)) return false; const expected = crypto.createHmac('sha256', secret) .update(timestamp + '.').update(rawBody).digest(); return parts.some((part) => { if (!/^v1=[a-fA-F0-9]{64}$/.test(part)) return false; return crypto.timingSafeEqual(expected, Buffer.from(part.slice(3), 'hex')); }); }Si vous préférez une bibliothèque Standard Webhooks, donnez-lui la valeur signing_secret_standard et laissez-la vérifier les en-têtes webhook-id, webhook-timestamp et webhook-signature. Vérifiez un seul schéma entièrement ; ne mélangez pas les deux.
7. Confirmez le paiement et honorez la commande
Un événement payment.succeeded ressemble à ceci. Des champs peuvent être ajoutés ; jamais retirés.
payment.succeeded { "id": "evt_01J9X3M7Q2K8R5T1V4W6Y8Z0AD", "type": "payment.succeeded", "api_version": "2026-09-11", "created_at": "2026-09-16T12:03:41.000Z", "tenant": { "id": "<merchant-public-id>" }, "data": { "payment": { "id": 123, "external_reference": "ORDER-1001", "status": "succeeded", "amount": 5000, "currency": "XAF", "fee": { "base_amount": 5000, "total_collected": 5000, "fee_payer": "MERCHANT" }, "trid": "<payment-reference>", "receipt_number": "<receipt-number>", "metadata": { "checkout_session_id": "01J9X3M7Q2K8R5T1V4W6Y8Z0AB" }, "customer": { "id": "<customer-public-id>" } } } }- Faites correspondre tenant.id, data.payment.external_reference et data.payment.metadata.checkout_session_id à la commande que vous avez enregistrée.
- Vérifiez la devise, puis comparez ce que vous avez facturé à fee.base_amount et ce qui a été encaissé à fee.total_collected.
- Marquez la commande payée et mettez sa livraison en file dans une seule transaction, indexée sur le paiement, pour qu’un événement renvoyé ne puisse pas la livrer deux fois.
- Gardez le succès définitif. Un événement processing ou failed qui arrive plus tard ne doit jamais « dépayer » une commande.
La livraison est au moins une fois : une livraison échouée est retentée jusqu’à sept fois sur environ une journée, et tout événement peut être renvoyé depuis le portail. Votre récepteur doit traiter un doublon comme déjà pris en charge.
8. Rattrapez un webhook qui n’arrive pas
Exécutez une vérification en arrière-plan pour les commandes encore ouvertes après leur expiration. Lisez la session avec son jeton, puis l’état du paiement avec le status_token que la session renvoie.
Les deux lectures d’état GET https://api.longhopay.com/api/v1/checkout-sessions/<token> GET https://api.longhopay.com/api/v1/payment-intents/status/<status_token>- OPEN, aucun paiement
- Attendez expires_at, puis libérez la commande.
- EXPIRED, aucun paiement
- Libérez la commande. Une session inutilisée n’envoie aucun webhook.
- PROCESSING
- Continuez d’attendre. Ne lancez pas un second prélèvement.
- REQUIRES_RECONCILIATION
- Laissez la commande non résolue et contactez les opérations LonghoPay.
- SUCCEEDED
- Validez la référence, le montant et la devise, puis livrez exactement une fois.
- Paiement FAILED ou EXPIRED
- Proposez une nouvelle référence seulement si la commande est encore disponible.
Les webhooks et cette vérification peuvent se croiser. Les deux doivent passer par la même déduplication de livraison.
9. Répétez dans le bac à sable
Une clé d’accès bac à sable atteint un simulateur, jamais MTN ni Orange. Le résultat est scénarisé à partir du numéro du payeur saisi sur la page de paiement.
- Se termine par 0000
- Le paiement est refusé.
- Se termine par 0001
- Le payeur ne répond jamais. Il reste en attente jusqu’à ce que vous forciez un résultat.
- Tout autre numéro
- Le paiement réussit.
Pour forcer le cas en attente vers une fin, appelez la route bac à sable avec la référence du paiement, le trid de la ressource d’état.
Forcer un résultat curl -X POST https://api.longhopay.com/api/v1/developer/v1/sandbox/collections/<trid> \ -H "Authorization: Bearer lp_sandbox_<key-id>_<secret>" \ -H "Content-Type: application/json" \ -d '{"outcome":"SUCCESS"}'FAILED est l’autre résultat accepté. Répétez le succès, le refus, le paiement non résolu, l’expiration d’une session inutilisée, une réponse perdue réessayée avec la même clé, une panne du récepteur et son renvoi, et des événements en double ou dans le désordre. Les paiements bac à sable ne sont jamais versés et n’apparaissent sur le tableau de bord d’aucune entreprise.
10. Passez en production
- Soumettez une application de production avec le même type d’intégration et vos vrais domaines de retour, et attendez son approbation.
- Donnez son identifiant d’application au propriétaire de l’entreprise qui recevra l’argent. Il l’autorise sous Paramètres → Applications connectées dans son portail marchand ; l’entreprise doit être active et vérifiée. Une application a une seule entreprise réceptrice, fixée une fois autorisée.
- Créez une clé d’accès de production et un webhook de production, et rangez les nouveaux secrets. Clés, secrets, références et données du bac à sable et de la production sont entièrement séparés.
- Encaissez un vrai paiement d’un petit montant et confirmez que le webhook, la vérification d’état et la liste des paiements de l’entreprise concordent.
L’entreprise est propriétaire des fonds et des versements. Révoquer l’autorisation arrête les nouvelles sessions de paiement ; les paiements déjà soumis vont jusqu’à leur résultat enregistré.
Erreurs et codes d’état
Décidez d’après le code HTTP et le champ code de la réponse, jamais d’après le texte du message.
- 400
- État ou commande invalide. Ne réessayez pas sans modification.
- 401
- Clé d’accès absente, invalide, expirée ou révoquée.
- 403
- La portée, la restriction d’adresse IP, l’environnement ou l’autorisation de l’entreprise s’y oppose.
- 404
- Absent, ou volontairement caché à cette clé d’accès.
- 409
- Référence en double ou conflit d’idempotence. Rapprochez avec l’opération existante.
- 422
- Erreurs de saisie nommées sous errors. Corrigez-les.
- 429
- Limite de débit atteinte. Respectez le délai indiqué avec une variation aléatoire bornée.
- 500 / 503
- Ne réessayez que ce qui est idempotent, conservez le request_id, et marquez une pause sur 503.
Un délai dépassé côté client pendant une commande monétaire est un résultat inconnu. Interrogez avec votre référence enregistrée, réutilisez la même clé d’idempotence, et laissez le webhook ou la vérification d’état trancher. Conservez le request_id de chaque réponse pour le support.
La spécification OpenAPI complète peut être téléchargée depuis le portail développeur.
Commencez à développer aujourd’hui
Créez votre compte développeur, soumettez une application bac à sable et effectuez votre premier paiement de test.