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-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. Un changement limité à l'un de ces champs renvoyait le paiement d'origine, sans le changement. Pour une clé privée ou restreinte, un paiement créé avant le 2026-10-14 est encore comparé sur les champs listés alors. 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 : il créait un paiement déjà expiré. 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. Il n'affichait que cette ligne.

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. La vérification dure 30 minutes.
  • 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 : chaque package passe en 1.8.1, @wajub/js, @wajub/react, @wajub/vue et @wajub/svelte sans autre changement, et @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 l'environnement d'exécution une seule fois, dans le navigateur uniquement. 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. Ils se comportent comme les packages React, Vue et Svelte : le chargeur skeleton par défaut, la hauteur estimée du formulaire tenue dès le rendu serveur, la même à l'hydratation, et appearance, locale, layout et frameTitle envoyés sur place, seulement quand leur contenu change. 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. Angular
  • Wajub.js 1.8.0 : loader: 'skeleton' garde votre page immobile pendant le chargement d'un champ de paiement. Le conteneur tient la hauteur du formulaire dès mount(), avec un squelette dessiné dans le style de vos champs, et le formulaire apparaît en fondu une fois prêt. Un champ rechargé sur la page prend la hauteur que son type avait au repos, mesurée sur un vrai formulaire seulement, jamais sur un message affiché à sa place. La place n'est jamais inférieure au min-height propre du conteneur, et sans readyTimeout le squelette laisse place à l'iframe au bout de 15 secondes, sans erreur. componentReserveHeight(type, variant, fields), sur wajub et en export synchrone de @wajub/js, donne cette hauteur, une hauteur apprise sur la page une fois l'environnement d'exécution chargé. componentEstimatedHeight(type, variant, fields), de @wajub/js, donne l'estimation seule, la même 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 qui suit le départ de la page chez le prestataire : un payeur qui validait sur son téléphone après plus d'une minute recevait confirmation_timeout alors que le paiement aboutissait. Pendant ce temps, une iframe retirée 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, alors qu'il ne faisait rien. Sur mount() et open(), un nouveau preset theme remplace le précédent et ce qu'il apportait, alors que les couleurs de night restaient sous flat, et une apparence qui n'a plus aucune clé arrive vide au checkout, alors qu'elle partait à null et était ignorée. update({ layout }) redispose les moyens d'un checkout intégré, en ligne comme dans la superposition, alors qu'il était seulement enregistré. 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 envoie appearance, theme, locale et layout par update(), alors qu'il les lisait une seule fois, 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 conteneur tient dès le premier rendu la place que le SDK réservera, l'estimation de componentEstimatedHeight() au rendu serveur et à l'hydratation, puis laisse le SDK tenir la place et finit à la hauteur du formulaire, si bien que minHeight={0} n'est plus nécessaire avec variant="fields". Un minHeight que vous passez est gardé, et avec loader="none" chaque type garde sa propre hauteur. Un nouveau variant, fields, loader, readyTimeout, collectAddress, addressMode ou collectName monte un nouveau champ dans le même conteneur, alors que seuls sessionId et type le faisaient, et que Svelte ne remontait jamais. appearance, locale, layout et frameTitle passent par update() seulement quand leur contenu change. Les trois premiers partaient ensemble à chaque changement, un objet écrit en ligne comptant pour un changement à chaque rendu, et frameTitle était lu une seule fois. La prop appearance est envoyée entière : une clé que vous en retirez est effacée. Les gestionnaires sont toujours les derniers passés, et en changer ne recharge jamais le formulaire. Svelte monte un champ une seule fois au départ, alors qu'il le montait deux fois, et Vue remet l'environnement d'exécution et l'instance tels que le SDK les crée, pas en proxys réactifs. Avec un framework
  • Le checkout livré avec Wajub.js 1.8.0, quelle que soit la version chargée par votre page : un champ de paiement dont la session est déjà terminée affiche son message à la hauteur du 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. Ni l'un ni l'autre n'envoyait rien : un squelette skeleton restait affiché, et le message était coupé à la hauteur du squelette. Pour ce qu'envoie Wajub.js 1.8.0, le checkout intégré applique update({ layout }), et une apparence vide ramène un champ ou un checkout à l'image de marque de votre Dashboard Wajub, alors qu'il gardait la précédente. Quand le formulaire n'arrive pas
  • Wajub.js 1.7.2 : avec variant: 'fields', l'iframe d'un composant prend la hauteur de ses champs, sans minimum de 120px, qui laissait une bande vide sous un champ de numéro de téléphone. Les composants de champs React, Vue et Svelte gardent leur propre minHeight : passez 0. Le SDK écarte les valeurs de rules que le checkout refusait déjà, comme ;, {, \, image-set( ou une valeur de plus de 256 caractères. Dans votre propre bloc de moyen de paiement
  • Le checkout livré avec Wajub.js 1.7.2, quelle que soit la version chargée par votre page : update({ appearance }) sur un checkout intégré tient, alors que la saisie ou l'étape suivante du payeur remettait l'apparence donnée au montage. 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, dans les champs de carte que le checkout dessine lui-même aussi, et la color d'une règle .Label atteint le libellé du titulaire de la carte avec Adyen. Une police Google Fonts que le checkout charge atteint les champs de carte Stripe, et sans fontSizeBase les champs font 16px sur téléphone ou tablette, où iOS zoomait 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, comme l'envoient d'anciennes intégrations dont le plugin WordPress, est lu comme colorScheme, system valant auto, quand vous ne donnez pas de colorScheme. Il était ignoré. Les préréglages stripe, night, flat et none ne changent pas. Préréglages
  • Le checkout livré avec Wajub.js 1.7.1, quelle que soit la version chargée par votre page : 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 plus que les champs, alors qu'ils modifiaient tous les arrière-plans et toutes les bordures. Les rules .Input et .Label atteignent les champs, alors qu'elles restaient sans effet, et une valeur qui pourrait charger une ressource ou sortir de sa déclaration, comme url( ou ;, est refusée par tous les chemins, update({ appearance }) compris. Règles
  • Le même checkout : ready part une fois le formulaire du composant affiché, ou aussitôt quand il n'a aucun formulaire à afficher. Il partait dès le chargement de la session, avant le formulaire. 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 tel canal était un choix unique, fait à la place du payeur. Un portefeuille utilisable avec n'importe quel réseau, comme Wave, Express Union ou Djamo, accepte n'importe quel numéro : Wave était refusé avec un numéro Orange Money. 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
  • DELETE /keys/current révoque toute clé créée par un appairage (wajub login, la connexion d'une application), plus seulement une clé de wajub login. Toute autre clé reçoit toujours 409.

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 (il vaut de 15 à 30 minutes). Tout autre membre apprend qu'un administrateur ou un développeur doit approuver, et le support Wajub connecté à votre compte ne peut ni approuver ni refuser. 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. Une clé approuvée doit être récupérée dans les 15 minutes, sinon elle n'est jamais remise et elle est supprimée. Le propriétaire et chaque Administrator reçoivent un e-mail pour chaque clé créée par un appairage.
  • Settings → Developer → API Keys 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é. Ces actions demandaient votre mot de passe, ou rien, puis étaient refusées. Un mot de passe confirmé n'ouvre aucune de ces actions : c'est le code qui les ouvre, pendant 15 à 30 minutes. É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. L'iframe s'appelait toujours Wajub <type> component.
  • Wajub.js 1.7.0 : quand le paiement se poursuit sur la page du prestataire, PayPal, Mollie ou un paiement crypto par exemple, le composant émet redirect avec { url, method } et Wajub.js y emmène votre page. L'iframe y allait elle-même, et les prestataires refusent d'y être affichés. Un prestataire qui prend tout l'onglet, comme Mollie, PayPal, Djamo, Adyen ou Paddle, ramène le payeur sur la page Wajub de la session, dans la langue du composant, qui affiche le résultat puis envoie le payeur sur le callback du paiement avec status, reference et trxref, d'elle-même après un succès et au choix du payeur après un échec, ou garde le résultat affiché quand il n'y a pas de callback. La page du prestataire ouverte dans un nouvel onglet depuis un paiement en attente ramène le payeur de la même façon. 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
  • Le checkout livré avec Wajub.js 1.7.0, quelle que soit la version chargée par votre page : un envoi demandé avec submit() ou confirmPayment() qu'un composant refuse, quel que soit son formulaire, comme un numéro Mobile Money vide ou invalide, une carte laissée incomplète chez n'importe quel prestataire, des champs de carte encore en chargement, un virement sans IBAN ni numéro de compte, un paiement crypto sans actif ou un numéro de carte rejeté par son prestataire, émet error avec submission_failed et un message pour le payeur, et confirmPayment() rejette avec cette erreur. Un formulaire qui n'était pas prêt ne disait rien auparavant, sauf quand l'e-mail manquait. 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, quel que soit le moyen : 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, alors qu'ils étaient coupés à la hauteur du formulaire, 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. Un paiement en plusieurs fois encore ouvert est repris quand c'est possible, ou clôturé en gardant ce qu'il a encaissé, et 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, qui valait XAF pour tous les canaux.
  • 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

  • La sandbox ne fractionne plus d'elle-même un débit Mobile Money au-dessus du plafond par transaction : elle répond 422, comme le 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, qui était ramené dans les bornes, 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 (il répondait 500) ;
    • GET /links : un type inconnu ; GET /events : un type qu'aucun endpoint ne reçoit (les deux renvoyaient une liste vide) ;
    • 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, si bien que type=CRYPTO liste les cryptomonnaies là où il listait les devises classiques.

    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 le compteur d'écritures de versement. 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 et /health/ready renvoient 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, et non « safe to retry ». 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 qui attend plus de 10 secondes répond 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 (Settings → Regional → Language), 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 pendant que Wajub le mène à terme autrement, 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 refusé par le prestataire que Wajub n'a pas pu mener à terme autrement 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 : tax vaut null dans la session. 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
  • Des refus répétés sur un même BIN de carte chez vous comptent désormais dans le score de risque.
  • 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. Un litige accepté dans le Dashboard pèse sur la réputation du payeur comme un litige accepté par l'API. API Shield

Orchestration

  • Une route qui échoue sans cesse est mise en pause quelques minutes, puis essayée de nouveau ; une route qui échoue encore reste en pause plus longtemps. Bascule en cascade
  • 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. Un rail Wajub approuvé démarre à la priorité 0, comme toute autre connexion. 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 (au moins 90 s), les sessions client et les confirmations qui ne basculent jamais, 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. Chaque checkout n'écoute que sa propre iframe : 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. wajub listen --events ne propose plus payment.checkout_page_opened, payment.redirected_to_callback ni link.expired, qu'aucun endpoint ne reçoit. 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 Settings, Security. 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, Settings → Checkout embedding, 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 Team security, 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

  • Les SDK serveur relancent le 409 envoyé par l'API quand une requête avec la même Idempotency-Key est encore en cours, et renvoient le résultat de la première : Node.js et C# 2.0.0, PHP 2.0.1, Ruby 1.3.0, Python, Go et Java 1.2.1. Go garde la même Idempotency-Key d'une tentative à l'autre. Idempotence
  • SDK serveur, mêmes versions : 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, Android 1.2.1 et Flutter 1.5.0 : 401, 404 et une session terminée (410) ne sont pas réessayables, et une erreur serveur (5xx) est une erreur d'API. React Native et Android annulent le paiement quand le payeur ferme l'interface avant d'avoir rien soumis, comme Flutter, dont showWajubPaymentSheet 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. watchStatus() de Flutter suit l'identifiant Wajub du paiement et continue le polling pendant toute la surveillance. 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. Chaque intégration lit le retour du payeur par l'identifiant Wajub du paiement, et une commande antérieure à 1.2.1 retrouve son paiement par la référence envoyée par l'extension. 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. L'ancienne adresse de webhook répond 403 à une livraison qu'elle refuse.
  • 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. Jusqu'ici un compte ne portait aucune version et suivait celle de la plateforme : une nouvelle version l'aurait atteint le jour de sa sortie. 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 pèse moins sur la réputation du payeur qu'un litige tranché contre vous. Le litige porte désormais metadata.resolution à accepted. Score de risque
  • POST /beneficiaries/{id}/verify interroge désormais l'opérateur pour tous les comptes. Hors Sync Relay, les vérifications faites avant cette version n'atteignaient pas l'opérateur : vérifiez de nouveau tout bénéficiaire 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 : Flutter et React Native 1.4.0, Android 1.2.0. Cartes par un prestataire qui les collecte sur sa propre page (Paystack, Flutterwave, PayPal, Kkiapay, FedaPay, CinetPay) et portefeuilles en un geste comme Djamo. Un paiement Mobile Money revient comme une action à approuver, push_approval. SDK mobiles
  • Shield : Always allow customer 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, lists 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, Reveal fonctionne sur la page de l'endpoint, et Promote to Live 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é et n'est pas décompté de vos Répétitions de webhooks par mois. 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 : Diagnose 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
  • Konsole ne propose plus payment.checkout_page_opened et payment.redirected_to_callback pour un endpoint webhook : ils ne sont jamais livrés. Un endpoint qui en liste un le garde, sans effet. Événements webhook
  • 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 corps des livraisons de webhook (et de leurs relances), des copies reçues par une plateforme Sync, des statistiques et de la recherche. Un appel répété termine un effacement qu'un appel précédent a laissé inachevé. 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.
  • Une règle personnalisée sur ip_country ne lit qu'une adresse du payeur vérifiée. Si vous utilisez votre propre checkout
  • Relancer un lot de payouts avec la même Idempotency-Key renvoie les lignes déjà parties, même quand l'heure n'a plus de place. Limites
  • 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, Reviews 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 : Rotate 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. crypto.deposit est un champ de la sandbox. 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.
  • SDK React Native 1.4.1 : watchStatus() renvoie le statut quand le temps réel est activé, et le polling tourne pendant tout le suivi. SDK Android 1.2.1 : watchStatus() ouvre la connexion temps réel et garde le polling à côté. SDK mobiles
  • 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, /tax et /listen 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 ; si une partie échoue, il répond 500 et ne change rien. 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, un appel répété répond 200 au lieu de 404, et la copie archivée est supprimée après 120 jours. Supprimer un payeur
  • La vélocité horaire des payouts ne compte que les payouts acceptés : un payout refusé, faute de fonds ou par le plafond lui-même, n'occupe aucune des six places, et le réessayer ne prolonge pas l'attente. Un lot occupe une seule place quel que soit son nombre de lignes ; chaque ligne ajoute tout de même son montant au montant horaire. Limites
  • Sur un débit fait avec une clé secrète, faites noter l'IP du payeur : appelez Wajub.signals() (Wajub.js 1.6.0) dans le navigateur du payeur et transmettez le résultat dans data._client. Son token atteste l'adresse du payeur. 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 Settings, Refunds. 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
  • js.wajub.com envoie désormais Access-Control-Allow-Origin: * : importer wajub.mjs 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 publiée avec les sessions d'écoute (la 1.6.0 n'a jamais atteint npm).

2026-10-02

CLI

  • CLI 1.6.0 : wajub listen passe par des sessions d'écoute, et votre handler reçoit 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, sauf pour les écritures de payout (création de bénéficiaires, de transferts et de lots), plafonnées à 20 par minute sur tous les plans. 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 avec une attente progressive, pendant 72 heures au plus. Auparavant, il y avait cinq tentatives sur environ seize minutes, et un 4xx n'était jamais retenté. 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, shield->addToBlocklist() la liste de blocage mise à jour, et listen->config() et listen->auth() déballent leur enveloppe. 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.
  • DELETE /keys/current révoque la clé créée par wajub login. wajub logout l'appelle.

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

L'API a accepté cette version à partir du 10 septembre : avant cette date, X-Wajub-Version: 2026-09-01 répondait 400.

Que pensez-vous de ce contenu ?