SubSovereign sur React (web) — guide d’intégration
Ce guide couvre @subsovereign/react (sdk-react/) — la couche d’interface utilisateur (UI) de paiement pour les applications web React. Elle rend le paywall que vous concevez dans le tableau de bord SubSovereign sous forme de composants React réels, à partir du même moteur de rendu que celui utilisé pour l’aperçu du tableau de bord, afin que ce que vous validez dans le tableau de bord soit exactement ce qui est déployé.
Ce SDK affiche le paywall ; il ne gère ni la facturation ni les droits d’accès. Associez-le au SDK de données Web/JS (@subsovereign/js-sdk) pour checkEntitlements() et la validation des achats — les deux sont conçus pour être utilisés ensemble.
Avant de commencer
Vous aurez besoin d’un serveur SubSovereign en cours d’exécution, d’une application enregistrée dans le tableau de bord (un appId et une clé API de rôle SDK), et d’un paywall publié (tableau de bord → Paywall → Publier).
Étape 1 — Installation
Le package se trouve dans sdk-react/ et n’est pas encore sur npm — ajoutez-le en tant que dépendance locale ou via git (ou copiez le dossier dans votre projet) :
npm install ./sdk-react # path dependency while it's pre-npm
import { Paywall, usePaywallConfig } from '@subsovereign/react';
Étape 2 — Charger le paywall publié
usePaywallConfig récupère la configuration de cette application/utilisateur. La variante A/B est choisie côté serveur par userId, afin que le même utilisateur voie toujours le même paywall.
const { config, loading, error } = usePaywallConfig({
apiUrl: 'https://subs.yourdomain.com/api/v1', // YOUR self-hosted server
appId: 'your-app-id',
userId: currentUser.id, // your own stable user id
apiKey: 'YOUR_SDK_KEY',
locale: 'en', // optional, default 'en'
platform: 'web', // optional, default 'web'
});
Passez null à la place des paramètres pour ignorer la récupération (par exemple, lorsque l’utilisateur n’est pas connecté).
Étape 3 — L’afficher
<Paywall
config={config}
loading={loading}
loadingState={<Spinner />} // optional
emptyState={<FallbackPaywall />} // optional — shown when no config is published
onSelectProduct={(productId) => startCheckout(productId)}
/>
onSelectProduct se déclenche lorsque l’utilisateur sélectionne un produit — connectez-le à votre processus de paiement (Stripe sur le web). Après un paiement réussi, validez avec le SDK de données et vérifiez à nouveau les droits d’accès :
await SubSovereign.validateStripeSubscription({ subscriptionId, productId, accessLevelId: 'pro' });
const { hasAccess } = await SubSovereign.checkEntitlements();
if (hasAccess) unlockProFeatures();
Si vous avez déjà une configuration (récupérée via le SDK de données), ignorez le hook et transmettez-la directement. Pour un contrôle total, utilisez le moteur de rendu brut : <PaywallRenderer config={config} onSelectProduct={…} />.
Bouton de rétractation (Compliance Passport)
Si vous vendez des abonnements à des consommateurs de l’UE en ligne, la directive (UE) 2023/2673 exige une fonction de rétractation clairement étiquetée. Le SDK l’intègre prêt à l’emploi :
import { WithdrawalButton, useWithdrawalConfig } from '@subsovereign/react';
function CancelSubscription({ user, sub }: { user: { id: string; locale: string }; sub: { id: string } }) {
// Fetches the withdrawal settings AND the notice's wording in the customer's language.
const { config, strings, error } = useWithdrawalConfig({
apiUrl: 'https://subs.yourdomain.com/api/v1',
appId: 'your-app-id',
apiKey: 'YOUR_SDK_KEY',
locale: user.locale, // the CUSTOMER's language, not your console's
});
// Log it: a silent failure here is how a tenant ships English to German customers and never finds
// out. The customer is never shown this — they get the button, in English.
if (error) console.warn('SubSovereign: withdrawal settings unavailable', error);
if (config && config.enabled === false) return null; // the tenant turned it off
return (
<WithdrawalButton
apiUrl="https://subs.yourdomain.com/api/v1"
appId="your-app-id"
apiKey="YOUR_SDK_KEY"
userId={user.id}
subscriptionId={sub.id}
strings={strings} // ← without this the dialog is ENGLISH for every customer
locale={user.locale} // ← and without this the DATE is formatted for the device
labelKey={config?.labelKey} // ← the label the tenant chose in the console
appearance="auto"
/>
);
}
Vous ne pouvez pas modifier le libellé. La console propose deux étiquettes pour la fonction de rétractation — « Withdraw from contract here » et « Cancel here » — et labelKey transmet celle que le locataire a choisie ; les mots eux-mêmes proviennent du serveur dans la langue du client. Il n’y a aucun moyen de transmettre votre propre texte. Une ancienne prop label acceptait du texte libre et est désormais ignorée avec un avertissement dans la console : une mention légale pouvant être reformulée peut être adoucie en argument marketing, c’est la même raison pour laquelle vous ne pouvez pas transmettre une couleur.
🚩 Transmettez également locale. Cela formate l’horodatage sur l’accusé de réception. Sans cela, la date est formatée pour l’appareil, donc un client allemand sur un navigateur américain verra 9/3/2026 — qu’il interprétera comme le 9 mars, et non le 3 septembre. Il s’agit de la date figurant sur l’acte juridique, et l’ambiguïté fonctionne dans les deux sens.
🚩 Transmettez strings, sinon la mention légale sera en anglais pour tous. Les mots sont fournis par votre serveur SubSovereign dans la locale demandée — ils nous appartiennent plutôt qu’à vous, afin qu’une mention légale ne puisse pas être adoucie en argument marketing — et le bouton affiche ce qu’on lui transmet. Il ne les récupère pas lui-même, car le même contrat de composant doit fonctionner sur Roku, où un composant d’interface ne peut pas effectuer de requête réseau. useWithdrawalConfig est la seule ligne qui relie les deux.
Si la récupération échoue, le bouton apparaît toujours, en anglais, plutôt que de ne pas s’afficher. Ne pas placer une fonction de rétractation facilement accessible devant le consommateur constitue une violation de votre part ; l’afficher dans la mauvaise langue ne l’est pas. Le hook retourne error afin que vous puissiez le journaliser ; ne l’affichez jamais au client.
Apparence — light, dark ou auto (par défaut), et rien d’autre. La boîte de dialogue peint sa propre carte et son propre texte, afin qu’elle soit lisible sur n’importe quelle page, en mode clair ou foncé ; auto suit le paramètre du navigateur de l’utilisateur, et en l’absence de préférence détectée, elle bascule en foncé. Il n’existe délibérément aucun moyen de transmettre une couleur : il s’agit d’une mention légale, et ses mots ainsi que ses couleurs sont fixes pour que chaque client de chaque locataire la lise de la même manière. Si vous appliquez cette règle ailleurs dans votre interface, resolveAppearance(appearance, scheme) est exporté (scheme est 'light' | 'dark' | null).
Elle affiche le bouton étiqueté en évidence, confirme une fois, soumet de manière idempotente (une nouvelle tentative réseau ne peut jamais créer deux rétractations), et affiche l’accusé de réception. Le bouton lui-même n’effectue aucun appel réseau en dehors de la soumission, donc c’est à vous de gérer la validation avec config.enabled et config.jurisdictions, comme ci-dessus. Des éléments de bas niveau (fetchWithdrawalConfig, useWithdrawal, submitWithdrawal) sont exportés pour les interfaces personnalisées.
Référence rapide
| Vous souhaitez… | Utilisez |
|---|---|
| Charger le paywall publié | usePaywallConfig(params) → { config, loading, error } |
| L’afficher | <Paywall config onSelectProduct … /> |
| Contrôle total du rendu | <PaywallRenderer config onSelectProduct /> |
| Rétractation UE, dans la langue du client | useWithdrawalConfig({…, locale}) → transmettez strings, locale et labelKey à <WithdrawalButton> |
| Droits d’accès / validation | le guide Web & React Native |
Étapes suivantes
- Couche de données (droits d’accès, achats, RGPD) : guide Web & React Native.
- Sites indépendants du framework (Vue/Svelte/HTML brut) : guide du composant Web.
- Nouveau sur les concepts ? Lisez Comment fonctionne SubSovereign.