Collecting Payments

First, create the charge on the server using the Whop API. Then you can either:
  1. Open a modal in your app using the iframe SDK (recommended)
  2. Redirect the user to Whop’s checkout page

1. Create the charge on the server

This step will create a charge on the server and return the inAppPurchase object required for the next step.
On the server, use the chargeUser method to create a charge:
app/api/charge/route.ts
import { whopSdk } from "@/lib/whop-sdk";

export async function POST(request: Request) {
  try {
    const { userId, experienceId } = await request.json();

    const result = await whopSdk.payments.chargeUser({
      amount: 100,
      currency: "usd",
      userId: userId,
      // metadata is information that you'd like to receive later about the payment.
      metadata: {
        creditsToPurchase: 1,
        experienceId: experienceId,
      },
    });

    if (!result?.inAppPurchase) {
      throw new Error("Failed to create charge");
    }

    return Response.json(result.inAppPurchase);
  } catch (error) {
    console.error("Error creating charge:", error);
    return Response.json({ error: "Failed to create charge" }, { status: 500 });
  }
}

2. Confirm the payment on the client

In this step the user will be prompted to confirm the previously created charge in a modal.
This function requires the iFrame SDK to be initialized. See iFrame Overview for more information.
Use the iframe SDK to open a payment modal:
"use client";
import { useIframeSdk } from "@whop/react";

export default function PaymentButton({
  userId,
  experienceId,
}: {
  userId: string;
  experienceId: string;
}) {
  const iframeSdk = useIframeSdk();
  
  const [receiptId, setReceiptId] = useState<string>();
  const [error, setError] = useState<string>();
  
  async function handlePurchase() {
    try {
      // 1. Create charge on server
      const response = await fetch("/api/charge", {
        method: "POST",
        body: JSON.stringify({ userId, experienceId }),
      });
      
      if (response.ok) {
        const inAppPurchase = await response.json();
        // 2. Open payment modal
        const res = await iframeSdk.inAppPurchase(inAppPurchase);
        
        if (res.status === "ok") {
          setReceiptId(res.data.receipt_id);
          setError(undefined);
        } else {
          setReceiptId(undefined);
          setError(res.error);
        }
      } else {
        throw new Error("Failed to create charge");
      }
    } catch (error) {
      console.error("Purchase failed:", error);
      setError("Purchase failed");
    }
  }
  
  return <button onClick={handlePurchase}>Purchase Plan</button>;
}

3. Validate the payment

After a payment is processed, you should validate it on your server using webhooks to ensure the payment was successful and update your application accordingly.
Set up a webhook route to handle payment events:
app/api/webhook/route.ts
import { makeWebhookValidator, type PaymentWebhookData } from "@whop/api";
import { after } from "next/server";

const validateWebhook = makeWebhookValidator({
  webhookSecret: process.env.WHOP_WEBHOOK_SECRET,
});

export async function POST(request: Request) {
  // Validate the webhook to ensure it's from Whop
  const webhook = await validateWebhook(request);

  // Handle the webhook event
  if (webhook.action === "payment.succeeded") {
    after(handlePaymentSucceededWebhook(webhook.data));
  }

  // Make sure to return a 2xx status code quickly. Otherwise the webhook will be retried.
  return new Response("OK", { status: 200 });
}

async function handlePaymentSucceededWebhook(data: PaymentWebhookData) {
  const { id, user_id, subtotal, amount_after_fees, metadata, ... } = data;

  // ...
}
Make sure to create a webhook in your dashboard app settings and set your WHOP_WEBHOOK_SECRET environment variable.
Webhook Configuration

Sending Payouts

You can send payouts to any user using their Whop username. The funds will be transferred from your company’s ledger account.

Transfer Funds

import { whopSdk } from "@/lib/whop-sdk";

async function sendPayout(
  companyId: string,
  recipientUsername: string,
  amount: number
) {
  // 1. Get your company's ledger account
  const experience = await whopSdk.experiences.getExperience({ experienceId });
  const companyId = experience.company.id;
  const ledgerAccount = await whopSdk.companies.getCompanyLedgerAccount({
    companyId,
  });

  // 2. Pay the recipient
  await whopSdk.payments.payUser({
    amount: amount,
    currency: "usd",
    // Username or ID or ledger account ID of the recipient user
    destinationId: recipientUsername,
    // Your company's ledger account ID that can be retrieve from whopSdk.companies.getCompanyLedgerAccount()
    ledgerAccountId: ledgerAccount.company?.ledgerAccount.id!,
    // Optional transfer fee in percentage
    transferFee: ledgerAccount.company?.ledgerAccount.transferFee,
  });
}