
Wave
Wave - API Checkout
Crée une session de paiement Wave, redirige le client vers wave_launch_url et confirme le paiement par webhook signé.
Même prompt, avec et sans ce contexte
Les passages barrés sont ceux que l'IA a inventés. Basculez pour voir la sortie avec le contexte.
› Ajoute un paiement Wave dans ma route Next.js /api/pay.
1export async function POST(req: Request) {2 const { phone, amount } = await req.json();3 const res = await fetch("https://api.wave.com/v1/pay", {Endpoint inexistant4 method: "POST",5 headers: { "X-API-KEY": process.env.WAVE_KEY },Header inventé6 body: JSON.stringify({7 phone_number: phone,Champ inconnu8 amount: amount.toFixed(2),Décimales refusées en XOF9 currency: "FCFA",Devise invalide10 }),11 });12 const { payment_url } = await res.json();Champ absent de la réponse13 return Response.redirect(payment_url);Champ absent de la réponse14}Testez le code généré avant de le brancher sur la vraie API
Une sandbox Wave répond comme l'API et envoie un webhook signé.
Authentification
- Header
Authorization: Bearer <WAVE_API_KEY>sur chaque requête. - Une clé API est liée à une seule API (Checkout, Payout, Balance). Une clé Checkout ne sert pas pour Payout.
Content-Type: application/json.- Toujours lire la clé depuis
process.env.WAVE_API_KEY. Jamais de valeur en dur.
Endpoints
POST https://api.wave.com/v1/checkout/sessionscrée une session.- Requis :
amount(string, ex."1000"),currency("XOF"),success_url,error_url(HTTPS). - Optionnel :
client_reference(votre identifiant de commande),restrict_payer_mobile(format E.164). - Réponse :
id(préfixecos-),wave_launch_url,checkout_status,payment_status,when_expires.
- Requis :
GET https://api.wave.com/v1/checkout/sessions/:idlit une session.POST https://api.wave.com/v1/checkout/sessions/:id/expireexpire une session ouverte.POST https://api.wave.com/v1/checkout/sessions/:id/refundrembourse une session payée.
Erreurs
400corps invalide : le JSON contientcodeetmessage. Corriger la requête, ne pas réessayer telle quelle.401clé absente ou invalide.403clé valide mais pas pour cette API.404session inconnue.429trop de requêtes : réessayer avec backoff exponentiel.5xxréessayer avec la mêmeIdempotency-Key.
Webhooks
- Événements :
checkout.session.completed,checkout.session.payment_failed. - Header
Wave-Signature: t=<timestamp>,v1=<signature>. - Signature : HMAC-SHA256 de
timestamp + corps brutavecWAVE_WEBHOOK_SECRET, comparée en temps constant. - Lire le corps brut (
await req.text()) avant toutJSON.parse.
Idempotence et limites
- Envoyer
Idempotency-Key: <uuid>sur chaquePOSTpour éviter les doubles sessions. - Une session expire : vérifier
when_expiresavant de rediriger. - Gérer
429avec backoff, pas de boucle serrée.
Pièges courants
Ce que les LLMs inventent le plus souvent pour Wave.
/v1/pay,/v1/paymentset/v1/transactionsn'existent pas. Le seul point d'entrée est/v1/checkout/sessions.amountest une chaîne sans décimales pour le XOF :"1000", pas1000.00.- La devise est
XOF, jamaisFCFAniCFA. - Pas de header
X-API-KEY: c'estAuthorization: Bearer. - Ne pas inventer de domaine
sandbox.wave.com: tester contre la sandbox AfriContext. - Le paiement n'est confirmé que par le webhook, pas par l'arrivée sur
success_url.
Exemple minimal
1type WaveSession = {2 id: string;3 wave_launch_url: string;4 checkout_status: "open" | "complete" | "expired";5 payment_status: "processing" | "cancelled" | "succeeded";6};7 8export async function createWaveCheckout(orderId: string, amountXof: number): Promise<WaveSession> {9 const res = await fetch("https://api.wave.com/v1/checkout/sessions", {10 method: "POST",11 headers: {12 Authorization: "Bearer " + process.env.WAVE_API_KEY,13 "Content-Type": "application/json",14 "Idempotency-Key": crypto.randomUUID(),15 },16 body: JSON.stringify({17 amount: String(Math.round(amountXof)),18 currency: "XOF",19 client_reference: orderId,20 success_url: process.env.APP_URL + "/paiement/succes",21 error_url: process.env.APP_URL + "/paiement/erreur",22 }),23 });24 if (!res.ok) throw new Error("Wave " + res.status + ": " + (await res.text()));25 return res.json();26}Variables d'environnement
WAVE_API_KEYWAVE_WEBHOOK_SECRETAPP_URL