Aller au contenu

Concepts clés

Cycle de vie d'un paiement, environnements, jetons de session, API keys et modèle d'orchestration.

Avant d'écrire du code, prenez quelques minutes pour comprendre les concepts de base. Ensuite, chaque appel d'API et chaque événement webhook vous paraîtra clair tout de suite.

Cycle de vie d'un paiement

Un paiement est une conversation entre trois parties : votre serveur, Wajub et la personne qui paie. Chaque changement d'état vient de l'action de l'une d'elles. Le plus rapide pour comprendre le cycle de vie est donc de regarder qui fait quoi, et dans quel ordre.

Le parcours d'un paiement réussi

Six mouvements, dont deux seulement vous reviennent. Vous ouvrez le paiement, vous redirigez, puis vous attendez. Wajub choisit un prestataire, encaisse l'argent et vous dit comment tout s'est terminé.

Quand le paiement n'aboutit pas

Les trois mêmes parties, le même ordre, mais le paiement quitte le parcours idéal. Chaque sortie produit son propre événement : votre endpoint l'apprend exactement comme il apprend un succès.

Quatre états mettent fin à la tentative : succeeded, failed, cancelled et expired. Rien de ce que fait le client ne fait sortir un paiement de ces états. pending, processing et partial sont encore en cours : traitez-les comme ouverts, jamais comme un échec. Les remboursements sont la seule chose qui continue après la fin : un paiement succeeded peut encore devenir refunded ou partially_refunded des jours plus tard.

ÉtatSignificationAction suivante
pendingInitialisé, en attente d'une action du client.Redirigez le client vers la page de paiement.
processingLe prestataire traite le débit.Attendez. Le webhook payment.* vous indique comment il se termine.
succeededFonds reçus. Vous pouvez livrer la commande.Livrez le produit ou le service.
failedRefusé, sans réponse à temps, ou jamais transmis à un prestataire.Affichez une erreur, proposez de réessayer.
cancelledAnnulé par le client ou le marchand.Aucune action nécessaire.
expiredLa fenêtre de paiement s'est fermée avant la fin.Relancez le paiement si nécessaire.
partialUne partie du montant est réglée, le reste est encore en cours.Gardez la commande ouverte. Elle peut encore atteindre succeeded.
refundedUn paiement réussi a été entièrement remboursé.Gérez le retour.
partially_refundedUn remboursement partiel a été appliqué.Suivez le montant restant.

Comment un paiement passe d'un état à l'autre

  1. Vous appelez POST /payments, ce qui crée une transaction en pending.
  2. Le client effectue le paiement sur la page hébergée (pay.wajub.com).
  3. Wajub traite le débit avec le meilleur prestataire disponible (voir Orchestration).
  4. Wajub envoie un webhook payment.succeeded à votre serveur.
  5. Vous vérifiez le statut via GET /payments/{id} et livrez la commande.

C'est à l'étape 4 que la machine à états vous atteint. Chaque transition enregistrée par Wajub émet un événement, et un événement livré à votre endpoint ressemble à ceci. Le type se trouve dans event, et data contient le paiement exactement tel que GET /payments/{id} le renverrait :

payment.succeeded
{
"id": "evt_test_aio5DpN577tNU2vOxdmu",
"event": "payment.succeeded",
"data": {
"id": "trx_test_CSUGajfv9xh0XQ5wu2lx",
"amount": 5000,
"amount_paid": 5000,
"currency": "XAF",
"status": "succeeded",
"channel": "cm.mtn",
"customer": {
"id": "cus_test_sAaim5apjocIgtlhzJY3",
"email": "amina@example.com"
},
"sandbox": true,
"created_at": "2026-09-11T10:24:00Z"
},
"livemode": false,
"pending_webhooks": 1,
"api_version": "2026-09-01",
"request": {
"id": null,
"idempotency_key": null
},
"created": "2026-09-11T10:26:13Z"
}

Sandbox ou live

Wajub fournit deux environnements entièrement isolés. Une seule URL de base sert les deux. L'environnement est déterminé par l'API key que vous utilisez.

SandboxLive
Cléspk_test.… / sk_test.…pk.… / sk.…
ArgentAucun mouvement de fonds réelPaiements réels
Données de testNuméros de téléphone de testDonnées clients réelles
PérimètrePaiements, remboursements, transferts, clients, webhooksTout, y compris les liens, les factures, les taxes et Shield

API keys

Trois types de clés, chacun avec un rôle précis :

Clé publique (pk.… / pk_test.…)sûre côté clientfacultatif
Initialisez des paiements depuis le navigateur ou l'application mobile. N'a pas accès aux opérations sensibles.
Clé privée (sk.… / sk_test.…)serveur uniquementfacultatif
Accès complet à l'API : paiements, transferts, remboursements, solde. Ne doit jamais quitter votre backend.
Clé restreinte (rk.… / rk_test.…)serveur uniquementfacultatif
Limitée à des ressources précises (par ex. payment.read). Idéale pour les intégrations tierces ou les services à privilèges minimaux.

Jetons de session

La page de checkout hébergée (pay.wajub.com) s'exécute dans le navigateur du client : elle ne peut donc pas détenir d'API key. Elle utilise à la place un jeton de session, renvoyé par POST /payments sous le nom authorization_token et déjà inclus dans l'authorization_url vers laquelle vous redirigez. Le jeton est limité à un seul paiement, il ne peut rien faire d'autre que payer ce paiement, et vous pouvez le confier sans risque à un navigateur.

Sa durée de vie suit celle du paiement. La fenêtre de paiement est de 24 heures par défaut, ajustable de 5 minutes à 30 jours avec expires.in. Une fois que le paiement atteint un état final, le jeton reste valable pendant un court délai de grâce : 5 minutes après un succès, pour que le payeur puisse recharger son reçu, et 60 secondes après un échec, une annulation ou une expiration, pour qu'un onglet de checkout encore ouvert puisse découvrir le résultat. Ensuite, il ne fonctionne plus.

Vous ne manipulez le jeton vous-même que si vous intégrez le checkout dans votre propre page au lieu de rediriger. Votre serveur crée le paiement comme d'habitude :

Serveur, créer le paiement
import { Wajub } from '@wajub/node';

const wajub = new Wajub({ apiKey: process.env.WAJUB_API_KEY! });

const payment = await wajub.payments.create({
  amount: 5000,
  currency: 'XAF',
  customer: { email: 'amina@example.com' },
});

// Send payment.authorization_token to your frontend.

Votre frontend transmet ce jeton au SDK navigateur, qui est un package différent et ne voit jamais votre API key :

Navigateur, afficher le checkout
import { mount } from '@wajub/js';

await mount('#checkout', { sessionId: authorizationToken });

Consultez Wajub Components pour le checkout intégré complet.

Modèle d'orchestration

Quand vous traitez un paiement, Wajub ne se contente pas de le transmettre. Il l'orchestre :

  1. Routage : choisit le meilleur prestataire selon le canal, le pays et le montant.
  2. Exécution : appelle l'API du prestataire.
  3. Repli : si le prestataire principal échoue, réessaie avec le suivant.
  4. Rapprochement : associe les callbacks du prestataire à la transaction d'origine.

Tout cela est transparent pour vous. Il vous suffit de créer un paiement et d'écouter le webhook.

Suivez l'orchestration en temps réel

Ouvrez Konsole → Event Stream pour voir la décision de routage et les réponses des prestataires au moment où elles arrivent.

Identifiants de ressources

Chaque identifiant de ressource se compose d'un préfixe, puis de test_ quand l'objet vit dans la sandbox, puis de 20 à 24 caractères aléatoires selon la ressource. Un identifiant vous indique donc deux choses d'un coup d'œil : ce qu'il désigne, et quel environnement l'a produit. Stockez les identifiants en texte, avec de la place pour 40 caractères.

PréfixeRessourceLiveSandbox
trx_Transaction de paiementtrx_CSUGajfv9xh0XQ5wu2lxtrx_test_CSUGajfv9xh0XQ5wu2lx
po_Transfert (payout)po_225KMKULRQqYvlhrgUOEpo_test_225KMKULRQqYvlhrgUOE
rfd_Remboursementrfd_9xh0XQ5wu2lxCSUGajfvrfd_test_9xh0XQ5wu2lxCSUGajfv
ben_Bénéficiaireben_LRQqYvlhrgUOE225KMKUben_test_LRQqYvlhrgUOE225KMKU
dsp_Litigedsp_hrgUOE225KMKULRQqYvlhdsp_test_hrgUOE225KMKULRQqYvlh
pm_Moyen de paiementpm_sAaim5apjocIgtlhzJY3xpm_test_sAaim5apjocIgtlhzJY3x
cus_Clientcus_sAaim5apjocIgtlhzJY3wQ8scus_test_sAaim5apjocIgtlhzJY3wQ8s
evt_Événement webhookevt_aio5DpN577tNU2vOxdmuZGhTevt_test_aio5DpN577tNU2vOxdmuZGhT

Trois ressources suivent leur propre règle. Une facture commence toujours par inv_, sans segment d'environnement. Un lien de paiement n'a aucun préfixe : son identifiant fait neuf caractères, comme kQ7vB4nL6, car c'est aussi l'URL publique que reçoivent les gens. Un message de litige est un UUID.

Servez-vous du préfixe comme garde-fou

Un identifiant test_ qui arrive dans votre base de données de production est un bug de configuration, pas un paiement. Vérifier le préfixe avant de livrer une commande repère une API key mal choisie bien avant votre comptable.

Montants

Contrairement à beaucoup de prestataires de paiement, Wajub exprime les montants dans l'unité principale de la devise (par ex. 5000 = 5 000 XAF, et non 500 000 centimes). Les devises en franc CFA n'ont pas de subdivision courante, ce qui évite toute confusion.

« Paiement » ou « transaction »

Wajub utilise les deux termes, et ils désignent le même objet :

  • Paiement. Le concept métier. Vous créez un paiement, un client paie, vous livrez la commande.
  • Transaction. La représentation interne. La réponse de l'API utilise "transaction": {...} comme clé racine, et le champ id est préfixé par trx_.

En pratique : vous appelez POST /payments, recevez transaction.id = "trx_xxx", et écoutez les webhooks payment.succeeded. Dans cette documentation, les deux termes sont interchangeables.

Étapes suivantes

Que pensez-vous de ce contenu ?