Aller au contenu

Cas d'utilisation

Six intégrations réelles et les raisons qui déterminent la forme de chacune.

Tous les modèles ci-dessous reposent sur les trois mêmes éléments : une session créée sur votre serveur, une interface dans le navigateur et un webhook de confirmation. Seuls l'emplacement de l'interface et la part de la page que vous contrôlez changent.

Une boutique en ligne avec le checkout sur la page

Vous gardez le contrôle du panier, le paiement en constitue une section et le client ne quitte jamais votre domaine. onBreakdown maintient le total à jour lorsqu'un coupon ou un choix de livraison le modifie.

La page du panier
import { mount } from '@wajub/js';

const { sessionId } = await fetch('/api/checkout/session', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ cartId }),
}).then((r) => r.json());

await mount('#checkout', {
  sessionId,
  layout: 'tabs',
  onBreakdown: (b) => {
    cartTotal.textContent = `${b.total.toLocaleString()} ${b.currency}`;
  },
  onSuccess: () => (window.location.href = '/order/complete'),
  onError: (error) => showToast(error.message),
});

Le flux hébergé complet est inclus : coupons, OTP, 3DS et livraison. Les couleurs et le logo proviennent de l'image de marque de votre compte. Vous n'avez rien à styliser ici, sauf si vous souhaitez donner une apparence différente à cette page.

Une landing page avec un minimum de code

Votre serveur a déjà reçu authorization_url depuis POST /payments. Redirigez-y le client.

Aucun SDK sur la page
window.location.href = authorizationUrl;

Le client revient sur votre URL de callback avec un paramètre d'URL status. Lisez-le pour choisir la page à afficher, puis confirmez correctement le paiement grâce au webhook. Consultez Sessions et sécurité pour plus de détails.

Cette solution est la plus rapide à mettre en place et la plus facile à maintenir. Elle constitue donc la meilleure première intégration pour la plupart des marchands.

Une mise à niveau dans une application

Le client effectue déjà une action. Le paiement l'interrompt et doit lui rendre la page une fois terminé.

Une fenêtre modale sur votre interface
import { open } from '@wajub/js';

upgradeButton.onclick = async () => {
  const { sessionId } = await fetch('/api/billing/upgrade', { method: 'POST' })
    .then((r) => r.json());

  await open({
    sessionId,
    closeOnOverlay: false,
    onSuccess: () => refreshAccount(),
    onCancel: () => track('upgrade_cancelled'),
  });
};

closeOnOverlay: false est la valeur par défaut et convient à ce cas. Un clic accidentel ne doit pas interrompre un paiement en cours.

La fermeture de la fenêtre modale ne fait que la masquer. La session reste ouverte. Si le client change d'avis, le même jeton permet de la remonter.

Un formulaire d'abonnement conçu par vos soins

Vous contrôlez le sélecteur de plan et le bouton. Wajub affiche uniquement les champs de carte.

React
'use client';

import { useRef, useState } from 'react';
import type { ComponentInstance } from '@wajub/js';
import { CardComponent, useConfirmPayment } from '@wajub/react';

export function Subscribe({ sessionId }: { sessionId: string }) {
  const { confirm, isConfirming } = useConfirmPayment(sessionId);
  const card = useRef<ComponentInstance | null>(null);
  const [canPay, setCanPay] = useState(false);

  return (
    <>
      <h2>Pro plan, 25 000 XAF per month</h2>
      <CardComponent
        sessionId={sessionId}
        appearance={{ labels: 'floating' }}
        onInstance={(instance) => (card.current = instance)}
        onChange={(event) => setCanPay(Boolean(event.complete))}
      />
      <button
        disabled={!canPay || isConfirming}
        onClick={() => card.current && confirm(card.current)}
      >
        {isConfirming ? 'Processing…' : 'Subscribe'}
      </button>
    </>
  );
}

useConfirmPayment renvoie un objet, pas une fonction. Déstructurez-le. isConfirming empêche un second clic d'ouvrir un autre paiement.

Ce mode ne prend en charge ni les coupons ni les OTP. Si la page du plan doit accepter un code promotionnel, le checkout hébergé est la solution la plus directe.

Mobile Money avec les moyens de paiement dans des onglets

Le composant payment contient le sélecteur et le formulaire correspondant. Un seul composant couvre donc les cartes, le Mobile Money et les portefeuilles.

Un composant pour tous les moyens de paiement
import { components, confirmPayment } from '@wajub/js';

const factory = await components(sessionId, { layout: 'tabs' });

const payment = factory
  .create('payment', { collectName: true, fields: { phone: 'always' } })
  .on('change', (event) => (payButton.disabled = !event.complete))
  .mount('#payment');

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

Configurez fields.phone: 'always' si le Mobile Money est votre canal principal. Avec auto, le champ apparaît uniquement lorsque le moyen de paiement choisi l'exige, ce qui provoque un décalage du formulaire.

Afficher le montant avant le chargement du checkout

fetchSession lit la session avec le jeton lui-même. Il fonctionne donc dans le navigateur avant le montage de tout autre élément.

Un récapitulatif au-dessus de l'intégration
import { fetchSession, preload } from '@wajub/js';

const preview = await fetchSession(sessionId);

amount.textContent = `${preview.amount.toLocaleString()} ${preview.currency}`;
merchant.textContent = preview.merchant_name;

if (preview.environment === 'sandbox') showSandboxBanner();
if (preview.saved_methods?.length) showReturningCustomerHint();

preload(sessionId);

preload(sessionId) ouvre une connexion vers l'origine du checkout. L'iframe n'a donc plus rien à négocier lors de son montage. Appelez cette fonction lorsque le client arrive dans le panier, pas lorsqu'il clique sur le bouton de paiement.

preload(sessionId, { iframe: true }) va plus loin et charge tout le checkout dans une iframe masquée. Le montage semble instantané, mais coûte le chargement d'une page complète. Utilisez cette option uniquement lorsque le client est très susceptible de payer.

Choisir un modèle

Votre situationModèle
Une page de checkout de boutiquemount en ligne avec onBreakdown
Une landing page ou un MVPRedirection vers authorization_url
Un paiement dans une application en cours d'utilisationSuperposition open()
Un tunnel que vous avez déjà conçuChamps de paiement et votre propre bouton
WordPress ou HTML simpleScript CDN et mount
Next.js, Nuxt, SvelteKitProvider du framework et CheckoutEmbed

Que pensez-vous de ce contenu ?