Aller au contenu

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.

  1. Votre serveur crée une session : POST https://api.wave.com/v1/checkout/sessions, avec l'en-tête Authorization: Bearer <clé API Wave>. Sans lui, Wave répond 401. Champs obligatoires : amount (chaîne), currency (XOF), success_url et error_url (HTTPS). Champ utile : client_reference, votre identifiant de commande.

  2. Wave répond avec un id (préfixe cos-) et un wave_launch_url. Redirigez le client vers cette adresse.

  3. Le client paie dans Wave. La session porte deux statuts : checkout_status (open, complete, expired) et payment_status (processing, cancelled, succeeded).

  4. Wave envoie un webhook : checkout.session.completed si le paiement réussit, checkout.session.payment_failed s'il échoue. Corps : { "id": "EV_…", "type": "…", "data": { …session… } }.

  5. 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-Signature et a la forme t=…,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 id de 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é.
JavaScript
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_url et 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.

Et ensuite ?