Aller au contenu

Journal des modifications

Les nouveautés de la plateforme Wajub, classées par date, version et produit.

Toutes les modifications importantes apportées à l'API et aux produits Wajub. La version actuelle de l'API est 2026-10-11 (Gestion des versions). Les changements additifs ne nécessitent aucune action. Les changements cassants sont publiés sous une nouvelle date.

2026-10-23

Sync Webhooks

  • Nouvel événement account.onboarding_declined : le marchand a refusé la connexion dans l'onboarding hébergé. Rien n'est connecté et le lien d'invitation reste valable ; reason contient ses mots quand il en a donné. Comme les autres événements des étapes du marchand, il n'atteint qu'un endpoint abonné à son nom. Comptes, pour les plateformes Sync

2026-10-17

CASSANT Sync

Un changement sur toutes les versions d'API à la fois : il n'est pas lié à une version datée, et X-Wajub-Version ne conserve pas l'ancien comportement. Il concerne les livraisons Sync qui portent X-Sync-Event, celles des étapes du marchand lui-même, et le retour vers votre page.

  • Cassant pour une plateforme qui vérifie X-Sync-Signature : ces livraisons ne le portent plus. Vérifiez X-Sync-Signature-V1 avec X-Sync-Timestamp, comme le fait constructEvent dans les SDK. Vérification de la signature
  • Cassant pour une plateforme qui lit sync_uid : ces livraisons désignent la connexion dans account seulement, l'identifiant acc_…, et ne portent aucun identifiant interne de Wajub pour la connexion, la plateforme ou le marchand. account.onboarding_started ne porte plus l'adresse depuis laquelle le marchand a ouvert le lien. Livraisons du cycle de vie Sync
  • Cassant pour une plateforme qui lit sync_id sur sa page de retour : le marchand revient avec account, state et status seulement. Retour sur votre page
  • Seul un 2xx vaut livraison : une redirection n'est pas suivie et compte comme un échec. Chaque tentative part vers l'endpoint tel qu'il est à ce moment, signée avec son secret actuel, et un endpoint désactivé ou supprimé entre-temps ne reçoit plus rien.

API Webhooks Konsole

  • Les renvois manuels de webhooks ne sont plus décomptés d'un quota mensuel, sur aucun plan. Un même événement repart vers le même endpoint au plus une fois toutes les 5 minutes, depuis Konsole ou avec POST /events/{id}/resend. L'appel ignore un endpoint encore dans ce délai, et répond 429 avec error_code: event_resend_cooldown et un en-tête Retry-After quand c'est le cas de chaque endpoint qui n'a pas accepté l'événement. Un 429 qui n'est pas une limitation
  • Konsole : Renvoyer dans ce délai indique combien de minutes il reste, et Relancer les livraisons échouées ignore ces livraisons et les compte dans son message. Testeur de webhooks

Link Orchestration

  • Le webhook propre à un lien de paiement ne compte comme livré que sur un 2xx : toute autre réponse, une redirection comprise, est enregistrée comme échouée et retentée, et une redirection n'est jamais suivie. Son envoi de test indique seulement si l'endpoint l'a accepté. Dans le Dashboard
  • La cible Slack ou webhook d'une règle d'alerte doit être une URL https qui ne pointe pas vers une adresse privée ou interne : Wajub n'envoie rien à une autre, et ne suit aucune redirection qu'elle renvoie. Alertes

CASSANT API

Un changement sur toutes les versions d'API à la fois : il n'est pas lié à une version datée, et X-Wajub-Version ne conserve pas l'ancien comportement.

  • Cassant pour une intégration qui fabrique ou modifie un cursor : une liste n'accepte qu'un next_cursor ou un prev_cursor tel qu'une réponse l'a renvoyé. Toute autre valeur, un curseur fait à la main ou modifié compris, renvoie un 422 sur cursor. Un curseur renvoyé avant ce changement est encore lu jusqu'au 2026-11-13. Pagination par curseur
  • Cassant pour une intégration qui envoie à GET /balance une devise que Wajub ne sait pas convertir : currency accepte la devise de votre compte, ou une devise pour laquelle Wajub a un taux de change, en majuscules ou en minuscules. Tout autre code renvoie un 422 sur currency. Solde
  • Cassant pour une plateforme qui distingue 403 et 404 avec X-Sync : une connexion qui appartient à une autre plateforme répond 404 Sync account not found., comme un identifiant qui n'existe pas. Clés et accès

API

  • Une clé restreinte (rk. ou rk_test.) utilisée depuis un navigateur déclenche la même alerte de sécurité qu'une clé secrète : le propriétaire du compte et les administrateurs reçoivent un e-mail. Pour l'instant, la requête aboutit encore ; Wajub la refusera plus tard avec le même 403, déplacez donc ces appels vers votre serveur. Les clés privées sont bloquées dans le navigateur

2026-10-16

CASSANT API

La version d'API 2026-10-12, celle des nouveaux comptes, apporte aussi ces changements. Les versions antérieures gardent l'ancien comportement, et les webhooks suivent la version actuelle, 2026-10-11.

  • Un paiement n'a plus theming. Les versions antérieures lisent toujours la clé, null sur un paiement créé à partir de maintenant.
  • POST /webhooks et PUT /webhooks/{id} vérifient chaque type de events dans le catalogue des événements : un type qui n'existe pas, mal orthographié ou un préfixe comme payment.* répond 422 sur events.N. * prend toujours tous les types, et un endpoint garde les types qu'il a déjà. Endpoints de webhook
  • Une entrée de la liste de blocage Shield ne porte plus team_id. Shield
  • Les items d'un paiement fait sur la page d'une facture se terminent par la remise sur toute la facture, quand il y en a une : un élément avec kind: discount, name: Discount, un total négatif, et quantity et unit_price à null. L'objet Payment

Gestion des versions

API Paiements

  • DELETE /payments/{id} répond 409 quand le paiement ne peut pas être annulé maintenant : error_code: payment_in_progress pendant qu'un débit est en cours, le payeur le validant sur son téléphone ou payant sur la page du prestataire, et payment_partly_paid sur un paiement partial ou dont des échéances sont payées, à clôturer avec POST /payments/{id}/close. Un paiement processing sans rien en cours peut être annulé, de même qu'un paiement dont l'expires_at est passé sans qu'il ait encore expiré. Annuler un paiement
  • De deux débits envoyés en même temps sur un paiement, le second répond 409 payment_in_progress. Un paiement dont le débit est encore en cours quand expires_at passe attend l'issue de ce débit avant de pouvoir expirer, et en live un débit sur un paiement dont l'expires_at est passé répond 400. Expiration
  • Certains opérateurs, comme Orange Money au Burkina Faso, n'acceptent un paiement qu'avec un code que le payeur génère d'abord. Le débit répond alors 202 avec action: payer_otp et, dans payer_otp, comment obtenir le code : débitez de nouveau avec lui dans data.otp. Après trois codes refusés, le débit répond 402 otp_attempts_exceeded. En sandbox, bf.orange demande le code et accepte 123456. Un code que le payeur génère
  • L'objet paiement renvoie client à une clé secrète ou restreinte : d'où le payeur a payé, la page de paiement hébergée, Wajub.js, un SDK mobile ou une autre application, telle qu'elle se déclare, avec sa version et sa plateforme quand elles sont connues. L'objet Payment
  • POST /payments ne conserve plus theming, sur toutes les versions : le champ est ignoré, jamais refusé.
  • otp_masked_contact ne contient plus que le contact masqué, comme 080******78, et il est vide quand le prestataire n'en nomme aucun. GET /payments/options donne à chaque canal et à chaque opérateur logo_png, son logo en PNG. Prévisualiser les moyens
  • Pour un débit, un numéro Mobile Money peut commencer par 00 au lieu de +. Le 0 qui fait partie d'un numéro en Côte d'Ivoire, au Bénin, au Congo et au Burkina Faso est conservé, et les renumérotations du Bénin et du Gabon se lisent sous leur nouvelle forme. Formats de numéros de téléphone
  • Sandbox : les numéros à dix chiffres du Bénin (+2290190…, +2290191…, +2290197…) et les blocs actuels du Gabon (+24174…, +24177…, +24162…, +24165…, +24166…) ont des numéros de test, et 00 peut remplacer +. Scénarios de test

API

  • POST /accounts, POST /tax/registrations, POST /customers/{id}/tax_ids et POST /disputes/{id}/messages respectent Idempotency-Key : un appel répété répond ce qu'a répondu le premier, pendant 24 heures. Idempotence
  • Un chemin qui encode une barre oblique ou une barre oblique inverse, %2F ou %5C, répond 404. Forme d'une erreur
  • Le customer d'un litige est l'identifiant cus_ du client, même une fois ce client supprimé, et sa transaction l'identifiant trx_ du paiement. L'un ou l'autre est omis quand il n'y en a pas.
  • Sur les versions antérieures à 2026-10-12, un canal de GET /channels et GET /providers indique la devise dans laquelle il paie, ou null pour un canal qui ne paie pas dans une seule devise, comme une carte ou un actif crypto, au lieu de XAF pour chaque canal. Couverture

API Link

  • single_use_link: true ferme un lien après son premier paiement réussi et n'y laisse payer qu'un payeur à la fois : un autre payeur apprend qu'un paiement est en cours, et le lien rouvre si ce paiement n'aboutit pas. Un remboursement ne le rouvre pas. Si un second paiement aboutit malgré tout, le propriétaire, les administrateurs et les membres finance de votre équipe reçoivent un e-mail qui nomme le paiement à rembourser. Un lien qui avait déjà single_use_link se ferme désormais après son premier paiement, sauf celui d'un produit digital, dont le réglage devient single_use_access. Comment un lien se ferme
  • single_use_access: true, pour un produit digital, permet à chaque acheteur de télécharger le fichier une seule fois ; le lien reste ouvert à l'acheteur suivant. L'acheteur télécharge par un lien propre à son paiement, jamais par l'adresse du fichier lui-même, et un remboursement total arrête le téléchargement. file_url sur POST /links prend une adresse à vous : un fichier téléversé dans le Dashboard répond 422. Produits numériques
  • L'URL de réunion d'un service parvient au payeur dans l'e-mail de confirmation de son paiement, avec ce qu'il faut préparer, et n'est plus sur la page avant le paiement.
  • link.expired est envoyé une fois, dans la journée qui suit le passage de l'expiry_date d'un lien, sauf si le lien est archivé entre-temps, avec le lien dans data, aux endpoints qui s'y abonnent, et GET /events?type=link.expired le liste. Catalogue des événements

API Factures

  • Les remises sur les lignes sont déduites du subtotal, du total et du amount_due d'une facture, et une remise ne peut plus faire passer une ligne sous zéro : 422 sur items.N.discount_value. Les factures ouvertes qui ont une ligne remisée sont remises en cohérence, ce qui peut baisser leur total et leur amount_due, jamais augmenter ceux d'une facture déjà envoyée, et fait passer à paid une facture déjà payée à hauteur de son nouveau total, avec invoice.updated et invoice.paid. Calcul d'une ligne
  • Les items d'un paiement fait sur la page d'une facture donnent à chaque ligne son total, net de sa remise et taxe comprise, sur toutes les versions. L'objet Payment
  • global_discount_type et global_discount_value déduisent une remise de toute la facture, qui les renvoie avec has_global_discount. Le reçu et la confirmation de paiement l'indiquent après les lignes. Une remise sur toute la facture
  • Les devis et les estimations créés avec POST /invoices se lisent, se corrigent, s'annulent et se suppriment par leur id, et GET /invoices?document_type=quote ou estimate les liste. /send et /mark-paid répondent 400 sur eux. Devis et estimations
  • Vos clients sont relancés par e-mail de leurs factures impayées avant et après l'échéance, factures envoyées par l'API comprises, sauf si vous désactivez les relances dans Paramètres → Facture → Rappels automatiques, où vous choisissez aussi les jours. Une facture déjà envoyée depuis le Dashboard garde les relances déjà prévues pour elle ; vos jours prennent le relais pour les jours qui suivent. Relances
  • Les e-mails de facture et de relance sont rédigés dans la language de la facture, pied de page compris.

SDK

  • Les prochaines versions des SDK Flutter (1.6.0), React Native (1.5.0) et Android (1.3.0) guident le payeur pour un code qu'il génère dans le menu de son opérateur, dans un nouvel état, PAYER_OTP_REQUIRED (CheckoutState.payerOtpRequired en Dart). Un when ou un switch qui liste tous les états doit lui prévoir une branche. Chaque montant qu'affiche l'interface est ce que paie le payeur, frais Wajub compris quand il les supporte, pour le moyen ou l'opérateur qu'il choisit. États

2026-10-15

NOUVEAU Plugins

  • Module PrestaShop 1.0.1, pour PrestaShop 8.1 à 9 : Mobile Money et Carte bancaire comme moyens de paiement à part entière, avec le formulaire de paiement de Wajub dans le tunnel de commande (Classic et Hummingbird), et Autres moyens de paiement sur la page de paiement Wajub, chacun affiché seulement si votre compte le propose pour le panier. La commande est créée quand le client la passe et réglée par le webhook, paiements en plusieurs échéances compris ; un paiement inférieur au total compte, et le client paie le reste. Une commande que PrestaShop divise en plusieurs colis est payée, remboursée et annulée comme une seule. PrestaShop
  • Module PrestaShop 1.0.1 : Connexion avec Wajub obtient la clé de la boutique depuis le Dashboard, avec le type de client prestashop ; le back-office et l'adresse e-mail de la boutique sont prévenus à partir de 14 jours avant l'expiration d'une clé ainsi créée. Les remboursements dans les deux sens, depuis la page de la commande et depuis le Dashboard ; un remboursement que Wajub ou le module refuse ne crée pas d'avoir. Une connexion par boutique en multiboutique, et les données du client pour le module RGPD de PrestaShop. Connecter votre application à Wajub
  • Module PrestaShop 1.0.1 : des alertes dans le back-office pour un environnement choisi sans clé, une clé qui expire, une boutique ouverte au public encore en mode Test, Wajub absent du tunnel de commande et une tâche planifiée qui ne s'exécute pas ; les réglages préviennent une boutique non servie en HTTPS en production. Wajub · Test s'affiche dans l'en-tête du back-office tant que la boutique accepte des paiements de test. La désinstallation garde la trace des paiements, remboursements et notes Wajub des commandes. Alertes du back-office

2026-10-14

CASSANT API Transfers

Un changement de confidentialité sur toutes les versions de l'API à la fois : il n'est lié à aucune version datée, et X-Wajub-Version ne conserve pas l'ancien comportement.

  • Cassant pour une intégration qui affiche registered_name après un name_mismatch : POST /beneficiaries/{id}/verify ne renvoie que les initiales du nom détenu par l'opérateur quand il ne correspond pas à celui que vous avez déclaré, P*** N***. Une correspondance renvoie toujours le nom complet. Vérifier le nom d'un portefeuille

CASSANT API Paiements

Un changement de sécurité sur toutes les versions de l'API à la fois : il n'est lié à aucune version datée, et X-Wajub-Version ne conserve pas l'ancien comportement.

  • Cassant pour une intégration qui lit le client d'un paiement avec une clé publique (pk.) : POST /payments ne renvoie dans customer, shipping_address et billing_address que ce que la requête a envoyé, jamais le client que le compte a déjà avec cet e-mail ou ce téléphone. GET /payments/{id}, ainsi que POST /payments/{id}, /splits et /confirm, ne renvoient ni customer, ni shipping_address, ni billing_address, et payment_method ne contient que channel. Lisez-les depuis votre serveur, avec une clé privée ou restreinte. Authentification
  • Cassant pour une intégration qui lit le client que renvoie POST /customers avec une clé publique : quand le compte a déjà un client avec cet e-mail ou ce téléphone, la réponse, toujours 200, contient son id et les champs envoyés par la requête. Lisez le client enregistré depuis votre serveur, avec une clé privée ou restreinte ; ces clés ne changent pas. Authentification
  • Cassant pour une intégration qui réutilise une Idempotency-Key sur POST /payments avec un autre corps : le corps entier est comparé, expires, customer, metadata, bearer, address et shipping compris, et un changement répond 422. Sur POST /payments, une clé qu'une clé publique a utilisée répond 422 à une clé privée ou restreinte, et inversement. Idempotence

API Paiements

  • expires.in envoyé vide, blanc ou null donne à POST /payments son expiration par défaut, 24 heures. Sur PATCH /payments/{id}, il laisse l'expiration telle qu'elle était. Modifier un paiement préparé
  • OPay (ng.opay) et PalmPay (ng.palmpay) acceptent un numéro de n'importe quel réseau, comme Wave, Express Union, Djamo et Capitec Pay. API directe

CLI

  • CLI 1.7.4 : un 406 Private Key Required, la réponse à une clé publique (pk.) sur une route qui demande une clé secrète, comme wajub payments list ou wajub customers retrieve, indique que la requête demande une clé secrète (sk.) ou restreinte (rk.), dit d'où vient la clé publique (WAJUB_API_KEY, --api-key ou le profil) et dit comment y mettre une clé secrète, wajub login pour un profil.

Dashboard

  • Modifier les coordonnées ou le statut d'un client demande désormais une vérification de sécurité récente, comme l'affichage d'une clé : modifier, bloquer, débloquer, activer, désactiver ou supprimer un client, un par un ou, hors modification, par lot, et le supprimer définitivement.
  • Supprimer des clients par lot les anonymise désormais, comme la suppression d'un seul client.
  • Créer ou modifier un client live qui a un e-mail n'échoue plus sur une erreur.
  • Le type d'un bénéficiaire s'affiche en lecture seule sur sa page de modification : il est fixé à sa création, et la page ne propose plus un changement qu'elle ne faisait pas.

Components

  • Wajub.js 1.8.1 : @wajub/angular est nouveau, pour Angular 17 et les versions ultérieures, installé avec @wajub/js 1.8.0 ou une version ultérieure à ses côtés. provideWajub() et WajubService chargent Wajub.js. Des composants standalone affichent le checkout hébergé, <wajub-checkout-embed>, et chaque groupe de champs, de <wajub-card> à <wajub-crypto>, ou n'importe lequel d'entre eux avec <wajub-component>, et injectConfirmPayment() envoie un champ. Les options sont des inputs, les callbacks des outputs, et onBeforeSubmit est l'input beforeSubmit. Le package fonctionne avec zone.js comme en zoneless, et avec Angular SSR. @wajub/js, @wajub/react, @wajub/vue et @wajub/svelte passent en 1.8.1 sans autre changement. Angular
  • Wajub.js 1.8.0 : loader: 'skeleton' garde votre page immobile pendant le chargement d'un champ de paiement : un squelette dessiné dans le style de vos champs tient la hauteur du formulaire jusqu'à ce qu'il soit prêt. componentReserveHeight(type, variant, fields), sur wajub et en export synchrone de @wajub/js, donne cette hauteur. componentEstimatedHeight(type, variant, fields), de @wajub/js, donne une estimation identique sur le serveur et à l'hydratation. readyTimeout signale à onLoadError et à loaderror un champ qui n'est pas prêt à temps, avec ready_timeout. Charger sans décaler la page
  • Wajub.js 1.8.0 : appearance.inherit, true ou { input, label, button, background }, reprend le style des champs, du libellé, du bouton et du fond de votre page, sous les clés que vous donnez, dans les champs de paiement, mount() et open(). wajub.appearanceFrom(), aussi sur le client Wajub() et dans @wajub/js, renvoie ce qu'il lit, {} depuis @wajub/js quand la page charge un Wajub.js plus ancien. Reprendre le style de votre page
  • Wajub.js 1.8.0 : onStateChange, onResize et onRedirect à create(), pour les événements statechange, resize et redirect, et on() et off() typent la donnée de chaque événement avec ComponentEventMap. confirmPayment({ timeout }) ne compte plus le temps pendant lequel le paiement attend le payeur, comme APPROVAL_REQUIRED, OTP_REQUIRED ou 3DS_REQUIRED, ni le temps que le payeur passe sur la page du prestataire. Un champ retiré de la page sans unmount() le fait rejeter avec component_unmounted, et un champ remonté repart de INITIATED. Verrouiller votre checkout pendant le paiement
  • Wajub.js 1.8.0 : update({ appearance }), sur un champ, mount() ou open(), change les clés que vous donnez et garde les autres. Une clé donnée à undefined ou null est effacée, et appearance: undefined efface tout, pour revenir à l'image de marque de votre Dashboard Wajub. Sur mount() et open(), un nouveau preset theme remplace le précédent et ce qu'il apportait. update({ layout }) redispose les moyens d'un checkout intégré, en ligne comme dans la superposition. Modifier l'apparence après le montage
  • @wajub/react, @wajub/vue et @wajub/svelte 1.8.0, qui demandent @wajub/js 1.8.0 : chaque option ci-dessus est une prop, et BankTransferComponent et CryptoComponent rejoignent les composants de champs. CheckoutEmbed applique sur place un changement d'appearance, de theme, de locale ou de layout, et ne se recharge que pour un nouveau sessionId ou embedOrigin. useConfirmPayment lit la session au moment de confirmer, depuis une ref ou un getter en Vue et un store ou un getter en Svelte, et un sessionId passé à confirm() l'emporte. Les composants de champs Svelte prennent chaque gestionnaire en prop, et typent toutes leurs props. Mobile Money et carte dans votre propre checkout
  • Changements pour les composants de champs React, Vue et Svelte en 1.8.0 : loader vaut 'skeleton' par défaut, passez donc loader="none" pour garder l'iframe telle qu'elle arrive. minHeight n'a plus de valeur fixe par défaut : le composant tient la place dont le formulaire a besoin, si bien que minHeight={0} n'est plus nécessaire avec variant="fields", et un minHeight que vous passez est gardé. Un nouveau variant, fields, loader, readyTimeout, collectAddress, addressMode ou collectName monte un nouveau champ dans le même conteneur. La prop appearance est envoyée entière : une clé que vous en retirez est effacée. Changer de gestionnaire ne recharge jamais le formulaire. Avec un framework
  • Un champ de paiement dont la session est déjà terminée affiche son message, puis envoie ready si la session a été payée, sinon loaderror avec session_terminal_expired, session_terminal_cancelled ou session_terminal_failed : créez un nouveau paiement. Un champ qui ne peut pas savoir dans quelle page il se trouve envoie loaderror avec component_origin_missing. Quand le formulaire n'arrive pas
  • Wajub.js 1.7.2 : avec variant: 'fields', un composant prend la hauteur de ses champs ; avec les composants de champs React, Vue et Svelte, passez minHeight à 0. Les valeurs de rules que le checkout refuse sont écartées. Dans votre propre bloc de moyen de paiement
  • update({ appearance }) sur un checkout intégré tient pendant les étapes suivantes du payeur. La page vers laquelle checkout() envoie le payeur prend votre apparence dès son premier rendu. Un colorScheme que vous donnez s'applique dès le premier affichage sur chaque page, et masque le bouton clair et sombre du checkout. La color et la police d'une règle .Input atteignent le texte saisi, champs de carte compris, et la color d'une règle .Label atteint le libellé du titulaire de la carte. Une police Google Fonts que le checkout charge atteint les champs de carte, et sans fontSizeBase les champs font 16px sur téléphone ou tablette, pour qu'iOS ne zoome pas au focus. OPay et PalmPay acceptent un numéro de n'importe quel réseau, comme Wave, Express Union et Djamo. Apparence
  • Wajub.js 1.7.1 : appearance.theme réglé sur light, dark, system ou auto est lu comme colorScheme, system valant auto, quand vous ne donnez pas de colorScheme. Les préréglages stripe, night, flat et none ne changent pas. Préréglages
  • Un colorScheme que vous donnez l'emporte sur l'appareil du payeur et sur le choix qu'il a enregistré, dans un champ de paiement comme dans le checkout intégré. variables.fontFamily, qui charge une police Google Fonts connue du checkout, fontSizeBase, qui donne la taille des champs, 16px au moins sur téléphone ou tablette, libellés et aides un cran plus petits, colorText, colorTextSecondary, colorTextPlaceholder et borderRadius stylisent désormais les champs. inputBackgroundColor et inputBorderColor ne stylisent que les champs. Les rules .Input et .Label atteignent les champs, et le contrôle des valeurs de rules s'applique par tous les chemins, update({ appearance }) compris. Règles
  • ready part une fois le formulaire du composant affiché, ou aussitôt quand il n'a aucun formulaire à afficher. Dans le formulaire Mobile Money, chaque opérateur d'un canal qui en regroupe plusieurs, comme MTN et Orange au Cameroun, est un choix à part avec son logo, et avec fields.operator: 'detect' la liste apparaît quand le numéro ne permet pas de reconnaître l'opérateur. Un portefeuille utilisable avec n'importe quel réseau, comme Wave, Express Union ou Djamo, accepte n'importe quel numéro. Dans votre propre bloc de moyen de paiement

API Sync

  • Un sous-compte nomme le marchand qui l'a revendiqué connected_merchant, sur toutes les versions de l'API. slave, le même objet, est déprécié et disparaît dans la version 2026-10-12, qui retire aussi l'id de master et de connected_merchant, le uid d'un canal, une répétition de son id, et identifie un prestataire de GET /providers par prv. et son slug. Versionnage

2026-10-13

CASSANT API Paiements

Un changement de sécurité sur toutes les versions de l'API à la fois : il n'est lié à aucune version datée, et X-Wajub-Version ne conserve pas l'ancien comportement.

  • Cassant pour une intégration qui appelle ces routes avec une clé publique (pk.) : elles répondent désormais 406 Private Key Required. GET /payments, DELETE /payments/{id}, POST /payments/{id}/close et GET /payments/{id}/refunds ; GET /customers, GET, PUT et DELETE /customers/{id}, ainsi que ses block, unblock, activate et deactivate ; toutes les routes /links et /invoices. Faites ces appels depuis votre serveur, avec une clé privée ou restreinte. Une clé publique crée, débite, confirme et lit toujours un paiement par son identifiant, lit GET /payments/options, crée un client avec POST /customers et lit les données de référence. Authentification
  • Cassant pour une clé restreinte qui n'a que des scopes payment.* : POST /payments/{id}/close avec outcome: refund exige aussi refund.write, comme POST /refunds, et GET /payments/{id}/refunds exige aussi refund.read. Ajoutez à la clé le scope de remboursement dont elle a besoin. Scopes des clés restreintes
  • Cassant pour une plateforme dont la connexion a payments sans refunds : avec X-Sync, GET /payments/{id}/refunds et POST /payments/{id}/close avec outcome: refund exigent aussi la capacité refunds de la connexion, comme /refunds : une connexion qui n'a que payments reçoit désormais 403. Capacités du compte

API Paiements

  • POST /payments/{id}/activate accepte reference et description, qui remplacent ceux donnés à la préparation du paiement, quand votre commande n'existait pas encore. Absents, ceux de la préparation restent. Activer un paiement préparé
  • PATCH /payments/{id} vérifie le nouveau montant comme POST /payments : hors des limites de la devise, il répond 422 sur amount, et quand accept ne laisse plus aucun moyen de le payer, 422 sur accept. Il accepte expires.in, de 5 à 43 200 minutes à partir de maintenant, et le paiement garde cette expiration une fois activé. Modifier un paiement préparé

Dashboard CLI Plugins

  • Approuver wajub login ou la connexion d'une application, comme Connexion avec Wajub dans le plugin WordPress, est réservé au propriétaire, à un Administrator ou à un Developer (à un Sandbox User pour une clé sandbox uniquement), et exige un code de vérification de sécurité récent. La page démarre toujours sur Sandbox, quoi que demande l'application, et la personne qui approuve choisit l'environnement. Installation et authentification
  • La personne qui approuve choisit la durée de la clé d'une application : 90 jours, par défaut, ou une durée indéterminée. Une clé de wajub login dure toujours 90 jours. Le propriétaire et chaque Administrator reçoivent un e-mail pour chaque clé créée par un appairage.
  • Paramètres → Développeurs → Clés API indique quand chaque clé cesse de fonctionner : Expire le … ou Expirée le …. Une clé sans expiration n'affiche aucune date. Environnements et API keys
  • Transférer l'équipe, confirmer un payout, et afficher une API key ou copier ses lignes .env demandent un code de vérification de sécurité, de votre application d'authentification ou envoyé par SMS ou par e-mail, comme renouveler ou supprimer une clé. Équipe et sécurité

Components

  • Wajub.js 1.7.0 : frameTitle, passé à create() ou à update() d'un composant, nomme son iframe pour les lecteurs d'écran, dans la langue de votre page.
  • Wajub.js 1.7.0 : quand le paiement se poursuit sur la page du prestataire, le composant émet redirect avec { url, method } et Wajub.js y emmène votre page. Au retour de cette page, le payeur arrive sur la page Wajub de la session, dans la langue du composant, qui affiche le résultat puis l'envoie sur le callback du paiement avec status, reference et trxref, ou garde le résultat affiché quand il n'y a pas de callback. Une page restée sur une version antérieure de Wajub.js garde l'ancien comportement. Quand le paiement se poursuit sur la page du prestataire
  • Un envoi demandé avec submit() ou confirmPayment() qu'un composant refuse, comme un numéro Mobile Money vide ou invalide, une carte laissée incomplète ou rejetée, des champs de carte encore en chargement, un virement sans IBAN ni numéro de compte ou un paiement crypto sans actif, émet error avec submission_failed et un message pour le payeur, et confirmPayment() rejette avec cette erreur. Un appui sur Entrée dans un formulaire qui n'est pas prêt n'affiche la raison que dans le composant. Un envoi pendant le paiement ne fait rien : rien n'est débité deux fois. Les écrans OTP, PIN, validation sur le téléphone, USSD et 3-D Secure donnent leur hauteur à resize, et une fenêtre de carte bloquée par le navigateur après onBeforeSubmit laisse un bouton Continuer sur … dans le composant. Envoyer le paiement

Plugins

  • Plugin WordPress 1.4.0 : deux nouveaux moyens de paiement WooCommerce, Mobile Money et Carte bancaire, chacun avec le formulaire de paiement de Wajub dans votre checkout, classique et Blocks. Les deux restent désactivés tant que vous ne les activez pas : une boutique existante ne voit aucun changement. WordPress
  • Plugin WordPress 1.4.0 : Connexion avec Wajub, dans l'assistant de configuration et dans les réglages, obtient la clé du site une fois que vous l'approuvez dans le Dashboard, sans rien à copier ; coller des clés reste possible. L'expiration de la clé s'affiche dans l'administration, et l'adresse e-mail d'administration du site reçoit un e-mail dès 14 jours avant cette date.
  • Plugin WordPress 1.4.0, changement de comportement : chaque environnement paie uniquement avec sa propre clé. Un site en Sandbox qui n'a qu'une clé live ne prend plus de paiements réels avec elle, et n'en prend aucun tant que vous n'ajoutez pas de clé sandbox ou ne passez pas en Live. À la mise à jour, un site de production dans ce cas passe une fois en Live et le signale ; une copie locale, de développement ou de préproduction reste en Sandbox.
  • Plugin WordPress 1.4.0 : un client WooCommerce ne paie que ce qui reste. Un paiement inférieur au total de la commande, comme un paiement en plusieurs fois clôturé plus tôt, compte pour elle, et le client paie le reste depuis la page de paiement de la commande. Les remboursements faits dans WooCommerce sont répartis entre les paiements de la commande. WordPress

2026-10-12

NOUVEAU API

La version d'API 2026-10-12 est celle des nouveaux comptes. Un compte existant garde sa version et l'obtient avec X-Wajub-Version ; les webhooks suivent toujours la version actuelle, 2026-10-11. Ses changements cassants :

  • Un canal de GET /channels et GET /providers n'a plus currency.
  • currency est obligatoire sur POST /transfers et sur chaque ligne de POST /transfers/batch. Les versions antérieures prennent encore XAF par défaut : envoyez-la quelle que soit votre version.
  • Un lien de paiement n'a plus de category_id : POST et PUT /links ne le prennent plus, GET /links ne filtre plus dessus, et un lien ne le renvoie plus.
  • Un transfert ou un remboursement arrêté avant son envoi affiche cancelled, avec le motif merchant_rejected ou cancelled_by_wajub, et ?status=failed ne le liste plus. Les versions antérieures affichent failed. Les webhooks suivent la version actuelle : un tel arrêt part en transfer.failed ou refund.failed tant que 2026-10-12 n'est pas actuelle, puis en transfer.cancelled ou refund.cancelled.

Gestion des versions

API Paiements

  • POST /payments/{id}/splits débite les tranches en live, sur Mobile Money. Chaque appel débite la tranche suivante ; le paiement reste partial jusqu'à la dernière, et une tranche refusée laisse acquises les tranches payées. Chaque tranche payée est créditée sur votre solde dès qu'elle passe, avec sa part des frais Wajub, en live comme en sandbox ; elle est versée sur votre compte de versement comme tout paiement, et la page du paiement dans le Dashboard affiche sa retenue. Paiements fractionnés

  • Nouveau POST /payments/{id}/close : clôturez un paiement réglé en partie, en gardant (outcome: keep) ou en remboursant (outcome: refund) ce qui a été encaissé. Il passe à succeeded pour ce montant, et les remboursements se mesurent sur lui. DELETE /payments/{id} répond 409 payment_partly_paid sur un tel paiement. Clôturer un paiement

  • Un débit Mobile Money au-dessus du plafond par transaction répond 422, en sandbox comme en live. Une fois qu'un paiement a un plan en tranches, chaque débit suivant, y compris celui de la page de paiement, prend la tranche suivante, et un autre plan répond 422.

  • Nouveau POST /payments/{id}/confirm : terminez depuis votre serveur, avec votre clé secrète, l'étape OTP, PIN, téléphone, date de naissance, adresse ou fenêtre du prestataire d'un débit. Il répond comme le débit : 200, 202 avec l'étape suivante, ou 402 avec attempts_remaining. Confirmer une étape

  • Chaque canal Mobile Money annoncé débite désormais en live : T-Money, Tigo Pesa, HaloPesa, Free Money, Vodafone Cash (Ghana et Égypte), AirtelTigo Money, Zamtel Kwacha, TNM Mpamba, Africell RDC, Moov Money au Gabon, au Burkina Faso et au Mali, et MTN au Liberia et en Guinée. Djamo et Capitec Pay acceptent tout numéro. Numéros de téléphone

  • accept.channels accepte mobile pour tous les opérateurs Mobile Money. L'objet paiement renvoie bearer, expires_at et link, le lien de paiement dont il vient. Choisir ce qu'un paiement accepte

  • Un débit carte accepte card_bin à la racine du corps, comme chaque champ de data. En sandbox, la carte de test est elle aussi lue à la racine (card.number, card.holder).

  • Un débit sur un paiement déjà processing répond 409 avec error_code: payment_in_progress. La réponse

  • Le 402 d'un débit refusé porte payer_message, une phrase à montrer telle quelle au payeur. Codes de statut

  • callback doit être en HTTPS (http://localhost et http://127.0.0.1 acceptés en sandbox). metadata.cancel_url est obsolète : le callback est l'unique retour, quelle que soit l'issue. Checkout hébergé

  • GET /payments?reference= liste les paiements créés avec exactement cette reference. Un paiement se lit par son id ; reference vous appartient et n'est pas unique, et Idempotency-Key évite les doublons.

  • Un paiement échoué porte failure_reason et failure_message, sur le paiement et dans payment.failed. Motifs d'échec

  • Un blocage Shield répond 403 avec error_code: shield_blocked et block_reference. Blocages Shield

  • Un compte dont la vérification n'est pas approuvée ne peut encaisser aucun paiement live, quel que soit le prestataire : 402 merchant_not_verified. Conformité

  • Un customer_id inconnu sur POST /payments répond 422 sur ce champ, et non 404 Resource Not Found. operator et save_payment_method sont lus à la racine d'un débit. GET /payments/options est documenté et répond dans l'enveloppe habituelle.

  • La sandbox débite comme le live : les numéros d'échec répondent 402 avec error_code: insufficient_funds, un numéro au format local est lu dans le pays du canal, et chaque canal Mobile Money annoncé a un numéro de test, Vodafone Cash Égypte (+2010…) et Orange Money Sierra Leone (+23276…) compris. Capitec Pay a ses propres numéros de test (+2761…), qui choisissent le résultat ; le numéro de test de tout opérateur le paie toujours. Un numéro qui n'est pas un numéro de test reçoit un 422 qui liste les numéros de test de l'opérateur du canal. Scénarios de test

  • GET /channels : min_amount et max_amount sont des nombres en unité principale (c'étaient des chaînes cent fois plus grandes : retirez toute division par 100), et live et charge disent ce qu'ils promettent. Le plafond par transfert d'un canal est lui aussi lu en unité principale. Couverture

  • Chaque 422 porte status: "Unprocessable Content" et un objet errors ; un refus qui ne concerne aucun champ précis range son message sous errors.request. Codes de statut

  • Les filtres des listes sont vérifiés au lieu d'être ignorés, chacun avec une 422 sur son champ :

    • toute liste paginée, codes et juridictions de taxe compris : un page qui n'est pas un entier à partir de 1 ;
    • GET /links et GET /invoices : un per_page hors de 1–100, et un sort_by ou un sort_dir inconnu ;
    • GET /invoices : un status ou un payment_status inconnu, et un date_from, date_to, due_date_from ou due_date_to qui n'est pas une date ou finit avant de commencer ;
    • GET /links : un type inconnu ; GET /events : un type qu'aucun endpoint ne reçoit ;
    • GET /channels : un country inconnu ; GET /countries : une region inconnue ; GET /currencies : un type autre que fiat, crypto ou all, lu sans tenir compte de la casse.

    GET /links trie désormais d'abord sur le sort_by et le sort_dir demandés, puis du plus récent au plus ancien entre liens à égalité. Pagination

  • Les limites de débit se comptent par environnement : une rafale en sandbox n'entame plus le budget live. Lire un transfert ne compte plus dans la part des transferts. Un 429 ou un 400 de version porte désormais les en-têtes CORS, X-Wajub-Version est autorisé en preflight, et Retry-After, X-RateLimit-Reset et X-Wajub-Version sont lisibles depuis un navigateur. Un 429 d'une limite plus stricte, comme celle des écritures de versement, répond comme le limiteur principal : type la nomme (payout_writes), et retry_after comme Retry-After donnent l'attente réelle. X-RateLimit-Reset donne la fin de la fenêtre en cours. Limites de débit

  • GET / indique dans env l'environnement de la clé utilisée. /health renvoie la version de l'API. Monitoring

  • Identité est disponible sur Growth, Scale et Enterprise ; Pay as you go reçoit 403. Identité

  • Référence de l'API : chaque paramètre est décrit avec un vrai exemple, et les champs de requête qui acceptent null l'indiquent. Les pages des factures, des remboursements, du relevé et des créances montrent leur réponse de succès, et les listes de remboursements, bénéficiaires, liens, comptes et endpoints de webhook un élément complet. Les filtres d'un GET ne sont que des paramètres de requête, beneficiary sur POST /transfers prend un id ou un objet, et les chemins des litiges s'écrivent {id}. La spécification OpenAPI déclare des schémas réutilisables (Payment, Transfer, Refund, Customer, Beneficiary, Invoice, Link, Account, Event, WebhookEndpoint, Balance, Error) que ses réponses référencent, pour en générer un client, et GET /events liste les 77 types d'événement qu'il accepte en type. Les pages d'aperçu des ressources sont disponibles en français. Référence de l'API

API Versements

  • Un versement refusé répond 422 avec un error_code à côté de message et errors, sur POST /transfers, sur chaque ligne refusée d'un lot et sur POST /accounts/{id}/payouts. Une ligne de lot dont le bénéficiaire n'existe pas dit beneficiary_not_found. Refus de versement
  • Chaque ligne de lot passe les contrôles de POST /transfers : les bornes de la devise (amount_out_of_range), et un bénéficiaire désigné par son id seulement (beneficiary_not_found).
  • Un versement désigne le canal de son opérateur (ke.mpesa, eg.vodafone…). Le seul canal générique est cm.mobile, qui déduit cm.mtn ou cm.orange du numéro : en live d'après le vrai plan de numérotation du Cameroun, comme les paiements, en sandbox d'après les préfixes de test. Tout autre {pays}.mobile est refusé comme un canal inconnu. Bénéficiaires
  • Un bénéficiaire supprimé reste sur ses transferts et son relevé, avec deleted: true. Payer un bénéficiaire désactivé répond 422 beneficiary_inactive au lieu de 404.
  • Un versement live peut répondre 429 payout_queue_busy avec Retry-After : renvoyez-le avec la même Idempotency-Key. Limites
  • Les versements de toutes les devises comptent dans votre plafond quotidien de versements, versements retenus pour vérification compris, dans l'API comme dans le Dashboard. Un versement sandbox dont le portefeuille couvre le montant mais pas les frais est refusé avec insufficient_balance.
  • Un ancien versement du Dashboard qui attend encore votre confirmation, et qui affiche pending en live, peut de nouveau être confirmé ; il peut être retenu en review avant son départ. Après un refus, le bouton Confirmer peut de nouveau être utilisé. Statuts des transferts
  • Documentation : un versement refusé conserve le bénéficiaire passé en ligne. La référence et les statuts des transferts suivent la vraie réponse, Balance documente disputed, in.transit et hold, le tableau des retenues gagne une ligne « Wajub a restreint votre compte », et les routes qui partagent le compteur d'écritures de versement sont listées. Transferts, Balance

API Factures

  • Un paiement n'est rattaché qu'à une facture de son propre compte.
  • GET /invoices : amount_min et amount_max se lisent en unité principale. La facture gagne customer, l'identifiant cus_ ; un paiement fait sur la page d'une facture la désigne dans invoice. invoice.paid et invoice.payment_succeeded sont envoyés.
  • POST /invoices/{id}/send répond 422 quand la facture n'a aucun destinataire et 400 pour une facture déjà payée, annulée ou remboursée. mark-paid refuse un brouillon, une facture déjà payée et un montant nul. Une facture payée passe à refunded une fois ses paiements en ligne intégralement remboursés ; une facture payée en partie en ligne aussi, avec invoice.updated. Factures
  • Les factures envoyées par l'API prennent leur numéro dans la numérotation de votre compte, la même séquence que le Dashboard : votre préfixe (INV- par défaut), l'année et un compteur à quatre chiffres remis à zéro chaque année (INV-2026-0001). Un numéro est unique dans votre compte.
  • Nouveau champ language (fr ou en) sur POST et PUT /invoices et dans chaque réponse de facture. Il fixe la langue des e-mails, des relances et du PDF, et la page de la facture s'ouvre dans cette langue (ajoutez ?locale=fr ou ?locale=en pour changer). Sans lui, une facture prend la langue préférée du client lié, sinon celle de votre compte (Paiement — Langue), sinon en ; les factures créées dans le Dashboard enregistrent la leur selon la même règle.
  • Le PDF de la facture est public une fois la facture envoyée : https://api.wajub.com/i/{id}/pdf, avec ?locale=fr|en. invoice.created est envoyé une seule fois, avec les lignes et les totaux, sans invoice.updated pendant la construction de la facture. PUT /invoices/{id} envoie un seul invoice.updated, avec les lignes et les totaux enregistrés, et aucun quand il ne change rien.
  • sort_by sur GET /invoices trie désormais la liste, et search trouve les factures par le nom et l'e-mail écrits dessus. Le payment_date de mark-paid devient paid_at dès que le paiement solde la facture. Le currency de POST et PUT /invoices doit être une devise prise en charge par Wajub, sinon 422.
  • Sur une facture sans e-mail, l'adresse que le payeur donne sur sa page est enregistrée comme customer_email, avec invoice.updated. Un e-mail que vous avez renseigné n'est jamais remplacé.
  • Un paiement sur la page de la facture tient compte des avoirs du Dashboard : la facture ne passe à paid qu'une fois ce qui a été payé, moins les avoirs, égal au total. Factures

Link Paiements

  • Le custom_url d'un lien de paiement doit être unique sur Wajub, liens supprimés compris (422). L'objet lien renvoie single_use_link et tous les autres champs que vous pouvez définir, et consulter un lien n'envoie plus link.updated. Liens de paiement
  • GET /customers?country= filtre sur le pays de l'adresse du client. PUT /customers/{id} garde name sauf si un champ de nom est envoyé avec une valeur. Clients

API Remboursements Litiges

  • Un remboursement live qui a pris de l'argent sur votre solde porte ledger_balance_before, ledger_balance_after et ledger_balance_currency. Un remboursement que l'opérateur refuse après son envoi reste processing, sans jamais revenir à pending. Un remboursement échoué porte toujours un failure_reason, pris dans une seule liste en production et en sandbox. Remboursements
  • refund.succeeded part une fois le remboursement sorti de votre solde et porte ledger_balance_before et ledger_balance_after, sandbox comprise. Un remboursement qui échoue finit avec la raison du prestataire ; ops_failed seulement sans raison connue. Gérer les remboursements
  • La reference d'un remboursement n'est jamais que la vôtre : l'identifiant du prestataire est dans provider_reference. Un metadata de remboursement vide vaut {}, et la recherche de remboursements en sandbox couvre aussi reference.
  • dispute.deadline_approaching est envoyé deux jours avant l'échéance d'un litige. dispute.closed suit aussi dispute.lost. Les litiges ouverts depuis Pocket reçoivent un due_date à sept jours, et le même rappel. Litiges
  • Une preuve de litige exige un texte ou un fichier (422). Les justificatifs et les pièces jointes des messages sont des fichiers privés : chaque réponse de l'API qui renvoie un litige donne à chaque fichier une url, un lien signé valable 30 minutes, et les webhooks ne portent que file_path. Le Dashboard les relie de la même façon et affiche dans le fil du litige le fichier joint par le payeur depuis Pocket. Litiges

Sync

  • Un litige perdu rend votre commission selon le commission_refund_policy de la connexion, comme un remboursement, et la sandbox déplace la commission dans les deux sens. fee.received donne la commission dans la devise de la règle tarifaire. Capacités des comptes
  • Tant que les paiements d'une connexion sont suspendus, les lectures avec X-Sync fonctionnent ; seuls les appels qui déplacent de l'argent sont refusés. Une connexion Relay ne porte plus de date d'invitation. POST et PUT /accounts acceptent l'email du marchand, un rappel garde valide le lien que vous avez envoyé, et un nouveau lien relance les trente jours, comme le fait désormais Renvoyer l'invitation dans le Dashboard. Les événements dispute.* sont copiés vers la plateforme. Onboarding
  • POST et PUT /accounts enregistrent vos metadata telles que vous les envoyez. Chaque compte les renvoie ({} si vides) ; PUT les fusionne, et une clé envoyée à null est supprimée. Le compte affiche pricing.min_fee, et GET /accounts?status= filtre sur le statut affiché, expired compris. Sous-comptes
  • Après l'onboarding, le marchand revient sur votre callback avec account, l'identifiant acc_…, à côté de state et status. Le callback doit être en HTTPS (http://localhost et http://127.0.0.1 acceptés avec une clé sandbox) ; un callback déjà enregistré continue de fonctionner.
  • 50 invitations ouvertes au plus par environnement, au-delà POST /accounts répond 429 ; les connexions Relay ne comptent pas. Une connexion de l'autre environnement répond 404. Une connexion Relay n'a pas de lien d'autorisation : authorization_url vaut null, et /token répond 422.
  • POST /accounts/{id}/payouts ne renvoie que le versement automatique du jour, qui peut être failed. Versements
  • Les événements envoyés par le Dashboard portent account à côté de sync_uid. account.updated est envoyé une fois, avec le compte entier, quand PUT /accounts/{id} modifie un compte, quand POST /accounts/{id}/token remet une invitation annulée en pending, et quand Wajub envoie le versement d'un marchand Lite (last_payout_at). Un enregistrement qui ne change rien n'envoie rien, DELETE envoie account.deauthorized, et on peut de nouveau choisir account.updated sur un endpoint. Événements webhook
  • Commissions dues : transaction est l'id du paiement (trx_…), celui que lit GET /payments/{id}, dans GET /accounts/{id}/commission-receivables et dans les webhooks account.commission_receivable_recorded et account.commission_receivable_collected, pour toutes les versions de l'API.

Tax

  • Un remboursement n'annule sa part de taxe que si le paiement en a enregistré, et il le fait même après la désactivation de Tax ou quand votre offre ne la couvre plus. Rapports
  • La taxe d'un paiement est enregistrée au taux national, comme /tax/calculate la calcule, et n'est pas enregistrée tant que votre offre ne couvre pas Tax. Les alertes de seuil convertissent les ventes dans la devise du seuil, et le seuil UE compte tous les États membres.
  • La page de paiement hébergée n'affiche aucune ligne de taxe, et les montants convertis n'en contiennent pas. La taxe se calcule quand le paiement est crédité, sans jamais s'ajouter à ce que paie le payeur.
  • Les numéros fiscaux des clients sont vérifiés avec les mêmes formats que le vôtre, avec ou sans séparateurs, et ajouter un numéro déjà enregistré relance sa vérification (200). gh.vat et gh.tin suivent le format de la GRA (C0001234567, ou un PIN de Ghana Card) ; l'ancienne forme de gh.tin à 12 caractères est refusée. Configuration
  • Enregistrements fiscaux : un doublon pour le même pays et le même État répond 422, un identifiant mal formé 404, et PUT peut réactiver un enregistrement révoqué. /tax/calculate répond 422 pour un pays inconnu et 404 pour un client inconnu, et retirer le numéro fiscal d'un client avec un identifiant mal formé répond 404 au lieu de 500. API Tax
  • Documentation : exemples d'arrondi corrigés, autoliquidation précisée, permissions et pagination documentées.

Shield

  • Les paiements sandbox n'ont jamais d'effet sur la notation du risque en live. Risk Scoring
  • La liste de blocage contrôle chaque valeur selon son type et l'enregistre sous une seule forme (+237 670 00 00 00 et 237670000000 sont une seule entrée). Une valeur impossible répond 422, et retirer une entrée inconnue répond 404. Règles
  • Un PUT /shield/settings partiel garde vos réglages Advanced enregistrés. /shield/stats compte les revues comme la file et inclut les litiges under_review. Les règles en test sont toujours évaluées après la règle live qui décide. API Shield

Orchestration

  • Le routage écarte un prestataire que Wajub marque en maintenance (provider_in_maintenance), bientôt disponible ou désactivé (provider_unavailable) ; seuls les prestataires disponibles ou en bêta reçoivent des paiements. Le simulateur de routage indique chaque motif. Règles de routage
  • Chaque tentative enregistre sa latence, affichée dans la chronologie du paiement et pour chaque candidat dans le journal de routage. Une connexion peut être limitée à des devises choisies, dans l'assistant et sur sa page. Prestataires
  • Les alertes du Dashboard limitées à un canal ou à une règle, l'aperçu d'impact d'une règle et le conseiller lisent le canal et la règle de routage de chaque paiement, et « Cascade récupérée » ne compte que les basculements. Ils comptent les paiements routés à partir de cette version : les paiements antérieurs ne portent ni canal routé ni règle.
  • GET /channels renvoie countries: [] pour un canal global au lieu de [""].
  • Documentation : le délai à laisser à votre client HTTP (au moins 90 s), les prestataires que vous pouvez connecter, et les moyens internationaux à venir sur Couverture. Orchestration

Webhooks

  • payment.attempt_failed est envoyé quand une tentative est refusée aussitôt et que le paiement repasse pending. payment.expired et payment.cancelled partent en sandbox comme en live ; une expiration sandbox n'envoie plus payment.failed.
  • Chaque tentative de livraison est signée avec le secret actuel de l'endpoint : une rotation couvre aussi les nouvelles tentatives.
  • link_payment_complete n'est plus livré (payment.succeeded le couvre), et GET /events ne liste que les types livrés.
  • Dans les contenus, un objet vide comme metadata reste {} au lieu de [], à la livraison, au renvoi ou dans une liste. Les événements payment.split.* portent le paiement complet, payment_method compris.
  • beneficiary.created part aussi pour les comptes de retrait ajoutés dans le Dashboard, et transfer.processing une seule fois à l'approbation d'un versement retenu. Événements webhook

Components CLI Dashboard

  • Wajub.js 1.6.0 : onSuccess, onBreakdown et fetchSession() donnent les montants en unités normales (12.5 pour 12,50 EUR) ; retirez toute division par 100. onSuccess porte id, l'identifiant Wajub du paiement. Au retour du checkout hébergé, reference est cet identifiant et trxref votre référence. En ligne, Terminé et close() appellent onClose. CheckoutState gagne quatre états d'étape, chaque wrapper réexporte les types du cœur, et WajubPay.create() est obsolète. Référence de l'API
  • Wajub.js 1.6.0 : un checkout hébergé qui ne charge pas sa session ferme l'overlay ou retire le cadre en ligne juste après onLoadError, sans onClose. submit() sans bouton de paiement à presser appelle onError avec nothing_to_submit. Avec deux checkouts sur une page, chacun ne reçoit que sa propre fermeture et son propre succès. En Vue, <CheckoutEmbed> affiche son état de chargement quand show-loading est absent.
  • @wajub/svelte 1.6.0 livre ses composants en source, compilés par le Svelte 4 ou 5 de votre projet, et ils ont désormais des types de props. Un projet Svelte 5 qui impose les runes à tous les fichiers doit en exclure node_modules, comme le fait npx sv create. Svelte
  • Checkout hébergé : un payeur qui réessaie pendant que sa tentative précédente est en cours attend son issue sur un écran « paiement en cours », dans sa langue, au lieu d'une erreur en anglais. Si cette tentative se termine sans débit, le checkout revient au moyen de paiement et affiche le payer_message du refus. Le retour après un paiement échoué porte reference (l'identifiant Wajub) et trxref (votre référence). Checkout hébergé
  • Le CLI 1.7.3 complète payment.attempt_failed et dispute.deadline_approaching, et déclenche chaque canal Mobile Money avec son numéro sandbox. Une connexion ne déplace plus votre profil par défaut : une première connexion sandbox devient le profil par défaut, une connexion live jamais (wajub config use <profil>). Avec -d, une valeur à zéro initial ou de plus de 15 chiffres, et un champ nommé phone, finissant par _phone, account_number ou reference, restent du texte. wajub doctor exige Node.js 22, et wajub open balance ouvre la page des soldes. Déclencheurs
  • Dashboard : une équipe peut détenir une seconde clé publique, et en modifier ou supprimer une. Le rôle Développeur gère les prestataires, les domaines, la bascule sandbox/live et l'orchestration (règles de routage, politiques de canal, alertes), et peut lancer le simulateur de routage et prévisualiser l'impact d'une règle. Les membres qui gèrent les réglages peuvent exiger la double authentification. Un membre derrière une IP bloquée peut encore changer son mot de passe, sa double authentification et ses passkeys. L'assistant de connexion laisse décochés les canaux à activation explicite. Équipe et sécurité
  • Dashboard : se connecter avec une passkey compte comme second facteur. Fermez une seule de vos autres sessions depuis Paramètres, Sécurité. Filtrez le journal d'audit de l'équipe par membre. Une clé d'API désactivée est marquée Désactivée, et les clés restreintes ne proposent pas de scope settings. Approuver wajub login ou l'appairage d'un autre appareil demande la permission de gérer les clés d'API.
  • Dashboard : les sites autorisés à intégrer votre checkout ont leur propre page, Paramètres → Intégration de la page de paiement, sur toutes les offres, Pay as you go compris, et le rôle Développeur peut les modifier. Une fois la liste renseignée, seuls ces sites peuvent afficher votre checkout. Tant qu'elle est vide, le Dashboard vous rappelle de les déclarer : faites-le avant d'encaisser en live.
  • Dashboard : modifier Sécurité de l'équipe, créer ou modifier une clé d'API, créer, modifier, supprimer ou promouvoir un endpoint de webhook, inviter, modifier ou retirer un membre, quitter une équipe, modifier les réglages de sécurité des versements et enregistrer la liste d'intégration demandent de confirmer votre identité ; l'enregistrement de la liste d'intégration figure aussi dans le journal d'audit. Un endpoint de webhook créé sans description reçoit une erreur de validation au lieu d'une erreur serveur.
  • Konsole : les logs d'API enregistrent la version d'API de chaque requête. Explorateur de logs

SDK Plugins

  • SDK serveur Node.js et C# 2.0.0, PHP 2.0.1, Ruby 1.3.0, Python, Go et Java 1.2.1 : correctifs de sécurité dans la vérification de signature des webhooks. Mettez à jour votre SDK serveur.
  • SDK Node.js 2.0.0 : les résultats sont des objets typés là où la 1.5.0 renvoyait des enregistrements bruts, WebhookEvent porte le type dans event, et expires.in est typé. payments.initialize disparaît : appelez create. SDK Node.js
  • SDK C# 2.0.0 : Webhooks.ConstructEvent renvoie des valeurs simples (string, long ou double, bool, dictionnaires et listes) au lieu de JsonElement. Le code qui lisait des JsonElement doit passer aux valeurs simples. SDK C#
  • SDK Ruby 1.3.0 : les méthodes de taxe (rapports, codes, enregistrements, juridictions, seuils) et la liste de blocage Shield sont dans la gem, comme dans les autres SDK serveur. SDK Ruby
  • React Native 1.4.1 et Android 1.2.1, et Flutter à partir de sa prochaine version, 1.6.0 : une erreur qu'un nouvel essai ne peut pas corriger, comme une session terminée, n'est plus marquée retryable. React Native et Android annulent le paiement quand le payeur ferme l'interface avant d'avoir rien soumis, et showWajubPaymentSheet de Flutter appelle désormais onCancel. Les interfaces React Native et Flutter parlent français. React Native ouvre la page 3D Secure sur Android 11+ sans bloc <queries>, et @stripe/stripe-react-native est vraiment facultatif. SDK mobiles
  • Extension WordPress 1.2.1 : correctif de sécurité pour le contenu payant et pour l'inscription aux cours LearnDash, LifterLMS et Tutor LMS. Mettez à jour vers la 1.2.1. Les boutons des cours ne s'affichent qu'aux visiteurs connectés. WordPress
  • Extension WordPress 1.2.1 : un remboursement partiel lancé depuis WooCommerce est enregistré une seule fois. MemberPress envoie le reçu de la transaction.
  • Documentation : un callback mobile doit être un App Link ou Universal Link en https. Les pages Components documentent isOpen(), les hauteurs des champs, les types de champs et leurs propriétés, avec des exemples qui compilent.

2026-10-11

NOUVEAU API

Nouvelle version datée de l'API : 2026-10-11, avec un changement cassant : le status d'un paiement affiche refunded ou partially_refunded une fois des remboursements réussis, et GET /payments?status= filtre sur cette lecture ; un paiement remboursé n'est donc plus listé sous succeeded. Envoyez X-Wajub-Version: 2026-09-01 pour continuer à lire succeeded. Ce que dit le statut du paiement

Votre compte ne bouge pas. Tous les comptes existants sont désormais fixés sur 2026-09-01, et un nouveau compte est fixé sur la version en vigueur à sa création. Les webhooks restent mis en forme pour la dernière version, quelle que soit celle de votre compte. Gestion des versions

API Sync Shield Konsole

  • Un litige que vous acceptez ou clôturez porte désormais metadata.resolution à accepted. Litiges
  • POST /beneficiaries/{id}/verify interroge désormais l'opérateur pour tous les comptes. Hors Sync Relay, vérifiez de nouveau tout bénéficiaire vérifié avant cette version dont le nom compte pour vous. Sur vos propres bénéficiaires, la réponse est une information : l'appel répond 200 avec verification (verified, name_mismatch ou lookup_unavailable) et registered_name, le nom que détient l'opérateur, et le bénéficiaire reste payable quel que soit le résultat. Une clé sandbox obtient toujours lookup_unavailable : la sandbox n'a pas d'opérateur. Sur un compte Relay, l'appel reste une barrière et ne renvoie aucun nom. Un compte de versement ajouté dans le Dashboard ne peut plus être vérifié par cet appel. Vérifier le nom d'un portefeuille
  • Documentation : une Idempotency-Key sur POST /payments, /transfers, /transfers/batch et /refunds n'expire jamais ; seule la réponse enregistrée dure 24 heures. Une clé réutilisée pour autre chose répond 201 avec l'ancienne ressource et ne fait rien. Idempotence
  • La page Couverture marque désormais « bientôt disponible » les rails qu'aucun prestataire connectable ne porte encore : Égypte, Algérie, Maroc, Tunisie, Sierra Leone, OPay et PalmPay au Nigeria, et la crypto. Couverture
  • SDK mobiles : React Native à partir de 1.4.1 et Android à partir de 1.2.1, leurs premières versions publiées qui les apportent, et Flutter à partir de sa prochaine version, 1.6.0. Cartes sur la page sécurisée du prestataire de paiement, et portefeuilles en un geste comme Djamo. SDK mobiles
  • Shield : Toujours autoriser ce client sur un examen est ouvert à tous les plans. Une tentative bloquée par Shield figure dans votre file d'examen, et autoriser le client laisse passer son prochain paiement, sauf s'il figure dans votre liste de blocage ou correspond à une liste de sanctions. Shield, Listes affiche les clients autorisés et permet d'en retirer un. Le blocage ou le remboursement depuis un examen, les règles personnalisées et la liste de blocage restent réservés à Shield Advanced. Règles
  • Une facture récurrente produit désormais ses copies : la prochaine est due un intervalle après invoice_date, jamais dans le passé. Chaque copie est un brouillon ordinaire, généré une seule fois par cycle, qui conserve la remise globale ; elle reste à envoyer et à payer. Les dates de début et de fin du Dashboard sont maintenant appliquées. Une facture marquée récurrente auparavant reste inactive tant que sa récurrence n'est pas enregistrée de nouveau. Factures récurrentes
  • Konsole : désactiver ou réactiver un endpoint webhook depuis son formulaire prend désormais effet.
  • Konsole : le secret de signature d'un nouvel endpoint est affiché une fois à sa création, Afficher fonctionne sur la page de l'endpoint, et Passer en production crée l'endpoint live et affiche son secret une fois.
  • Konsole : la recherche dans les logs d'API retrouve un appel par son X-Request-Id, en live comme en sandbox. L'export JSON contient les enregistrements complets, et les exports des logs et des événements appliquent désormais les filtres affichés.
  • Konsole : nouveaux filtres sur l'endpoint (logs d'API), la catégorie et le statut de livraison (événements) et le prestataire retenu (journal de routage).
  • Konsole : renvoyer une livraison dont l'endpoint a déjà accepté l'événement est refusé. Sans ligne cochée, la relance groupée prend les livraisons échouées de la dernière heure, des 24 dernières heures ou des 7 derniers jours. Testeur de webhooks
  • Vue d'ensemble de Konsole : Diagnostiquer est proposé sur les cartes d'authentification, de latence et d'endpoint. « Clé d'API inutilisée » surveille vos clés d'API, et « Secret de signature de plus de 6 mois » compte depuis le dernier renouvellement.
  • Les logs d'API masquent moins de champs anodins et affichent un préfixe de clé plus long. Explorateur de logs
  • POST /beneficiaries/{id}/verify a son propre plafond sur tous les plans : 10 vérifications par minute et 200 par jour et par compte en live, 10 par minute en sandbox. Au-delà, la réponse est 429. Limites
  • Vous pouvez arrêter une facture récurrente quel que soit son statut, payée comprise : POST /invoices/{id}/stop-recurring, ou Arrêter la récurrence dans le menu d'actions de la facture. Les copies déjà générées restent. L'objet facture porte désormais next_invoice_date, la date de la prochaine copie, et recurring_parent, la facture récurrente dont une copie a été générée. Arrêter une récurrence
  • refund.updated est désormais livré, et un endpoint peut s'y abonner. Qui envoie un remboursement live
  • Un remboursement dans une devise à trois décimales comme le TND garde toutes ses décimales : un remboursement complet ou un litige accepté aboutit. Dans une devise sans subdivision comme le XAF, la part des frais et payer_amount sont des nombres entiers. Qui supporte les frais
  • Avec X-Sync, une plateforme ne voit que les clients que sa connexion a créés ou utilisés. Un paiement est créé sans aucun autre client, et leur identifiant cus_ est traité comme inconnu. DELETE /customers/{id} répond 403 : effacer un client est une décision du marchand. Types de compte
  • DELETE /customers/{id} retire désormais aussi les coordonnées du client des factures, des adresses d'un paiement, des événements enregistrés et des livraisons de webhook, et des copies reçues par une plateforme Sync. Supprimer un payeur
  • POST /events/{id}/resend livre de nouveau aux endpoints qui n'ont pas accepté l'événement.
  • Avec X-Sync, une Idempotency-Key appartient à la connexion, et accepter ou clore un litige est refusé une fois les paiements de la connexion suspendus.
  • POST /beneficiaries/{id}/verify rend payable un bénéficiaire resté non vérifié quand les noms correspondent. Vérifier le nom d'un portefeuille
  • Un paiement envoyé en examen parce que le nom du payeur est proche d'une liste de sanctions apparaît dans Shield, Examens même quand Shield est désactivé. Score de risque
  • Une copie récurrente générée reste un brouillon tant que vous ne l'envoyez pas, même après son échéance ; une copie passée overdue sans avoir été envoyée redevient un brouillon. Une série désactivée puis réactivée reprend après sa dernière copie, l'annulation efface next_invoice_date, et un devis, une estimation ou une copie générée ne peut pas devenir récurrent (422). Dupliquer une facture récurrente donne un simple brouillon. Factures récurrentes
  • Konsole : Renouveler sur la page d'un endpoint remplace son secret de signature, après votre mot de passe, et affiche le nouveau une seule fois. Testeur de webhooks
  • Les webhooks sont toujours mis en forme pour la version actuelle de l'API, quelle que soit la version de l'appel qui les déclenche.

API Paiements Factures Sync Dashboard

  • POST /payments/{id} renvoie désormais ce dont l'étape suivante du payeur a besoin : un 202 qui nomme une étape dans action porte action_url, otp_id et otp_masked_contact, les identifiants pin, phone, birthday et address, et client_session. Quand action est renseigné
  • Wave (ci.wave, sn.wave), Express Union (cm.eu) et M-Pesa (ke.mpesa, tz.mpesa, mz.mpesa) peuvent être débités en live. Wave et Express Union acceptent tout numéro. M-Pesa accepte un numéro Safaricom au Kenya et un numéro Vodacom en Tanzanie et au Mozambique, et mobile ou un agrégat de pays envoie un tel numéro sur M-Pesa. Les autres canaux n'acceptent qu'un numéro de leur propre opérateur. Laisser Wajub trouver l'opérateur
  • Un paiement créé avec accept peut être débité sur mobile ou sur un agrégat de pays comme cm.mobile. La restriction est vérifiée sur l'opérateur que donne le numéro, et un numéro qui sort de ce que le paiement accepte est refusé. Choisir ce qu'un paiement accepte
  • Une page numérotée d'une liste porte désormais next_cursor et has_more dans meta, à côté des compteurs de pages. Envoyez ce next_cursor comme cursor et le parcours continue juste après le dernier élément de la page. Sur toutes les listes qui acceptent un curseur ; GET /invoices et GET /links triés avec sort_by restent paginés par numéro. Avec le SDK PHP, getNextPage() et autoPagingIterator() suivent ce curseur à partir de la deuxième page : mêmes éléments, mais le meta de ces pages n'a plus current_page, last_page ni total. Pagination
  • Un fichier joint à un message de litige avec POST /disputes/{uid}/messages est désormais enregistré. Envoyer un message
  • Une facture sans customer_email ni customer_id peut maintenant être payée : sa page demande un e-mail au payeur, utilisé pour le paiement et sa confirmation. Sur cette page, l'e-mail que vous avez mis sur la facture est toujours conservé. Démarrage rapide des factures
  • Un paiement en ligne sur une facture s'ajoute à ce que vous avez enregistré avec mark-paid. Enregistrer un paiement encaissé ailleurs
  • Sync : un sous-compte accepté n'affiche jamais expired. expires_at est la date de l'invitation ; elle est effacée quand le marchand accepte, y compris sur les connexions déjà acceptées, et les paiements d'une connexion acceptée passent. Le Dashboard redemande l'accord du marchand avant un changement de tarif. Onboarding
  • Sync : chaque événement account.* envoyé par l'API désigne sa connexion dans data.account, l'identifiant acc_…. account.deauthorized, account.payment_activated et account.payment_suspended gagnent cette clé ; data.id n'est pas toujours la connexion. Événements webhook
  • Clés API, Dashboard : la date d'expiration d'une clé se fixe à la création, se change ou se retire sur une clé privée ou restreinte, et s'affiche à côté de la clé. Modifier autre chose la conserve. La liste d'IP autorisées accepte les adresses IPv4 et IPv6 et les plages CIDR des deux familles, à la création comme à la modification, et une entrée IPv6 correspond quelle que soit son écriture. Environnements et clés
  • Orchestration : l'assistant de connexion d'un fournisseur pré-remplit la priorité 0, la valeur documentée, au lieu de 50. Les connexions existantes gardent leur priorité. Fournisseurs
  • Playground de la documentation : Tester cet endpoint fonctionne une fois connecté, en sandbox uniquement. Référence de l'API
  • Documentation : le callback d'une connexion Sync est la page sur laquelle le marchand revient, pas l'adresse des événements. Ceux-ci vont à vos endpoints de webhook, et account.connected demande un abonnement par son nom. Capacités des comptes
  • Documentation : la référence de POST /beneficiaries exige channel et name et n'a pas de type ; POST /transfers décrit le beneficiary en ligne (name et channel obligatoires, pas de bank_code) et précise que reference n'est jamais contrôlée pour l'unicité, seule Idempotency-Key protège une relance ; le complete d'un transfert n'est true que sur succeeded ; l'objet Event liste event, created, livemode, pending_webhooks, api_version et request. Transferts, Événements
  • Documentation : le démarrage rapide Tax utilise maintenant inclusive: true, car il débite le total calculé. Avec inclusive: false, un paiement de 11 925 XAF enregistrait 2 296 XAF de taxe au lieu de 1 925. Si vous avez suivi l'ancienne version, passez inclusive à true ; les enregistrements passés ne sont pas recalculés. Démarrage rapide Tax
  • Documentation : le conseil de garder cinq à dix appels simultanés est remplacé par un débit par minute sous le plafond de chaque ressource pour votre plan (24 appels par minute sur /payments en Pay as you go, où le plafond est de 30), avec un exemple qui attend le Retry-After. Performances
  • Documentation : dans le démarrage rapide Payment Links, les champs supplémentaires se décrivent avec name et type, et non key. Le premier exemple de la page d'accueil des Components envoie email ; sans contact du payeur, l'API répond 422. Le cookbook marketplace Django crée la connexion avec withdrawals, enregistre le payout_phone qu'utilise son exemple de retrait et lit la connexion dans data.account. Démarrage rapide Payment Links, Marketplace Django

Components SDK CLI Plugins

  • Wajub.js 1.6.0 : la locale passée à mount(), open(), checkout() ou components() est désormais la langue d'ouverture du checkout ou du champ. Checkout hébergé
  • Wajub.js 1.6.0 : un checkout hébergé dont la session ne se charge pas appelle onLoadError avec session_not_found ou session_terminal_expired. Il appelait onError : déplacez ce traitement dans onLoadError. Référence de l'API
  • Wajub.js 1.6.0 : checkout.submit() appuie sur le bouton de paiement du moyen en cours. unmount() retire le checkout hébergé en conservant l'instance, mount() le remet, en ligne et en superposition. Référence de l'API
  • @wajub/vue et @wajub/svelte 1.6.0 : useWajubOptional() renvoie une ref (Vue) ou un store (Svelte) qui suit le chargement du runtime. Lisez runtime.value ou $runtime. @wajub/svelte fonctionne dès le premier rendu, avec Svelte 4 comme Svelte 5. Vue, Svelte
  • SDK PHP 2.0.1 : create(), retrieve() et update() sur transfers, beneficiaries, links, invoices, accounts et webhookEndpoints ne lèvent plus Cannot instantiate abstract class après l'envoi de la requête. Si un transfers->create() a échoué ainsi en 2.0.0, le transfert a bien été créé : vérifiez avant de le renvoyer. SDK PHP
  • SDK Python 1.2.1 : le package sur PyPI contient de nouveau le module. Les versions 1.1.0 et 1.1.1 installaient un wheel vide. Installez avec pip install "wajub>=1.2.1". SDK Python
  • SDK Ruby 1.3.0 : customers.delete_tax_id appelle DELETE /customers/{id}/tax_ids/{tax_id}. SDK Ruby
  • payments.initialize, alias de create, n'existe plus dans les SDK Node.js et C# (2.0.0), ni dans Python, Go et Java (1.2.1) et Ruby (1.3.0). PHP le conserve. Appelez create. SDK
  • Les exemples SDK des pages transferts, solde, bénéficiaires, liens de paiement, factures et litiges correspondent aux signatures réelles de chaque SDK. La preuve de litige avec fichier est présentée comme une requête multipart.
  • CLI 1.7.2 : wajub trigger --channel paie avec un numéro sandbox de l'opérateur du canal, --channel ci.orange compris. Déclencheurs
  • Plugin WordPress 1.2.1 : un client qui revient de la page de paiement trouve sa commande dans l'état de son paiement (WooCommerce, GiveWP) ; les remboursements lancés depuis WordPress sont acceptés ; un remboursement fait dans le Dashboard arrive dans WooCommerce ; [wajub_pay_content] se débloque. WordPress

2026-10-10

API Orchestration Sync Tax Shield Webhooks Components CLI

  • Les appels Sync et Tax demandent le produit dans votre plan ou en option : sans lui, /accounts, tout appel portant X-Sync et /tax répondent 403 avec error_code: feature_not_in_plan. Sync · Tax
  • Un endpoint webhook live doit utiliser https:// : en créer un en http://, ou en pointer un vers une URL http://, répond 422. Les endpoints sandbox acceptent toujours http://. Les endpoints live déjà en http:// conservent leurs livraisons, et Konsole les signale. Webhooks
  • customer_id sur POST et PUT /invoices attend l'identifiant cus_ du client. Factures
  • PUT /accounts/{id} répond 409 avec error_code: merchant_not_verified quand il passe payment_status à active pour un marchand dont la vérification n'est pas approuvée. Onboarding
  • Avec X-Sync, une plateforme n'atteint que ce que la connexion a apporté. Les litiges sont ceux de ses paiements ; les liens, factures et bénéficiaires sont ceux qu'elle a créés, et un versement ne va qu'à l'un de ces bénéficiaires ; GET /events liste les événements de tout cela, et POST /events/{id}/resend envoie à vos propres endpoints. Le reste répond 404. /balance, /webhooks, /shield et /tax répondent 403 avec X-Sync. Un paiement sur un lien ou une facture de la connexion porte la connexion, et il est refusé dès que la connexion ne peut plus encaisser. write, settings, subscriptions et analytics ne sont plus des capacités : en demander une répond 422. Types de comptes
  • DELETE /customers/{id} anonymise et supprime le client. customer.deleted porte la fiche anonymisée et n'est plus suivi de customer.updated. Les coordonnées du client sont retirées des événements déjà enregistrés et un appel répété répond 200 au lieu de 404. Supprimer un payeur
  • Sur un débit fait avec une clé secrète depuis votre propre checkout, appelez Wajub.signals() (Wajub.js 1.6.0) dans le navigateur du payeur et transmettez le résultat tel quel dans data._client. Si vous utilisez votre propre checkout
  • Un payeur dont le nom est proche d'un nom sous sanctions, sans l'être, part désormais en revue quel que soit le score. Vous pouvez choisir de le refuser, avec sanctions_near_match_action sur PUT /shield/settings ou dans Shield, Risk controls. Une correspondance exacte reste toujours refusée. Notation du risque
  • Un paiement passe désormais à votre prestataire suivant quand le premier répond que le chemin est en panne : l'opérateur a dépassé son délai ou est indisponible, vos identifiants sont refusés, ou ses fonds de roulement sont épuisés. Un refus qui concerne le payeur s'arrête toujours là. Ce qui arrête la cascade
  • Un remboursement live dit qui l'envoie : execution_mode (automatic, merchant ou manual) et, quand il n'est pas envoyé automatiquement, manual_reason avec un code stable et un message. refund.updated part quand l'un des deux change. Un remboursement encore processing compte dans ce qui reste à rembourser. Qui envoie un remboursement live
  • Vous choisissez qui supporte les frais Wajub d'un paiement quand vous le remboursez : fees_bearer sur POST /refunds et dans le formulaire de remboursement du Dashboard, avec une valeur par défaut dans Paramètres, Remboursements. merchant rend au client tout ce qu'il a payé pour la part remboursée, customer lui laisse la part des frais. Le remboursement porte fee_amount et payer_amount, et votre solde est débité de payer_amount. Rien ne change tant que vous ne le réglez pas : les frais restent à celui qui les a payés. Qui supporte les frais
  • Un paiement créé avec bearer à customer ne vous coûte pas de frais : ils sont pris une fois, chez le payeur, et aucun fee.charged n'est émis pour ce paiement. La sandbox fait de même. Qui paie les frais
  • Accepter ou clore un litige par l'API rembourse désormais le payeur : POST /disputes/{id}/accept et /close créent un remboursement du montant contesté avec le motif customer_complaint. Ce remboursement ne vous débite pas une seconde fois. Une rétrofacturation, que la banque du payeur a déjà remboursée, n'est pas remboursée en plus, ni par l'API ni par le Dashboard. dispute_settlement est une clé réservée dans le metadata d'un remboursement. Concéder
  • Wajub Components : fetchSession() fonctionne depuis le site de n'importe quel marchand. Sessions
  • Importer wajub.mjs depuis js.wajub.com comme module fonctionne. Wajub.js
  • CLI 1.7.1 : wajub logout retire aussi la clé de config.json.bak. Supprimez tout config.json.bak laissé par une version antérieure. Déconnexion

2026-10-09

NEW Payments Components

  • deferred: true sur POST /payments prépare un paiement pour des champs de paiement affichés avant que la commande existe : pas de transaction, pas de payment.created et aucune ligne dans vos paiements avant que POST /payments/{id}/activate le crée avec le total final et le client. Avant que la commande existe
  • PATCH /payments/{id} modifie le montant et la devise d'un paiement préparé tant que le checkout est ouvert, sans remonter les champs. Modifier un paiement préparé
  • Wajub Components : variant: 'fields' intègre les champs d'un composant dans votre propre bloc de moyen de paiement, et fields.country et fields.operator: 'detect' retirent les listes de pays et d'opérateurs du Mobile Money. Également onBeforeSubmit, fields.customer: 'external', et les composants bankTransfer et crypto. L'environnement d'exécution servi depuis js.wajub.com les lit, @wajub/js 1.5.0 ajoute leurs types, et @wajub/vue et @wajub/svelte 1.5.1 transmettent variant. Dans votre propre bloc de moyen de paiement

Orchestration

  • Le routeur applique d'abord l'instruction la plus précise : les connexions désignées par vos règles de routage correspondantes, chacune suivie du secours de la règle, puis la politique du canal, ou la priority de la connexion sur un canal sans politique. Orchestration des paiements
  • Les règles de routage appliquent désormais leur poids et leurs conditions avancées : fenêtres horaires, segments clients, filtres de métadonnées et plafonds de fréquence. Une règle supprimée ne route jamais. Un filtre de métadonnées in prend des valeurs séparées par des virgules, et eq et in comparent le texte des valeurs : 100 saisi dans le Dashboard correspond à une valeur numérique. Règles de routage
  • Les frais fixes d'une connexion sont convertis de votre devise de base dans la devise du paiement avant que le routeur compare les coûts.
  • L'ordre de cascade, l'objectif et les garde-fous d'une politique de canal ordonnent les connexions qu'aucune règle n'a placées. Un garde-fou recule une connexion, il ne refuse jamais un paiement.
  • Le simulateur de routage de la page Règles de routage exécute le vrai routeur, à blanc.
  • Une carte saisie dans les champs propres à un prestataire n'est débitée que par ce prestataire, et ne bascule jamais. Un refus Stripe est définitif et renvoie le code de refus de Stripe.
  • Une connexion sans identifiants est ignorée : la suivante est essayée. Une clé manquante ou refusée est signalée sur la connexion, et votre équipe en est avertie par e-mail. Cascade et repli

2026-10-03

CLI

  • CLI 1.7.0 : wajub completion remplace wajub autocomplete. Lancez wajub completion install une fois ; wajub autocomplete reste un alias, et un shell configuré par lui continue de compléter après la mise à jour. La complétion couvre désormais les valeurs (statuts, types d'événements, chemins d'API, profils), fish et le bash fourni avec macOS. CLI
  • CLI 1.6.1 : la première version du nouveau wajub listen ; la 1.6.0 n'a pas été publiée.

2026-10-02

CLI

  • CLI 1.6.0 : wajub listen remet à votre handler chaque livraison exactement comme la production l'envoie. Le CLI 1.5.0 et les versions antérieures ne peuvent plus écouter : leur wajub listen s'arrête et demande une mise à jour (npm install -g @wajub/cli@latest). Toutes les autres commandes des anciennes versions continuent de fonctionner. Listen
  • CLI 1.5.0 : les Agent Skills sont copiées dans ~/.agents/skills et ~/.claude/skills à la première commande après une installation ou une mise à jour, sans wajub login. Désactivez-le avec WAJUB_NO_SKILLS=1.

2026-09-19

API Payments

  • La limite de requêtes est désormais le plafond par minute de votre plan, partagé par toutes vos clés, avec une part plus petite pour les paiements, les payouts et quelques autres routes, et aucun plafond sur Enterprise. Les écritures de payout (création de bénéficiaires, de transferts et de lots) sont plafonnées à 20 par minute sur tous les plans, Enterprise compris. Limites de requêtes
  • Une rétrofacturation ouverte chez un prestataire vous parvient désormais sous forme de litige, avec son échéance dans due_date.

2026-09-17

NOUVEAU Payments Transfers Sync

  • En live, les données de carte brutes envoyées à POST /payments/{id} sont refusées.
  • Créances : POST /beneficiaries/{id}/receivables enregistre ce qu'un vendeur déjà payé vous doit, et une ligne de payout groupé peut le reprendre en premier. Nouveaux événements beneficiary.receivable_recorded et beneficiary.receivable_recovered.
  • Payouts vers un compte Wajub.
  • Sync : account.change_requested quand PUT /accounts/{id} propose de nouvelles conditions, et account.commission_receivable_recorded et account.commission_receivable_collected pour une commission qui n'a pas pu être prélevée à la source.

2026-09-16

NOUVEAU Transfers Sync

  • POST /transfers/batch : jusqu'à 500 payouts en un appel, avec une Idempotency-Key obligatoire.
  • Les comptes Sync reçoivent un mode, Lite, Direct ou Relay, et POST /accounts/{id}/payouts paie un marchand Lite, en live uniquement.
  • Les webhooks d'onboarding envoyés à une plateforme Sync s'appellent désormais account.onboarding_started, account.onboarding_email_verified, account.onboarding_account_selected, account.onboarding_kyc_submitted et account.connected, et on peut s'y abonner. Catalogue des événements

2026-09-15

Webhooks API Transfers

  • Nouvelles tentatives des webhooks : toute livraison en échec, sauf un 410, est retentée pendant 72 heures au plus, un 4xx compris. Nouvelles tentatives
  • Idempotence : la réponse enregistrée est renvoyée avec Idempotent-Replayed: true, une seconde requête arrivée pendant que la première s'exécute reçoit un 409, et la même clé avec un autre corps reçoit un 422. Idempotence
  • Payouts par virement bancaire.

SDK

  • SDK PHP 2.0.0, avec des changements cassants : il demande PHP 8.4 ; update() et delete() sont retirés de refunds et transfers, que l'API n'a jamais eus ; tax->reports() renvoie l'objet rapport et shield->addToBlocklist() la liste de blocage mise à jour. La pagination par curseur est suivie par getNextPage() et autoPagingIterator(). SDK PHP

2026-09-11

Payments Transfers CLI

  • Portefeuilles Djamo, pour les paiements et pour les bénéficiaires.
  • wajub logout révoque la clé créée par wajub login.

2026-09-07

Transfers

  • Ajout du canal sn.wave pour les transferts au Sénégal.

2026-09-01

NOUVEAU API

Nouvelle version datée de l'API : 2026-09-01, avec un changement cassant : ledger_balance_before et ledger_balance_after sont retirés de l'objet transfert. Envoyez X-Wajub-Version: 2026-08-01 pour les conserver. Gestion des versions

Que pensez-vous de ce contenu ?