Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.whop.com/llms.txt

Use this file to discover all available pages before exploring further.

Accept one-time and recurring payments using checkout links or an embedded checkout component. Whop supports 100+ payment methods across 195 countries, and the right ones appear automatically based on the buyer’s location. See all payment methods.
Building an iOS app? The Whop iOS Checkout SDK handles checkout natively with lower fees (2.7% + $0.30 vs Apple’s 15–30%). The SDK uses a scoped iap:read API key that’s safe to embed in your app.

Choose your integration

Checkout linkEmbedded checkout
EffortLowMedium
CustomizationLimitedFull control
Best forSharing links, quick setupCustom UX, dynamic pricing
Server code requiredNo (Dashboard) / Yes (API)Yes
Checkout links are the simplest way to accept payments. Create a plan to get a shareable checkout URL.
  1. Go to your Dashboard > Checkout links
  2. Click + Create checkout link
  3. Select a product and configure your pricing (free, one-time, or recurring)
  4. Click Create checkout link
The generated link can be shared directly with customers or embedded on your website.

Option 2: Embedded checkout

For a custom checkout experience, use the embedded checkout component with a checkout configuration.

Step 1: Create a checkout configuration

Create a checkout configuration on your server with an inline plan:
import Whop from "@whop/sdk";

const client = new Whop({
  apiKey: "Company API Key",
});

const checkoutConfig = await client.checkoutConfigurations.create({
  company_id: "biz_xxxxxxxxxxxxx",
  plan: {
    initial_price: 10.0,
    plan_type: "one_time",
  },
  metadata: {
    order_id: "order_12345",
  },
});

console.log(checkoutConfig.id); // ch_xxxxxxxxxxxxx (session ID)
console.log(checkoutConfig.plan?.id); // plan_xxxxxxxxxxxxx (plan ID)
In this example:
  • company_id is your company ID
  • plan.initial_price is the payment amount
  • plan.plan_type is either one_time or renewal for subscriptions
  • metadata stores custom data for your reference

Step 2: Render the checkout

import { WhopCheckoutEmbed } from "@whop/checkout/react";

export function Checkout({ sessionId }: { sessionId: string }) {
  return (
    <WhopCheckoutEmbed
      sessionId={sessionId}
      returnUrl="https://yoursite.com/checkout/complete"
      onComplete={(paymentId) => {
        console.log("Payment complete:", paymentId);
      }}
    />
  );
}
Pass the checkoutConfig.id from step 1 as the sessionId prop.
The returnUrl is required to handle redirects from external payment providers. When redirected, check the status query parameter:
  • success: The payment succeeded. Use the receipt information to render a success page.
  • error: The payment failed or was canceled. Remount the checkout so your customer can try again.

Step 3: Customize the checkout

You can customize the checkout appearance and behavior:
Prop (React)Attribute (HTML)Description
themedata-whop-checkout-theme"light", "dark", or "system" (default)
hidePricedata-whop-checkout-hide-priceHide the price display
themeOptions.accentColordata-whop-checkout-theme-accent-colorCustom accent color
For the full list of customization options, see the Embedded checkout reference.

Handle payment webhooks

Listen for webhooks to fulfill orders on your server. This example uses Next.js on Vercel, but the whopsdk.webhooks.unwrap pattern works with any framework:
import { waitUntil } from "@vercel/functions";
import type { Payment } from "@whop/sdk/resources.js";
import type { NextRequest } from "next/server";
import { whopsdk } from "@/lib/whop-sdk"; // your Whop SDK instance

export async function POST(request: NextRequest): Promise<Response> {
  const requestBodyText = await request.text();
  const headers = Object.fromEntries(request.headers);
  const webhookData = whopsdk.webhooks.unwrap(requestBodyText, { headers });

  if (webhookData.type === "payment.succeeded") {
    waitUntil(handlePaymentSucceeded(webhookData.data));
  }

  return new Response("OK", { status: 200 });
}

async function handlePaymentSucceeded(payment: Payment) {
  console.log("Payment succeeded:", payment.id);
}
Other useful webhook events: membership.went_valid (access granted), payment.failed (payment failed).

See it work end-to-end

The fastest way to confirm everything’s wired up is to run a test charge in sandbox and watch the result flow back to your server and dashboard.

1. Trigger a test charge

Switch your SDK and checkout to the sandbox environment, then run a checkout with a test card. The sandbox guide covers the URL changes and lists test cards for every payment outcome (succeeded, failed, requires action).

2. Inspect the webhook payload

When the test charge settles, your webhook handler receives a payment.succeeded event shaped like this:
{
  "id": "msg_xxxxxxxxxxxxx",
  "api_version": "v1",
  "type": "payment.succeeded",
  "timestamp": "2026-05-12T18:42:11.041Z",
  "company_id": "biz_xxxxxxxxxxxxx",
  "data": {
    "id": "pay_xxxxxxxxxxxxx",
    "status": "succeeded",
    "amount_after_fees": 9.71,
    "currency": "usd",
    "paid_at": "2026-05-12T18:42:10Z",
    "payment_method_type": "card",
    "card_brand": "visa",
    "card_last4": "4242",
    "member": { "id": "mem_xxxxxxxxxxxxx" },
    "metadata": {
      "order_id": "order_12345"
    }
  }
}
The metadata.order_id you attached when creating the checkout configuration flows straight through to the webhook handler. That’s the hook you use to map the payment back to your own order record.

3. Verify in the sandbox dashboard

Open the sandbox dashboard at https://sandbox.whop.com/dashboard/<your_company_id>/payments. The test charge appears in this payments list with its status and amount; use your server logs to confirm the metadata.order_id you set maps back to the same order. Sandbox dashboard Payments page showing the payments list If you see both the dashboard row and the payment.succeeded event on your server, the integration is live. Switch your SDK and webhook URL to production when ready.

Next steps

Webhooks

Handle payment events in real-time

Save payment methods

Save and charge payment methods

iOS payments

Accept payments in your iOS app with lower fees

Payment methods

100+ payment methods across 195 countries