> This page is for For Developers.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://whop.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://whop.ferndocs.com/_mcp/server.

# Save payment methods

> Save customer payment methods to charge them later

Use saved payment methods to charge customers automatically for subscriptions, renewals, or usage-based billing. The customer saves their card once using a Whop hosted or embedded flow, and you can charge it any time after.

> **Tip**
>
> Pair this guide with [webhooks](/developer/guides/webhooks): listen for `setup_intent.succeeded` to confirm the save, then for `payment.succeeded` / `payment.failed` to track future charges.

## Pick your save flow

Two paths, depending on whether the user is also paying right now.

|                           | Setup mode (collect-only)                                                                                                  | Save during checkout                                          |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| **Charges the user now?** | No                                                                                                                         | Yes                                                           |
| **Use case**              | Free trial signup, on-file card before usage-based billing                                                                 | Subscription that renews after the first paid checkout        |
| **API**                   | [Create checkout configuration](/api-reference/checkout-configurations/create-checkout-configuration) with `mode: "setup"` | Pass `setupFutureUsage: "off_session"` on `WhopCheckoutEmbed` |
| **Webhook to listen for** | `setup_intent.succeeded`                                                                                                   | `payment.succeeded` (the `payment_method` is on the result)   |

The rest of this page covers setup mode end-to-end, then shows how to charge a saved method later.

## Save a payment method

#### Create a checkout configuration in setup mode

[Create a checkout configuration](/api-reference/checkout-configurations/create-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.

**`TypeScript`**

```typescript TypeScript
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" },
});
```

**`Python`**

```python Python
checkout_configuration = whopsdk.checkout_configurations.create(
    company_id="biz_XXXXXX",
    mode="setup",
    redirect_url="https://mywebsite.com/return_location",
    metadata={"customer_id": "my_internal_user_id"},
)
```

**`Ruby`**

```ruby Ruby
checkout_configuration = whopsdk.checkout_configurations.create(
  company_id: "biz_XXXXXX",
  mode: "setup",
  redirect_url: "https://mywebsite.com/return_location",
  metadata: { customer_id: "my_internal_user_id" },
)
```

#### Direct the user to checkout

Use embedded checkout or redirect the user to save their payment method.

#### Embedded

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

export default function SavePayment() {
  return (
    <WhopCheckoutEmbed
      sessionId={checkoutConfiguration.id}
      returnUrl="https://yoursite.com/setup/complete"
      onComplete={(id) => {
        console.log("Payment method saved");
      }}
    />
  );
}
```

#### Redirect

```typescript
window.location.href = checkoutConfiguration.purchase_url;
```

#### 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.

> **Tip**
>
> The example uses `waitUntil` from `@vercel/functions` to run the handler after responding `200`. On other runtimes (Bun, Cloudflare Workers, Fastify, Hono) swap it for your framework's equivalent background-task primitive or a job queue. See the [webhooks guide](/developer/guides/webhooks) for Python and Ruby handler equivalents.

```typescript
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

#### Get the payment method

[List saved payment methods](/api-reference/payment-methods/list-payment-methods) for a member or use the payment method ID from the setup intent in the previous step.

**`TypeScript`**

```typescript TypeScript
const payment_methods = await whopsdk.paymentMethods.list({
  member_id: "mber_XXXXXXXX",
});

const payment_method = payment_methods.data[0];
```

**`Python`**

```python Python
payment_methods = whopsdk.payment_methods.list(member_id="mber_XXXXXXXX")
payment_method = payment_methods.data[0]
```

**`Ruby`**

```ruby Ruby
payment_methods = whopsdk.payment_methods.list(member_id: "mber_XXXXXXXX")
payment_method = payment_methods.data.first
```

#### Create an off-session payment

Charge the payment method without customer interaction. The [create payment endpoint](/api-reference/payments/create-payment) returns a payment object immediately and processes the charge asynchronously.

**`TypeScript`**

```typescript TypeScript
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);
```

**`Python`**

```python Python
payment = 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",
)

print("Payment:", payment.id)
```

**`Ruby`**

```ruby Ruby
payment = 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",
)

puts "Payment: #{payment.id}"
```

#### Handle payment events

Listen for payment webhooks to track success or failure.

```typescript
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 during checkout

To save a payment method while processing a payment, add `setupFutureUsage: "off_session"` to the embedded checkout.

```tsx
<WhopCheckoutEmbed
	planId="plan_XXXXXXXX"
	returnUrl="https://yoursite.com/checkout/complete"
	setupFutureUsage="off_session"
/>
```

The payment method will be saved after successful payment.

## Next steps

#### [Accept payments](/developer/guides/accept-payments)

One-time and subscription checkouts to pair with your save flow.

#### [Embedded checkout](/payments/checkout-embed)

Drop checkout into your own site without redirects.

#### [Listen to webhooks](/developer/guides/webhooks)

Track `setup_intent.succeeded`, `payment.succeeded`, and `payment.failed`.

#### [Billing portal](/payments-and-billing/manage-billing/billing-portal)

Let customers manage and remove their saved payment methods.