Aller au contenu

Champs de paiement

Votre mise en page et votre bouton de paiement, Wajub affiche uniquement les champs sécurisés.

Les champs de paiement inversent le principe du checkout hébergé. Vous conservez la page, le récapitulatif de commande et le bouton de paiement. Wajub affiche dans des iframes séparées les champs qui ne doivent pas toucher à votre DOM. Vous les envoyez lorsque vous êtes prêt.

Ce compromis vous donne le contrôle de la mise en page, mais retire les parties de la page hébergée qui nécessitent un flux complet : coupons, champs personnalisés, OTP et étape de livraison complète. Si vous en avez besoin, utilisez plutôt le checkout hébergé.

Les cinq composants

TypeAffichageDéclenchement du paiement
cardLes champs de carte du fournisseur (Stripe, Adyen, Mollie), le bouton carte de PayPal, ou un bouton qui ouvre la fenêtre de paiement du fournisseur (Paystack, Flutterwave, FedaPay, Paddle, PayDunya, CinetPay, Kkiapay)Vous, avec confirmPayment()
mobileMoneyOpérateur et numéro de téléphoneVous, avec confirmPayment()
paymentSélecteur de moyen de paiement et formulaire correspondantVous, avec confirmPayment()
addressAdresse de livraison ou de facturationPersonne, lisez-la avec getValue()
walletApple Pay ou Google PayBouton natif dans le composant

Structure générale

Une fabrique conserve la session et les options partagées. Chaque appel create() crée un composant, puis mount() le place sur la page.

Champs de carte et bouton personnalisé
import { components, confirmPayment } from '@wajub/js';

const factory = await components(sessionId, {
  locale: 'fr',
  appearance: { primaryColor: '#2563eb', labels: 'floating' },
});

const card = factory
  .create('card')
  .on('change', (event) => (payButton.disabled = !event.complete))
  .mount('#card');

payButton.onclick = () => confirmPayment({ sessionId, components: card });

Les options transmises à la fabrique deviennent les valeurs par défaut de tous ses composants. Les options transmises à create() sont prioritaires pour le composant concerné.

Les composants se dimensionnent automatiquement

Chaque composant démarre avec min-height: 120px. Le SDK définit la hauteur de l'iframe depuis le checkout à chaque modification du contenu. Vous n'avez rien à mesurer ni à réserver.

Configuration

OptionTypeComposants concernésFonction
sessionIdstringTousObligatoire, défini une fois sur la fabrique
localestringTousfr, en, es, pt, ar
appearanceAppearanceConfigTousApparence
layoutCheckoutLayoutpaymentDisposition du sélecteur de moyen de paiement
collectAddressshipping ou billingpaymentAjoute un bloc d'adresse dans le formulaire
addressModeshipping ou billingaddressEnsemble de libellés à utiliser
collectNamebooleanpayment, addressAjoute le champ de nom du payeur
fields.phonealways, auto, neverpayment, addressVisibilité du champ de téléphone
componentOriginstringTousVotre origine canonique pour les boutiques sur plusieurs domaines

componentOrigin utilise par défaut l'origine de la page qui effectue le montage. Un domaine unique ne nécessite donc aucune configuration.

Une adresse seule et un formulaire qui en contient une
factory
  .create('address', { addressMode: 'shipping', collectName: true, fields: { phone: 'auto' } })
  .mount('#address');

factory
  .create('payment', { collectAddress: 'shipping', collectName: true, layout: 'tabs' })
  .mount('#payment');

Événements

Abonnez-vous avec .on(event, handler), qui renvoie le composant et permet de chaîner les appels. Les mêmes handlers existent sous les noms onReady, onChange et autres dans ComponentConfig.

ÉvénementPayloadDéclenchement
readyComponentInstanceComposant monté et interactif
change{ complete, empty, error, value }Modification d'un champ ou de sa validité
focusRienPrise de focus par un champ
blurRienPerte de focus par un champ
successTransactionRéussite du paiement
errorWajubErrorÉchec du paiement
loaderrorWajubErrorÉchec du chargement du composant
resize{ height }Agrandissement ou réduction du composant
statechange{ state, method }Passage du checkout à un autre état
methodchange{ methodId }Choix d'un autre moyen de paiement par le payeur
Contrôler votre propre bouton
component.on('change', (event) => {
  payButton.disabled = !event.complete;
  errorLabel.textContent = event.error ? event.error.message : '';
});

complete signifie valide, pas payé

change.complete indique que les champs réussiraient la validation. L'argent est transféré lors de success, mais seul votre webhook le confirme.

Envoyer le paiement

confirmPayment reçoit la session et un composant monté, l'envoie et attend le résultat.

Réussite ou rejet avec une WajubError
try {
  const { status, transaction } = await confirmPayment({ sessionId, components: card });
  showReceipt(status, transaction);
} catch (error) {
  showRetry(error.code, error.message);
}
OptionValeur par défautFonction
sessionIdObligatoireSession utilisée pour créer le composant
componentsObligatoireUn composant card, mobileMoney ou payment monté
timeout60000Millisecondes avant le rejet avec confirmation_timeout. 0 attend indéfiniment

Quatre rejets se produisent avant tout envoi. Ils signalent donc des erreurs d'intégration, pas des échecs de paiement.

CodeCause
missing_componentAucun composant transmis ou objet incapable d'envoyer le paiement
wallet_not_supportedComposant wallet, dont le bouton natif déclenche le paiement
address_not_paymentComposant address, à lire avec getValue()
confirmation_timeoutAucun résultat reçu avant timeout

Piloter un composant

MéthodeFonction
mount(container)S'attache à un sélecteur ou un élément
update({ locale, appearance, layout })Applique la modification en direct sans nouveau montage
focus(), blur()Donne ou retire le focus au premier champ
submit()Envoie sans confirmPayment, vous gérez les événements
selectMethod(id)Change de moyen de paiement sur un composant payment
isComplete()Indique si les champs réussiraient la validation
getState()CheckoutState actuel, INITIATED avant toute action
getError()Dernière WajubError, ou null
getValue()Valeurs de l'adresse, { name, phone, address, mode }
unmount(), destroy()Retire le composant du DOM, en conservant ou non l'instance

update() fonctionne ici, contrairement à l'intégration hébergée

Un composant envoie locale, appearance et layout à son iframe, puis se redessine. Le checkout hébergé applique tout sauf layout. Cette différence existe réellement.

getValue() renvoie null jusqu'à ce que le composant d'adresse signale une valeur lors de son premier change. Lisez-la dans le handler ou lors de l'envoi par le payeur, pas au montage.

Avec un framework

Chaque composant existe sous forme d'enveloppe prête à l'emploi, avec les mêmes options comme props. L'enveloppe surveille aussi appearance, locale et layout, puis appelle update() pour vous.

const { confirm, isConfirming } = useConfirmPayment(sessionId);
const field = useRef<ComponentInstance | null>(null);

<PaymentComponent sessionId={sessionId} onInstance={(i) => (field.current = i)} />;
<button disabled={isConfirming} onClick={() => field.current && confirm(field.current)}>
  Pay now
</button>;

Le provider, les tableaux de props et l'intégration côté serveur figurent dans React, Vue et Svelte.

Fonctionnalités abandonnées

FonctionnalitéCheckout hébergéChamps de paiement
Moyens de paiement enregistrésOuiOui
3DSOuiOui
PortefeuillesOuiOui, avec le bouton natif
CouponsOuiNon
Champs de checkout personnalisésOuiNon
Flux de livraison completOuiBloc d'adresse uniquement
OTPOuiNon

Que pensez-vous de ce contenu ?