whop-payments-network

Par whopio · whop-payments-network-skill

Intégrez le réseau de paiements Whop dans votre plateforme — encaissements, versements, checkout, composants embarqués, patterns d'API et webhooks.

npx skills add https://github.com/whopio/whop-payments-network-skill --skill whop-payments-network

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_id pour lier un plan à un produit. access_pass_id est un alias hérité — préférez product_id pour 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 :

  1. 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.
  2. 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.
  3. 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

  1. Les transferts utilisent les cents, les retraits utilisent les dollarstransfers.create({ amount: 4500 }) = $45.00, mais withdrawals.create({ amount: 45 }) = $45.00.
  2. application_fee_amount doit être > 0 ET < prix total — zéro ou égal au total génèrera une erreur.
  3. Le champ webhook est event, pas type — Le corps du webhook utilise event comme clé. Certains docs montrent incorrectement type.
  4. Les événements webhook peuvent utiliser des underscoresmembership_went_valid au lieu de membership.went.valid. Normalisez avec .replace(/_/g, ".").
  5. returnUrl est requis pour les méthodes de paiement externes — Les redirections Apple Pay, Google Pay, PayPal échouent sans lui.
  6. Le secret webhook doit être encodé en base64 — Passez btoa(process.env.WHOP_WEBHOOK_SECRET) à la clé webhookKey du SDK.
  7. 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.
  8. 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.
  9. 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 }).
  10. L'initialisation du SDK sans appID est valide — Les Clés API Entreprise n'ont pas besoin d'appID.
  11. La réponse de configuration de checkout inclut purchase_url et plan.id — Utilisez-les pour les flux de redirection ou les références de plan.
  12. URL de checkout Sandboxhttps://sandbox.whop.com/checkout/{planId}.
  13. setupFutureUsage: "off_session" — Requis sur l'embed de checkout quand vous prévoyez de charger l'utilisateur plus tard via l'API chargeUser.
  14. Ré-approbation des permissions — Après l'ajout de nouvelles permissions d'app, les appels API échouent avec 403 jusqu'à ce que l'entreprise ré-approuve.
  15. Utilisez toujours les clés d'idempotence — Sur les transferts et toute opération de mouvement d'argent pour éviter les doublons.
  16. 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 .id lors de la consommation de la liste complète.
  17. 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

Skills similaires