Dépannage de Wajub Components
Le symptôme, sa cause et la ligne qui le corrige.
Presque tous les problèmes de Wajub Components proviennent de quatre causes : un jeton qui n'est plus valide, une page qui a chargé le SDK sur le serveur, un callback non configuré ou une clé de configuration ignorée silencieusement par le SDK. Commencez ici avant de lire le code.
Rien ne s'affiche
| Symptôme | Cause | Correction |
|---|---|---|
| Conteneur vide sans erreur | Jeton inconnu, ou jeton qui n'est plus valide parce que son paiement est terminé | Configurez onLoadError. Il contient session_not_found ou session_terminal_expired. À partir de Wajub.js 1.6.0, le checkout quitte la page juste après, sans onClose |
Intégration embed incorrecte (Embed configuration error en anglais) | URL de checkout collée manuellement dans une iframe | Appelez mount(), open() ou CheckoutEmbed |
| Aucune action ni requête réseau | mount() s'est exécuté sur le serveur | Importez depuis @wajub/js/pure ou marquez le fichier avec 'use client' |
Error lors de l'appel | Aucun sessionId ou sélecteur sans correspondance | Avant toute requête. window.wajub la lève de façon synchrone ; les helpers de @wajub/js (mount(), open()…) sont asynchrones et renvoient plutôt une promesse rejetée : attendez-les avec await dans un try |
| L'iframe n'apparaît jamais | load_error dans onLoadError | L'origine du checkout est inaccessible. Vérifiez l'onglet réseau et les règles de contenu |
| Un cadre vide sur un site, normal sur un autre, sans aucun callback | Settings → Checkout embedding ne contient pas l'origine de cette page | Ajoutez https:// suivi du domaine, port compris s'il y en a un. Où le checkout peut être intégré |
| La console signale une violation de Content Security Policy | La politique de votre page n'autorise pas les hôtes de Wajub | Autorisez les hôtes listés dans Content Security Policy |
onLoadError explique une intégration vide
onError concerne les paiements qui échouent. onLoadError concerne les checkouts qui ne
démarrent jamais, comme dans la plupart des lignes ci-dessus. Configurez-le en premier dans chaque intégration.
Clés
Les clés live commencent par pk. ou sk., les clés de sandbox par pk_test. ou sk_test..
| Symptôme | Cause | Correction |
|---|---|---|
secret_key_in_browser | Clé sk. transmise à Wajub() | Le navigateur reçoit un jeton de session, jamais une clé secrète |
invalid_publishable_key | La valeur n'est pas une clé publique | Elle commence par pk et ne correspond pas au jeton de session |
missing_publishable_key | Appel de createPayment() sans clé | Configurez-la sur le client ou créez la session sur votre serveur |
Réponse 403 de l'API et e-mail | Clé secrète envoyée depuis un navigateur | L'API la refuse et alerte son propriétaire. Renouvelez la clé |
CORS sur createPayment | Appel direct de l'API depuis le code de la page | Créez la session sur votre backend |
Pour distinguer la sandbox du mode live dans le navigateur, lisez la session plutôt que la clé.
import { fetchSession } from '@wajub/js';
const preview = await fetchSession(sessionId);
if (preview.environment === 'sandbox') showSandboxBanner();Champs de paiement
| Symptôme | Cause | Correction |
|---|---|---|
complete ne devient jamais true | Champ obligatoire encore vide ou invalide | Enregistrez event.error dans le handler change, il identifie le champ |
confirmPayment rejette avec wallet_not_supported | Composant wallet | Apple Pay et Google Pay utilisent leur propre bouton |
confirmPayment rejette avec address_not_payment | Composant address | Il collecte sans débiter. Lisez-le avec getValue() |
confirmPayment rejette avec missing_component | Aucun composant transmis ou composant jamais monté | Conservez l'instance de onInstance ou de l'événement ready |
confirmation_timeout après une minute | Aucun résultat reçu à temps. Le paiement continue et peut encore réussir | Augmentez timeout ou transmettez 0 pour attendre indéfiniment. Avant de proposer de payer à nouveau, écoutez success ou attendez le webhook |
confirmPayment rejette avec checkout_validation | onBeforeSubmit a renvoyé false, a levé une exception ou a dépassé 30 secondes | Répondez en moins de 30 secondes, et ne renvoyez false que si la commande a été refusée |
confirmPayment rejette avec payment_error, « Validate the order before confirming this payment. » | Le paiement a été préparé avec deferred: true et jamais activé | Activez-le depuis votre endpoint de commande avant que onBeforeSubmit renvoie true |
getValue() renvoie null | Aucune valeur encore saisie | La valeur arrive au premier change. Lisez-la dans le handler |
Style sans effet
Le SDK filtre appearance avant son départ du navigateur. Une clé inconnue est ignorée sans
avertissement. Une faute de frappe ressemble donc exactement à un bug du checkout.
| Symptôme | Cause |
|---|---|
Bloc rules ignoré | Le sélecteur n'est pas .Input ou .Label avec au maximum un pseudo-élément autorisé |
| Propriété d'une règle ignorée | Elle ne figure pas parmi les 31 propriétés autorisées |
| Image d'arrière-plan ou importation de police ignorée | Certaines valeurs sont refusées par sécurité, dont toute valeur qui chargerait une ressource externe |
Clé variables ignorée | Seules les seize clés documentées sont acceptées |
update({ layout }) ne change rien | Le checkout hébergé l'enregistre localement sans l'envoyer |
Les props appearance ne changent rien après le montage | CheckoutEmbed n'appelle jamais lui-même update() |
Les trois listes figurent dans Apparence. Le comportement propre à chaque framework est présenté dans React, Vue et Svelte.
Mise en page et dimensions
| Symptôme | Cause | Correction |
|---|---|---|
| L'intégration est coupée | Parent avec overflow: hidden ou hauteur fixe | Le SDK définit lui-même la hauteur de l'iframe. Laissez le parent grandir |
| La page se décale au chargement du checkout | Aucun espace réservé autour de votre contenu | Le SDK réserve déjà 480px. Réservez votre récapitulatif, pas l'intégration |
| Un composant de champ reste minuscule | Son parent utilise display: none lors du montage | Montez-le une fois visible ou après l'ouverture de l'onglet |
onResize est fourni à titre informatif. Le SDK a déjà appliqué la hauteur lors de son déclenchement.
Utilisez-le pour déplacer un autre élément de la page.
Paiement
| Symptôme | Cause | Correction |
|---|---|---|
| Moyen de paiement absent du checkout | La session ne contient pas ce canal | Lisez fetchSession().payment_methods avant le montage |
| Commande livrée deux fois | onSuccess et le webhook déclenchent tous deux la livraison | Livrez avec le webhook et utilisez onSuccess pour l'interface |
| Commande jamais livrée | onSuccess s'est exécuté puis l'onglet s'est fermé | Même réponse. Le navigateur n'est pas une source fiable |
onError se déclenche avec un decline_code | Le prestataire a refusé le paiement | retryable indique si une nouvelle tentative doit être proposée |
onError se déclenche avec nothing_to_submit | submit() n'a trouvé aucun bouton de paiement sur lequel appuyer : aucun moyen choisi, une étape d'OTP, le bouton propre d'un wallet, ou un paiement déjà en cours | Appelez submit() une fois que le payeur a choisi un moyen, et pas pendant un paiement en cours |
Avant de passer en live
onErroretonLoadErrorsont tous deux configurés.- La session est créée sur votre serveur avec la clé secrète dans une variable d'environnement.
- Votre site et votre URL de
callbackutilisent HTTPS. - La commande est livrée à la réception du webhook, pas dans le navigateur.
- L'intégration utilise
mount(),open()ou un composant de framework, jamais une URL construite à la main. onBreakdownmaintient votre total à jour s'il apparaît à côté d'une intégration en ligne.- Un paiement réel d'un petit montant a été effectué en mode live.
Les cartes et numéros Mobile Money de test figurent dans Scénarios de test.
Le problème persiste ?
Écrivez à [email protected] avec la référence de transaction, le domaine de votre
marchand et le code de onLoadError ou onError. N'envoyez jamais de clé.