Aller au contenu

Démarrage rapide

Un paiement sandbox, de la création au webhook vérifié, pour un compte qui a déjà ses clés.

Un paiement se fait en quatre étapes, et elles ne changent jamais : le créer, envoyer le client vers une page, demander à l'API ce qui s'est réellement passé, puis laisser les webhooks vous informer de tout ce qui arrive après le départ du client. Les quatre modes d'intégration ne diffèrent que par qui affiche la deuxième étape. Le reste de cette page est identique pour tous.

Cette page commence après la configuration

Elle suppose un compte, des clés sandbox et un SDK installé. Si vous n'avez encore rien de tout cela, le démarrage rapide de la plateforme couvre la création du compte, les clés et l'installation, puis parcourt les mêmes quatre étapes depuis zéro.

1. Créez le paiement

Une seule requête porte toute l'intention : combien, dans quelle devise, qui paie, et où cette personne revient. Wajub l'enregistre, la garde en pending, et répond avec une page vers laquelle envoyer le client. Rien n'a encore atteint un opérateur, et personne n'a été débité.

Envoyez-la depuis votre serveur avec la clé secrète. La clé publique crée aussi des paiements, mais elle existe pour le seul cas où l'appel se fait dans un navigateur.

Décrivez le payeur dans l'objet customer. Un email au premier niveau fonctionne aussi et aboutit sur la même fiche client, mais c'est l'objet qui grandit avec vous : il porte aussi name, phone, address et metadata.

POSThttps://api.wajub.com/payments
curl https://api.wajub.com/payments \
  -H "Authorization: sk_test.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5000,
    "currency": "XAF",
    "customer": { "email": "amina@example.com" },
    "reference": "order-4172",
    "callback": "https://shop.example.com/order/complete"
  }'

Wajub répond 201 Created. Deux champs comptent ici : transaction.id, que vous stockez avec votre commande, et authorization_url, où le client va ensuite.

Réponse · 201 Created
{
"code": 201,
"status": "Created",
"message": "Payment initiated",
"authorization_url": "https://pay.wajub.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"authorization_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"transaction": {
"id": "trx_test_CSUGajfv9xh0XQ5wu2lx",
"reference": "order-4172",
"amount": 5000,
"amount_paid": 0,
"currency": "XAF",
"status": "pending",
"customer": {
"id": "cus_test_sAaim5apjocIgtlhzJY3wQ8s",
"email": "amina@example.com"
},
"callback": "https://shop.example.com/order/complete",
"sandbox": true,
"created_at": "2026-09-11T10:24:00Z"
}
}

Les montants sont en unité principale, jamais en centimes

"amount": 5000 vaut 5 000 XAF, pas 50. Wajub n'utilise pas de sous-unités. Un paiement en XAF ou en XOF doit être compris entre 25 et 2 000 000 ; hors de cette plage, l'API répond 422 avec la limite dans errors.amount.

reference vous appartient : c'est votre numéro de commande, renvoyé à chaque lecture et consultable dans le Dashboard. Il n'a aucune contrainte d'unicité : l'envoyer deux fois crée deux paiements.

Ce qui vous protège vraiment d'un double débit, c'est l'en-tête Idempotency-Key. Générez-le vous-même, stockez-le à côté de la commande, et renvoyez la même valeur à chaque nouvelle tentative ; pendant 24 heures, l'API renvoie le paiement d'origine au lieu d'en ouvrir un second, et refuse carrément la clé si le payload a changé. Les SDKs joignent bien une clé automatiquement, mais une nouvelle clé aléatoire à chaque appel, ce qui ne dédoublonne rien. Idempotence présente les stratégies qui fonctionnent.

2. Envoyez le client vers la page

Redirigez vers authorization_url. Le client choisit un opérateur, saisit son numéro, confirme sur son téléphone et revient sur votre callback.

C'est le Checkout hébergé, et c'est le mode que nous recommandons. Wajub possède l'écran, la liste des opérateurs, la nouvelle tentative quand une demande de confirmation expire et la formulation de chaque échec. Rien de tout cela ne vous appartient, et rien de tout cela n'est du code à maintenir.

La session reste valide 24 heures. Passez expires.in en minutes, de 5 à 43 200, pour fermer la fenêtre plus tôt.

En sandbox, les six derniers chiffres du numéro décident du résultat, et …000000 réussit. Le tableau complet des suffixes et un numéro par opérateur se trouvent dans le démarrage rapide de la plateforme. N'importe quel code PIN est accepté.

3. Vérifiez avant de livrer

Le retour du client sur votre callback ne prouve rien. N'importe qui peut ouvrir cette URL à la main, et un client qui ferme l'onglet ne l'ouvre jamais. Demandez à l'API ce qui s'est passé, depuis votre serveur, avec l'id stocké à l'étape 1.

GEThttps://api.wajub.com/payments/{id}
curl https://api.wajub.com/payments/trx_test_CSUGajfv9xh0XQ5wu2lx \
  -H "Authorization: sk_test.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…"

La réponse est le paiement tel que Wajub le connaît, quoi qu'on ait dit au navigateur. channel indique l'opérateur réellement utilisé, et amount_paid ce qui a vraiment été encaissé :

Réponse · 200 OK
{
"code": 200,
"status": "OK",
"message": "Payment retrieved",
"transaction": {
"id": "trx_test_CSUGajfv9xh0XQ5wu2lx",
"reference": "order-4172",
"amount": 5000,
"amount_paid": 5000,
"currency": "XAF",
"status": "succeeded",
"channel": "cm.mtn",
"customer": {
"id": "cus_test_sAaim5apjocIgtlhzJY3wQ8s",
"email": "amina@example.com"
},
"sandbox": true,
"created_at": "2026-09-11T10:24:00Z"
}
}

Livrez la commande uniquement quand status vaut succeeded, et seulement si amount et currency correspondent à ce que vous avez facturé. Un paiement encore pending n'est pas un échec, c'est un client qui n'a pas encore terminé : laissez la commande ouverte et laissez l'étape suivante la clore.

4. Laissez le webhook boucler la boucle

Vérifier au retour couvre les clients qui reviennent. Les webhooks couvrent tous les autres, ainsi que chaque événement sans aucun navigateur derrière : une confirmation que l'opérateur envoie avec dix minutes de retard, un remboursement émis depuis le Dashboard, une session qui expire sans avoir été ouverte.

Abonnez-vous à payment.* et vous recevez les six événements qu'un paiement peut produire.

ÉvénementSe déclenche quand
payment.createdLe paiement a été enregistré et est pending
payment.processingLa requête a atteint l'opérateur, le client reçoit la demande de confirmation
payment.succeededFonds capturés. C'est sur celui-ci que vous livrez la commande
payment.failedRefusé, fonds insuffisants ou erreur de l'opérateur
payment.expiredLa session a expiré avant que le client confirme
payment.cancelledAnnulé de votre côté ou par le client

Les webhooks sont documentés une seule fois, ailleurs

L'enregistrement de l'endpoint, la vérification de signature, le calendrier des nouvelles tentatives et le catalogue complet se trouvent dans Webhooks. Une règle a pourtant sa place ici : dédoublonnez sur X-Wajub-Delivery-Id. Une livraison échouée est retentée jusqu'à cinq fois et chaque tentative porte ce même id, c'est ce qui empêche une nouvelle tentative de livrer la commande deux fois.

Choisissez ensuite le mode à mettre en production

Ce que vous venez de construire, c'est le Checkout hébergé. Les trois autres modes changent une seule chose : qui affiche l'écran de l'étape 2. La création, la vérification et le traitement des webhooks restent mot pour mot ce qu'ils sont ci-dessus.

Et ensuite ?

Que pensez-vous de ce contenu ?