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 clientThe usage parameter
Specify how you plan to use the saved payment method — this affects the authentication flow:
| Usage | When to use |
|---|---|
on_session | Will show card to customer at future checkouts |
off_session | Will 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_sessionCollect 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
| Status | Meaning |
|---|---|
requires_payment_method | Waiting for payment details |
requires_confirmation | Ready to be confirmed |
requires_action | Customer authentication needed |
processing | Stripe is verifying the payment method |
succeeded | Payment method saved and verified |
canceled | Setup was canceled |