Intégrer Wave
Le parcours Checkout de Wave, la vérification canonique des webhooks et la checklist de production.
Wave Business propose une API de paiement appelée Checkout. Ce guide résume son fonctionnement, puis liste ce qu'il faut avant la production. Fiche du fournisseur : Wave dans l'annuaire.
Le parcours Wave Checkout
Sources : Wave Checkout API et Wave Webhooks, vérifiées le 1er octobre 2026.
-
Votre serveur crée une session :
POST https://api.wave.com/v1/checkout/sessions, avec l'en-têteAuthorization: Bearer <clé API Wave>. Sans lui, Wave répond 401. Champs obligatoires :amount(chaîne),currency(XOF),success_urleterror_url(HTTPS). Champ utile :client_reference, votre identifiant de commande. -
Wave répond avec un
id(préfixecos-) et unwave_launch_url. Redirigez le client vers cette adresse. -
Le client paie dans Wave. La session porte deux statuts :
checkout_status(open,complete,expired) etpayment_status(processing,cancelled,succeeded). -
Wave envoie un webhook :
checkout.session.completedsi le paiement réussit,checkout.session.payment_faileds'il échoue. Corps :{ "id": "EV_…", "type": "…", "data": { …session… } }. -
Une session expire 30 minutes après sa création. Le remboursement passe par
POST /v1/checkout/sessions/:id/refund(réponse 200, corps vide).
La documentation Checkout consultée ne décrit pas d'environnement de test. Pour tester avant la production, demandez à Wave Business l'accès à son environnement de test.
Vérifier les webhooks
Cette fonction est la version canonique, que les guides Orange Money et PayTech reprennent par lien.
- L'en-tête s'appelle
Wave-Signatureet a la formet=…,v1=…. - Le message signé est le timestamp suivi directement du corps brut, sans
séparateur :
HMAC-SHA256(<t><corps brut>, secret), en hexadécimal. - Pendant une rotation de clé, l'en-tête peut contenir plusieurs
v1. Acceptez le message si l'une d'elles correspond. - Utilisez le corps brut, pas le JSON relu : un espace de plus change la signature.
- Rejetez un message de plus de 5 minutes. Dédupliquez sur le champ
idde l'événement. - Un en-tête absent ou mal formé se refuse (réponse 400), il ne plante pas.
- Autre mode proposé par Wave : un secret partagé envoyé en
Authorization: Bearer. Wave le juge plus risqué.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifierSignatureWave(entete, corpsBrut, secret, toleranceS = 300) {
if (typeof entete !== 'string') return false;
const paires = entete.split(',').map((p) => p.trim().split('='));
const t = Number(paires.find(([k]) => k === 't')?.[1]);
const signatures = paires.filter(([k, v]) => k === 'v1' && v).map(([, v]) => v);
if (!Number.isFinite(t) || !signatures.length || Math.abs(Date.now() / 1000 - t) > toleranceS) return false;
const attendu = createHmac('sha256', secret).update(`${t}${corpsBrut}`).digest('hex');
return signatures.some((s) => s.length === attendu.length && timingSafeEqual(Buffer.from(s), Buffer.from(attendu)));
}Gardez une seule fonction de traduction entre les statuts Wave et vos propres états.
Checklist de production
- Compte Wave Business ouvert. Seuls les administrateurs voient la section Développeurs du Business Portal (fiche annuaire).
- Entreprise immatriculée : RCCM et NINEA (démarche).
- Déclaration à la CDP faite et récépissé reçu avant de traiter des données personnelles (démarche).
- Rôle de votre service vis-à-vis de la monnaie électronique clarifié (démarche).
- Conditions commerciales et contrat : non publiés dans la documentation consultée. Voyez-les avec Wave Business.
- Adresse de base et clé Wave réelles.
success_url,error_urlet URL de webhook en HTTPS.- Secret de webhook stocké hors du code, signature vérifiée à chaque appel.
- Traitement idempotent : un même événement reçu deux fois ne livre qu'une commande.
- Rapprochement quotidien, par exemple avec l'API Balance & Reconciliation.