All providers

Wave

payment·🇸🇳🇨🇮🇲🇱🇬🇳🇺🇬🇧🇫🇬🇲🇳🇪🇨🇲🇸🇱🇨🇩
Documentation

Capabilities

CapabilityTypeStatusiMethod
create_checkout_sessionsynchronousAvailablePOST
create_payout_batchasynchronousAvailablePOST
expire_checkoutsynchronousAvailablePOST
get_balancesynchronousAvailableGET
get_payoutsynchronousAvailableGET
get_transactionssynchronousAvailableGET
refund_checkoutsynchronousAvailablePOST
search_checkoutssynchronousAvailableGET
send_payoutsynchronousAvailablePOST
verify_paymentsynchronousAvailableGET
verify_recipientsynchronousAvailablePOST
webhook_payment_completedwebhookAvailablePOST

Gotchas

  • Stocker session.id immédiatement avant de rediriger l'utilisateur — c'est le seul identifiant pour appeler verify_payment côté serveur.
  • wave_launch_url doit être ouvert directement dans le navigateur de l'utilisateur. Ne jamais l'ouvrir dans une WebView ou un iframe — le paiement ne s'initiera pas correctement.
  • La session expire par défaut 30 minutes après création. Après expiration, checkout_status passe à 'expired' et le paiement est impossible.
  • amount est une string, pas un nombre. XOF n'accepte aucune décimale — envoyer "5000" et non "5000.00" ou 5000.
  • La clé API est liée à un seul wallet Wave. Pour opérer dans plusieurs pays, obtenir une clé par wallet.
  • Il n'y a pas d'environnement sandbox. Tous les appels touchent la production.
  • Chaque requête POST /v1/payout-batch doit inclure un header Idempotency-Key unique (UUID v4 recommandé, max 255 chars). Un batch peut distribuer des fonds à des dizaines de destinataires — un retry sans idempotency key peut déclencher tous les payouts en double.
  • Cet endpoint est asynchrone — il retourne immédiatement un batch.id sans attendre le traitement des payouts. Interroger GET /v1/payout-batch/{id} en polling jusqu'à status === 'complete'.
  • batch.status === 'complete' ne signifie pas que tous les payouts ont réussi. Inspecter le status de chaque payout individuel dans la réponse — certains peuvent être 'failed' pendant que d'autres sont 'succeeded'.
  • Il n'y a pas de status 'success' ou 'failed' au niveau du batch lui-même, seulement 'processing' et 'complete'. Le résultat réel est dans chaque payout.
  • Chaque payout dans le batch est traité indépendamment. Un échec sur un payout (ex: insufficient-funds) n'annule pas les autres.
  • Impossible d'expirer une session déjà complétée ou déjà expirée — Wave retourne HTTP 409.
  • Les sessions expirent automatiquement 30 minutes après création. Cet endpoint est utile pour libérer immédiatement le stock réservé sans attendre l'expiration naturelle.
  • La clé API est liée à un seul wallet. Pour consulter le solde de plusieurs wallets (multi-pays), obtenir une clé API par wallet et appeler cet endpoint une fois par clé.
  • amount est retourné en string et peut être négatif en cas de débit. Toujours parser en nombre avant d'effectuer des comparaisons.
  • Utiliser cet endpoint pour surveiller un payout en status 'processing' retourné par send_payout. Un payout 'processing' peut encore basculer vers 'succeeded' ou 'failed' — ne jamais le marquer définitivement échoué avant d'avoir observé un status final.
  • Un payout en status 'reversed' a été annulé via POST /v1/payout/{id}/reverse. Le montant + les frais sont recrédités sur le wallet expéditeur.
  • Les transactions sont retournées de la plus ancienne à la plus récente pour un jour donné. Pour récupérer les transactions les plus récentes en premier, il faut inverser le tableau côté client.
  • Sans paramètre date, Wave retourne uniquement les transactions du jour courant (UTC). Pour la réconciliation, toujours spécifier la date explicitement.
  • La pagination utilise des curseurs opaques (end_cursor), pas des offsets. Ne pas construire le curseur manuellement — utiliser uniquement la valeur retournée par l'API.
  • Pour récupérer toutes les transactions d'un jour, boucler tant que page_info.has_next_page === true en passant end_cursor comme paramètre after.
  • Cet endpoint est idempotent — appeler refund deux fois sur la même session retourne HTTP 200 sans créer de remboursement en double.
  • Seule une session avec payment_status 'succeeded' peut être remboursée. Appeler refund sur une session non complétée retourne une erreur.
  • Le remboursement est total — Wave ne supporte pas les remboursements partiels via cet endpoint.
  • Alternative par transaction ID : si l'ID de session est perdu mais que le transaction_id Wave est connu, utiliser POST /v1/transactions/{transaction_id}/refund (Balance API) pour rembourser par transaction.
  • Si client_reference n'est pas unique par commande dans votre système, la recherche peut retourner plusieurs sessions — filtrer sur checkout_status === 'complete' && payment_status === 'succeeded' pour identifier la session payée.
  • Cet endpoint est le mécanisme de récupération principal quand session.id n'a pas été stocké (crash serveur entre create et redirect). Toujours passer un client_reference à la création pour pouvoir retrouver la session.
  • Chaque requête POST /v1/payout doit inclure un header Idempotency-Key unique (UUID v4 recommandé, max 255 chars). Sans cette clé, un retry en cas d'erreur réseau peut créer un payout en double.
  • Si le payout retourne status 'processing', ne pas le marquer comme échoué — le considérer comme pending et surveiller via GET /v1/payout/{id}. Marquer comme échoué trop tôt peut pousser l'utilisateur à retenter, causant un doublon.
  • En cas d'erreur 5xx, timeout ou connexion interrompue : retenter avec le MÊME Idempotency-Key et un backoff exponentiel. Wave garantit l'idempotence.
  • En cas d'erreur 'idempotency-mismatch' (409) : le même Idempotency-Key a été utilisé avec un body différent. Générer un nouveau key et retenter.
  • Le reversal d'un payout est limité à 3 jours après création. Après ce délai, POST /v1/payout/{id}/reverse retourne une erreur.
  • receive_amount est une string sans décimales pour XOF — envoyer "5000" et non 5000 ou "5000.00".
  • Toujours vérifier côté serveur avant de valider une commande — ne jamais se fier uniquement au success_url ou au webhook. Un utilisateur peut manipuler la redirection.
  • Vérifier les DEUX champs : checkout_status === 'complete' ET payment_status === 'succeeded'. Un checkout_status 'complete' avec payment_status 'cancelled' signifie que le paiement a échoué.
  • verify_payment est aussi le mécanisme de récupération si le webhook n'a pas été reçu (timeout, serveur indisponible, redémarrage).
  • Limite de rate : 30 vérifications incluant une comparaison de nom (champ name fourni) pour le même numéro dans une fenêtre de 5 minutes. Au-delà, ce numéro est bloqué pendant 60 minutes. Les appels sans name ne sont pas soumis à cette limite.
  • NAME_NOT_KNOWN ne signifie pas que le nom est incorrect — cela signifie que Wave n'a pas d'information légale sur ce destinataire (non KYC-2). Ne pas bloquer un payout sur cette base seule.
  • La comparaison de nom utilise Jaro-Winkler avec un seuil de 0.65 — les variations orthographiques mineures (accents, abréviations) peuvent retourner MATCH.
  • national_id_match nécessite une activation spécifique par Wave. Sans cette activation, le champ retourne toujours null même si national_id est fourni.
  • Wave envoie aussi l'événement checkout.session.payment_failed lorsqu'un paiement échoue. Implémenter un handler pour cet événement afin de notifier l'utilisateur ou libérer le stock réservé.
  • Ne jamais fulfiller une commande sur la base du webhook seul. Appeler verify_payment (GET /v1/checkout/sessions/{id}) pour confirmer côté serveur — le payload webhook peut être forgé.
  • Répondre HTTP 200 immédiatement et traiter de façon asynchrone. Wave retry pendant 3 jours si votre endpoint ne répond pas dans les 5 secondes.
  • Implémenter l'idempotence via event.id — Wave peut livrer le même événement plusieurs fois. Vérifier que la commande n'est pas déjà fulfillée avant d'agir.
  • Vérifier la signature Wave-Signature en production : HMAC-SHA256 du timestamp + raw body. Utiliser le raw body, pas le JSON parsé — certains frameworks modifient le body entre réception et parsing.
  • [MUST TELL USER] Wave whitelisté 15 plages d'IPs qui envoient les webhooks. Si votre serveur filtre le trafic entrant, ajouter ces IPs dans votre firewall ou les webhooks échoueront silencieusement. La liste est disponible dans le Business Portal.
  • [MUST TELL USER] En développement local, Wave ne peut pas joindre localhost. Utiliser un tunnel HTTPS (ex: `ngrok http 3000`) et configurer l'URL ngrok dans le Business Portal avant de tester.

Use with AI agents

After installing the plugin or adding the MCP server, prompt your agent:

Use the Wave API to [describe your task]
Install the plugin →

Details

Category
payment
Capabilities
12
Verified
0
Countries
11
Sandbox
No