Skip to content

The Setup Intents API Fresh

Use the Setup Intents API to save a payment method for future payments. Like a PaymentIntent, but no charge is created — it's purely for collecting and validating payment details.

When to use SetupIntents

Use SetupIntents for businesses that collect payment details before charging:

  • Car rental companies — collect card before rental, charge after
  • Crowdfunding — collect cards now, charge only if campaign reaches goal
  • Utility companies — collect SEPA details before first monthly bill
  • SaaS trials — save card during free trial, charge when it ends

Create a SetupIntent

bash
curl https://api.stripe.com/v1/setup_intents \
  -u "sk_test_YOUR_KEY:" \
  -d "usage=off_session"
javascript
const setupIntent = await stripe.setupIntents.create({
  usage: 'off_session', // or 'on_session'
  customer: 'cus_123', // attach to a customer
});
// Return setupIntent.client_secret to client

The usage parameter

Specify how you plan to use the saved payment method — this affects the authentication flow:

UsageWhen to use
on_sessionWill show card to customer at future checkouts
off_sessionWill charge customer when they're not present (subscriptions, billing)

Setting off_session authenticates the card upfront for later charges. It creates more friction now but enables smoother off-session payments later.

bash
curl https://api.stripe.com/v1/setup_intents \
  -u "sk_test_YOUR_KEY:" \
  -d usage=on_session

Collect payment method on client

javascript
const stripe = Stripe('pk_test_YOUR_KEY');
const elements = stripe.elements({ clientSecret: setupIntent.client_secret });

const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');

// On form submit:
const { error, setupIntent } = await stripe.confirmSetup({
  elements,
  confirmParams: {
    return_url: 'https://example.com/setup-complete',
  },
});

Attach to a customer

Always attach setup intents to a Customer object so the payment method is reusable:

javascript
const customer = await stripe.customers.create({ email: 'user@example.com' });

const setupIntent = await stripe.setupIntents.create({
  customer: customer.id,
  usage: 'off_session',
});

After the customer completes the setup flow, the PaymentMethod is attached to the customer automatically.

Use the saved payment method

Once saved, charge the customer off-session:

javascript
const paymentIntent = await stripe.paymentIntents.create({
  amount: 2000,
  currency: 'usd',
  customer: 'cus_123',
  payment_method: 'pm_saved_method_id',
  off_session: true,
  confirm: true,
});

If the payment requires authentication (3DS), handle the error and bring the customer back on-session to authenticate.

Compliance requirements

You must get explicit customer consent before saving a payment method. Your terms of service must cover:

  • Permission to charge on the customer's behalf
  • Anticipated frequency of payments (one-time vs recurring)
  • How the payment amount is determined

For on-session use: include a "Save my payment method for future use" checkbox.
For off-session use: include mandate text explaining recurring/future charges.

SetupIntent statuses

StatusMeaning
requires_payment_methodWaiting for payment details
requires_confirmationReady to be confirmed
requires_actionCustomer authentication needed
processingStripe is verifying the payment method
succeededPayment method saved and verified
canceledSetup was canceled

Stripe API Reference - Self-contained docs reference, refreshed 2026-05-18