Intégration du Réseau de Paiements Whop
Whop fournit un réseau de paiements complet : accepter des paiements (entrées de fonds), envoyer des versements, intégrer des composants de checkout et de portefeuille, gérer les webhooks, administrer les comptes connectés et envoyer des notifications. Cette compétence couvre les schémas dont vous avez besoin pour intégrer Whop dans n'importe quelle plateforme.
1. Packages SDK
| Package | Objectif | Installation |
|---|---|---|
@whop/sdk |
Client API côté serveur (TypeScript) | npm install @whop/sdk |
whop-sdk |
Client API côté serveur (Python) | pip install whop-sdk |
whop_sdk |
Client API côté serveur (Ruby) | gem install whop_sdk |
@whop/checkout |
Composant React de checkout intégré | npm install @whop/checkout |
@whop/embedded-components-react-js |
Composants de versement/portefeuille/KYC/chat intégrés (React) | npm install @whop/embedded-components-react-js |
@whop/embedded-components-vanilla-js |
Composants intégrés (Vanilla JS) | npm install @whop/embedded-components-vanilla-js |
2. Configuration du SDK
URL de base : https://api.whop.com/api/v1
import Whop from "@whop/sdk";
// Clé API Entreprise — accéder aux données de votre propre entreprise ou comptes connectés
const client = new Whop({
apiKey: process.env.WHOP_API_KEY,
// appID n'est PAS requis pour les Clés API Entreprise
});
// Clé API App — accéder aux données des entreprises qui ont installé votre app
const appClient = new Whop({
apiKey: process.env.WHOP_API_KEY,
appID: "app_xxxxxxxxxxxxxx",
});
Pour la vérification de webhook, ajoutez le secret webhook :
const client = new Whop({
apiKey: process.env.WHOP_API_KEY,
webhookKey: btoa(process.env.WHOP_WEBHOOK_SECRET || ""),
});
3. Authentification
Types de Clés API
| Type | Quand l'utiliser | Comment l'obtenir |
|---|---|---|
| Clé API Entreprise | Données de votre propre entreprise, comptes connectés, opérations de plateforme | Tableau de bord > Développeur > Clés API Entreprise |
| Clé API App | Accéder aux données des entreprises qui ont installé votre app | Tableau de bord > Développeur > Créer App > Variables d'env |
| Token OAuth | Agir au nom d'un utilisateur spécifique | Flux OAuth 2.1 + PKCE |
OAuth / NextAuth v5 OIDC
Configuration clé : type: "oidc", issuer: "https://api.whop.com", token_endpoint_auth_method: "none", id_token_signed_response_alg: "ES256", checks: ["pkce", "nonce"]. Champs de profil : sub, name, email, picture, username.
Remarque : OAuth/OIDC est encore marqué « en développement » dans la documentation officielle. Le schéma NextAuth fonctionne mais peut changer.
Autorisation Admin
const access = await client.users.checkAccess(companyId, { id: userId });
4. Schémas d'Architecture
Schéma A : Architecture Apatride / Sans Base de Données
Utilisez les entités Whop comme magasin de données au lieu de gérer votre propre base de données :
| Votre concept | Entité Whop | Stocker les données personnalisées via |
|---|---|---|
| Comptes utilisateurs | Entreprises | metadata sur l'entreprise |
| Annonces / articles du catalogue | Produits | description (peut stocker du JSON) |
| Tarification / variantes | Plans | champs de plan + metadata |
| Achats / réservations | Adhésions | recherche d'adhésion |
Cela fonctionne bien pour les marchés, les plateformes de réservation et les sites d'annonces où Whop gère tout l'état transactionnel.
Schéma B : Marché Bipartite (Comptes Connectés)
Chaque vendeur/créateur obtient une entreprise enfant. La plateforme prélève application_fee_amount sur les checkouts :
const vendor = await client.companies.create({
parent_company_id: "biz_yourplatform",
email: "vendor@example.com",
title: "Vendor Store",
metadata: { vendor_tier: "gold" },
});
const checkout = await client.checkoutConfigurations.create({
company_id: vendor.id,
mode: "payment",
redirect_url: "https://yourplatform.com/complete",
plan: {
company_id: vendor.id, product_id: "prod_xxx",
initial_price: 5000, plan_type: "one_time", currency: "usd",
visibility: "hidden", release_method: "buy_now",
application_fee_amount: 500, // doit être > 0 ET < total
},
});
// Frais dynamiques : Math.round(price * (tier === "gold" ? 0.05 : 0.10))
Schéma C : Modèle de Trésorerie de Plateforme
Tous les paiements vont à la plateforme. La plateforme distribue via des transferts après approbation admin :
// 1. Checkout vers la plateforme (sans application_fee)
const checkout = await client.checkoutConfigurations.create({
company_id: "biz_yourplatform",
plan: { initial_price: 5000, plan_type: "one_time" },
});
// 2. Vérifier le solde
const ledger = await client.ledgerAccounts.retrieve("biz_yourplatform");
// 3. Transférer au vendeur
const transfer = await client.transfers.create({
amount: 4500, currency: "usd", // montant en CENTS
origin_id: "biz_yourplatform", destination_id: "biz_vendor",
metadata: { order_id: "order_123" }, notes: "Payout for order #123",
idempotence_key: "transfer_order_123", // empêche les doublons
});
5. Produits et Plans
API Produits
Les produits sont la couche catalogue au-dessus des plans. Un produit a plusieurs plans (variantes tarifaires).
Utilisez
product_idpour lier un plan à un produit.access_pass_idest un alias hérité — préférezproduct_idpour les nouvelles intégrations.
const product = await client.products.create({
company_id: "biz_xxx",
title: "Premium Course",
description: JSON.stringify({ category: "education", level: "advanced" }), // peut stocker du JSON
visibility: "visible", // ou "hidden"
});
await client.products.update(product.id, { title: "Updated Title" });
const products = await client.products.list({ company_id: "biz_xxx" });
API Plans
// Plan de paiement unique
const plan = await client.plans.create({
company_id: "biz_xxx",
product_id: "prod_xxx",
initial_price: 2999, // $29.99
plan_type: "one_time",
currency: "usd",
visibility: "visible", // ou "hidden" pour les plans checkout uniquement
release_method: "buy_now",
});
// Plan d'abonnement
const subPlan = await client.plans.create({
company_id: "biz_xxx",
product_id: "prod_xxx",
plan_type: "renewal",
initial_price: 999,
renewal_price: 999,
billing_period: 30, // jours
currency: "usd",
});
// Plan à stock limité (inventaire)
const limitedPlan = await client.plans.create({
company_id: "biz_xxx",
product_id: "prod_xxx",
initial_price: 4999,
plan_type: "one_time",
stock: 100, // épuisé après 100 achats
});
console.log(plan.purchase_url); // lien checkout partageable
Itération Asynchrone pour les Résultats Paginés
Toutes les méthodes .list() retournent des itérateurs asynchrones :
for await (const product of await client.products.list({ company_id: "biz_xxx" })) {
console.log(product.title);
}
for await (const company of await client.companies.list({ parent_company_id: "biz_xxx" })) {
console.log(company.title, company.metadata);
}
6. Checkout
Option A : Liens Checkout (Le Plus Simple)
Créez un plan, redirigez vers plan.purchase_url. Sandbox : https://sandbox.whop.com/checkout/{plan.id}.
Option B : Checkout Intégré (Interface Personnalisée)
Serveur — créer la configuration de checkout :
const config = await client.checkoutConfigurations.create({
company_id: "biz_xxx",
mode: "payment",
redirect_url: "https://yoursite.com/complete",
plan: {
company_id: "biz_xxx",
product_id: "prod_xxx",
initial_price: 1000,
plan_type: "one_time",
currency: "usd",
visibility: "hidden",
release_method: "buy_now",
application_fee_amount: 100, // frais de plateforme optionnels
},
metadata: { order_id: "order_123" },
});
// config.id = sessionId pour le client
// config.purchase_url = lien direct
// config.plan.id = ID du plan créé
Client — rendre l'embed :
import { WhopCheckoutEmbed } from "@whop/checkout/react";
<WhopCheckoutEmbed
sessionId={config.id}
returnUrl="https://yoursite.com/complete"
environment="production" // ou "sandbox"
themeOptions={{ accentColor: "#FF6243", highContrast: true }}
onComplete={(paymentId) => console.log("Paid:", paymentId)}
/>
En production, redirect_url doit être HTTPS. Localhost (HTTP) fonctionne en sandbox mais sera rejeté en production.
Ou utilisez planId directement (aucune configuration serveur requise) :
<WhopCheckoutEmbed
planId="plan_xxx"
returnUrl="https://yoursite.com/complete"
environment="sandbox"
/>
Option C : Checkout Panier Agrégé
Agrégez le total du panier en un seul checkout, sérialisez les articles dans metadata.cart :
const total = cartItems.reduce((sum, i) => sum + i.price * i.qty, 0);
const config = await client.checkoutConfigurations.create({
company_id: "biz_xxx",
plan: { initial_price: total, plan_type: "one_time" },
metadata: { cart: JSON.stringify(cartItems) },
});
Option D : Checkout Vanilla JS
<script async defer src="https://js.whop.com/static/checkout/loader.js"></script>
<div
data-whop-checkout-plan-id="plan_xxx"
data-whop-checkout-return-url="https://yoursite.com/complete"
></div>
Consultez references/checkout-embed.md pour la référence complète des props, les contrôles programmatiques et les tests en sandbox.
7. Comptes Connectés
// Créer
const company = await client.companies.create({
parent_company_id: "biz_yourplatform",
email: "creator@example.com", title: "Creator Store",
metadata: { tier: "free" },
});
// Lister (itérateur asynchrone)
for await (const co of await client.companies.list({ parent_company_id: "biz_yourplatform" })) {
console.log(co.id, co.title);
}
// Mettre à jour les métadonnées (lacune de typage du SDK — utiliser un cast de type)
await (client.companies as any).update(company.id, { metadata: { tier: "premium" } });
Intégration du Compte et KYC
// use_case: "hosted_kyc" | "hosted_payouts" | "account_onboarding"
const link = await client.accountLinks.create({
company_id: "biz_xxx", use_case: "hosted_kyc",
return_url: "https://yourplatform.com/dashboard",
refresh_url: "https://yourplatform.com/refresh",
});
// Rediriger vers link.url
Ledger et Vérification : await client.ledgerAccounts.retrieve("biz_xxx") — retourne les soldes, l'état KYC, payments_approval_status.
8. Versements
Financer le Solde de Votre Plateforme (Recharges)
Avant de pouvoir envoyer des transferts aux comptes connectés, votre plateforme a besoin d'un solde positif. Utilisez l'API Top-ups pour ajouter des fonds en chargeant une méthode de paiement enregistrée. Les top-ups n'ont pas de frais.
// 1. D'abord, enregistrez une méthode de paiement via le Tableau de bord Whop (Paramètres > Moyens de paiement)
// 2. Puis rechargez programmatiquement :
const topup = await client.topups.create({
company_id: "biz_your_platform",
amount: 50000, // $500.00 en cents
currency: "usd",
payment_method_id: "pm_saved_method_id",
});
// Écoutez le webhook payment.succeeded pour confirmer
Trois façons pour l'argent d'entrer dans une plateforme :
- Top-ups — charger une méthode de paiement enregistrée (ACH, carte). Idéal pour les plateformes qui collectent les fonds en externe (virement, facture) et ont besoin de financer leur solde Whop pour les versements.
- Charges directes — les clients paient les comptes connectés directement, la plateforme prélève un
application_fee_amount. L'argent circule via le checkout. - Modèle de transfert — les clients paient la plateforme via checkout, la plateforme distribue aux comptes connectés via
transfers.create().
Consultez Ajouter des fonds à votre solde pour le guide complet.
Composants de Versement Intégrés (React)
import { PayoutsSession, VerifyElement, AddPayoutMethodElement } from "@whop/embedded-components-react-js";
import { loadWhopElements } from "@whop/embedded-components-vanilla-js";
const elements = loadWhopElements({ environment: "production" }); // ou "sandbox"
// Serveur : const token = await client.accessTokens.create({ company_id: "biz_vendor" });
function VendorPayouts({ token, companyId }: { token: string; companyId: string }) {
return (
<PayoutsSession token={token} companyId={companyId} redirectUrl="/dashboard">
<VerifyElement />
<AddPayoutMethodElement />
{/* Aussi : BalanceElement, WithdrawElement, PayoutMethodsElement */}
</PayoutsSession>
);
}
Vérifier la Méthode de Versement
const methods = await client.payoutMethods.list({ company_id: "biz_xxx" });
const hasDefault = methods.some((m: any) => m.is_default);
Transferts (cents) et Retraits (dollars)
// Transferts — montant en CENTS
await client.transfers.create({
amount: 4500, currency: "usd",
origin_id: "biz_platform", destination_id: "biz_vendor",
metadata: { order_id: "order_123" }, notes: "Weekly payout",
idempotence_key: "payout_week12_vendor456",
});
// Retraits — montant en DOLLARS (différent !)
await client.withdrawals.create({ company_id: "biz_xxx", amount: 45.00 });
Consultez references/payouts.md pour les versements hébergés, les composants de portefeuille intégrés et le terrain de jeu interactif.
9. Webhooks
Configuration : Tableau de bord > Développeur > Créer Webhook > sélectionner les événements > fournir l'URL.
import type { NextRequest } from "next/server";
import { whopsdk } from "@/lib/whop-sdk";
export async function POST(request: NextRequest): Promise<Response> {
const body = await request.text();
const headers = Object.fromEntries(request.headers);
const webhookData = whopsdk.webhooks.unwrap(body, { headers });
// ATTENTION : le champ d'événement est `event`, pas `type`
// ATTENTION : les événements peuvent arriver avec des underscores : "membership_went_valid"
const eventType = webhookData.event.replace(/_/g, "."); // normaliser
switch (eventType) {
case "payment.succeeded":
// gérer le paiement
break;
case "membership.went.valid":
// gérer l'activation
break;
}
return new Response("OK", { status: 200 }); // retourner 2xx rapidement !
}
Consultez references/webhooks.md pour tous les événements, webhooks d'entreprise vs d'app et la validation.
10. Notifications
Envoyez des notifications push aux utilisateurs avec deep linking :
await client.notifications.create({
company_id: "biz_xxx",
user_id: "user_xxx",
title: "Your order shipped!",
content: "Track your order in the app.",
rest_path: "/orders/order_123", // chemin de deep link dans votre app
});
11. Chat SDK
Intégrez le chat en temps réel via ChatElement à l'intérieur des wrappers ChatSession et Elements. Consultez references/chat-sdk.md pour les exemples React, Vanilla JS et Swift.
12. Pièges Courants
- Les transferts utilisent les cents, les retraits utilisent les dollars —
transfers.create({ amount: 4500 })= $45.00, maiswithdrawals.create({ amount: 45 })= $45.00. application_fee_amountdoit être > 0 ET < prix total — zéro ou égal au total génèrera une erreur.- Le champ webhook est
event, pastype— Le corps du webhook utiliseeventcomme clé. Certains docs montrent incorrectementtype. - Les événements webhook peuvent utiliser des underscores —
membership_went_validau lieu demembership.went.valid. Normalisez avec.replace(/_/g, "."). returnUrlest requis pour les méthodes de paiement externes — Les redirections Apple Pay, Google Pay, PayPal échouent sans lui.- Le secret webhook doit être encodé en base64 — Passez
btoa(process.env.WHOP_WEBHOOK_SECRET)à la cléwebhookKeydu SDK. - Retournez 2xx rapidement depuis les webhooks — Whop réessaie en cas de timeout. Utilisez
waitUntil()ou des jobs en arrière-plan pour les traitements lourds. - Les tokens d'accès expirent — Par défaut 1 heure, max 3 heures. Rafraîchissez avant l'expiration pour les composants intégrés.
- Lacune de typage SDK pour les métadonnées d'entreprise — Mettez à jour les métadonnées via un cast de type :
(client.companies as any).update(id, { metadata }). - L'initialisation du SDK sans appID est valide — Les Clés API Entreprise n'ont pas besoin d'
appID. - La réponse de configuration de checkout inclut
purchase_urletplan.id— Utilisez-les pour les flux de redirection ou les références de plan. - URL de checkout Sandbox —
https://sandbox.whop.com/checkout/{planId}. setupFutureUsage: "off_session"— Requis sur l'embed de checkout quand vous prévoyez de charger l'utilisateur plus tard via l'APIchargeUser.- Ré-approbation des permissions — Après l'ajout de nouvelles permissions d'app, les appels API échouent avec
403jusqu'à ce que l'entreprise ré-approuve. - Utilisez toujours les clés d'idempotence — Sur les transferts et toute opération de mouvement d'argent pour éviter les doublons.
- Doublons de pagination des méthodes de versement — La liste des méthodes de versement peut retourner des doublons lors de la pagination — déduplicjfiez par
.idlors de la consommation de la liste complète. - Retrait automatique après transfert — Après approbation d'un transfert, envisagez d'initier automatiquement un retrait vers la méthode de versement par défaut du destinataire afin qu'il n'ait pas à le faire manuellement. Remarque : les transferts utilisent les cents, les retraits utilisent les dollars.
13. Système de Permissions
Les apps doivent demander des permissions avant d'accéder aux données de l'entreprise. Chaque endpoint d'API a les scopes requis.
Configuration : Tableau de bord > Développeur > App > Onglet Permissions > Ajouter les permissions avec justification > Installer l'app > Approuver.
Lors de la mise à jour des permissions, les créateurs voient un bouton « Ré-approuver ». Gérez les erreurs 403 avec élégance jusqu'à ré-approbation.
14. Accès au Serveur MCP
| Transport | URL |
|---|---|
| HTTP Streaming (Cursor) | https://mcp.whop.com/mcp |
| SSE (Claude) | https://mcp.whop.com/sse |
| Docs MCP | https://docs.whop.com/mcp |
15. Fichiers de Référence
| Fichier | Contenu |
|---|---|
references/checkout-embed.md |
Référence complète des props, contrôles programmatiques, Vanilla JS, sandbox, Apple Pay |
references/payouts.md |
Composants de portefeuille intégrés, versements hébergés, liens de compte, terrain de jeu |
references/chat-sdk.md |
Chat SDK pour React, Vanilla JS, Swift avec des exemples complets |
references/api-reference.md |
Initialisation du SDK, endpoints clés, configuration du serveur MCP |
references/webhooks.md |
Événements webhook, validation, webhooks d'entreprise vs d'app |
codebase-scan.md |
Prompt pour analyser la base de code d'un client pour la planification d'intégration Whop |