Skip to main content
Use saved payment methods to charge customers automatically for subscriptions, renewals, or usage-based billing without requiring them to enter their card details again. The customer can vault their payment method once using a Whop hosted or embedded flow, and you can bill them at any point in time.

Save a payment method

1

Create a checkout configuration in setup mode

Create a checkout configuration without a plan to collect payment details without charging. Add metadata to be able to link the member and payment method to a customer in your system.
const checkoutConfiguration = await whopsdk.checkoutConfigurations.create({
  	company_id: "biz_XXXXXX",
  	mode: "setup",
  	redirect_url: "https://mywebsite.com/return_location",
  	metadata: { "customer_id": "my_internal_user_id" }
});
2

Direct the user to checkout

Use embedded checkout or redirect the user to save their payment method.
  • Embedded
  • Redirect
import { WhopCheckoutEmbed } from "@whop/checkout/react";

export default function SavePayment() {
  return (
    <WhopCheckoutEmbed
      sessionId={checkoutConfiguration.id}
      onComplete={(id) => {
        console.log("Payment method saved");
      }}
    />
  );
}
3

Handle completion

Listen for the setup_intent.succeeded webhook to get the payment method ID. The CheckoutConfiguration and its metadata will be included on the SetupIntent, which you can use to link the member and payment method to a customer in your system.
import { waitUntil } from "@vercel/functions";
import type { NextRequest } from "next/server";
import { whopsdk } from "@/lib/whop-sdk";

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 === "setup_intent.succeeded") {
    waitUntil(handleSetupSucceeded(webhookData.data));
  }

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

async function handleSetupSucceeded(setupIntent) {
  console.log("Payment method ID:", setupIntent.payment_method.id);
  console.log("Member ID:", setupIntent.member.id);
  console.log("Metadata:", setupIntent.metadata);
}
The payment method is now saved and authorized for this member.

Charge a saved payment method

1

Get the payment method

List saved payment methods for a member or use the payment method ID from the setup intent in the previous step.
const payment_methods = await whopsdk.paymentMethods.list({
  member_id: "mber_XXXXXXXX",
});

const payment_method = payment_methods.data[0];
2

Create an off-session payment

Charge the payment method without customer interaction. The create payment endpoint will respond with a payment object immediately, but the payment will be processed asynchronously in the background.
const payment = await whopsdk.payments.create({
  plan: { initial_price: 40.00, currency: "usd", plan_type: "one_time" },
  company_id: "biz_XXXXXXXX",
  member_id: "mber_XXXXXXXX",
  payment_method_id: "payt_XXXXXXXXX",
});

console.log("Payment:", payment.id);
3

Handle payment events

Listen for payment webhooks to track success or failure.
if (webhookData.type === "payment.succeeded") {
  await fulfillOrder(webhookData.data);
}

if (webhookData.type === "payment.failed") {
  await notifyCustomer(webhookData.data.member.email, webhookData.data.failure_message);
}

Save while charging

To save a payment method during checkout, add setupFutureUsage: "off_session" to the embedded checkout.
<WhopCheckoutEmbed planId="plan_XXXXXXXX" setupFutureUsage="off_session" />
The payment method will be saved after successful payment.