Photo by Yosuke Ota on Unsplash

On this page

This chapter follows Stripe API keys and the Node.js SDK.

Your app has users; Stripe has Customers. Link them once and reuse the Stripe id for Checkout, subscriptions, and saved cards. The examples store { appUserId, stripeCustomerId } in a Map—replace that with your database in production.

Create a Customer at signup

When someone registers, create a Customer in the same request flow (or immediately after):

store.js
/** @type {Map<string, { stripeCustomerId: string, email: string }>} */
export const usersById = new Map();
routes/signup.js
import { stripe } from '../stripe-client.js';
import { usersById } from '../store.js';
export async function signup(req, res) {
const { userId, email, name } = req.body;
const customer = await stripe.customers.create({
email,
name,
metadata: { appUserId: userId },
});
usersById.set(userId, { stripeCustomerId: customer.id, email });
res.status(201).json({ userId, stripeCustomerId: customer.id });
}

Store customer.id (for example cus_...) on your user record. If signup can retry, pass an idempotency key tied to userId.

Metadata and lookups

Metadata is key-value pairs on the Customer (up to 50 keys, string values). Use appUserId so Dashboard search and support tools match your database.

Retrieve or update later:

const customer = await stripe.customers.retrieve('cus_...');
await stripe.customers.update('cus_...', {
metadata: { plan: 'pro' },
});

List with a filter on metadata when debugging:

const list = await stripe.customers.list({ limit: 10, email: 'user@example.com' });

Prefer storing stripeCustomerId in your app as the primary join key; metadata is a backup for humans and scripts.

Saving payment methods with SetupIntents

A PaymentMethod represents a card or wallet. To save without charging, use a SetupIntent (or save during Checkout with setup_future_usage on a PaymentIntent—covered in payment chapters).

Server: create a SetupIntent for the Customer:

routes/setup-intent.js
import { stripe } from '../stripe-client.js';
import { usersById } from '../store.js';
export async function createSetupIntent(req, res) {
const { userId } = req.body;
const user = usersById.get(userId);
if (!user) return res.status(404).json({ error: 'Unknown user' });
const setupIntent = await stripe.setupIntents.create({
customer: user.stripeCustomerId,
automatic_payment_methods: { enabled: true },
});
res.json({ clientSecret: setupIntent.client_secret });
}

Browser: confirm with Stripe.js (same pattern as Payment Element—details in Custom payment forms with the Payment Element). After success, the PaymentMethod is attached to the Customer.

List saved methods:

const methods = await stripe.paymentMethods.list({
customer: user.stripeCustomerId,
type: 'card',
});

On-session versus off-session payments

On-session — The customer is present in your checkout UI and can complete 3D Secure or other authentication when the bank asks.

Off-session — You charge later without the customer in the flow (renewals, usage bills, background captures). The bank may still reject the charge if authentication is required and was not set up earlier.

When saving a card for off-session use, set usage: 'off_session' on the SetupIntent (or setup_future_usage: 'off_session' when creating a PaymentIntent). Off-session charges use payment_method and off_session: true on a PaymentIntent; failures with authentication_required should prompt the customer to return on-session.

await stripe.paymentIntents.create({
amount: 1500,
currency: 'usd',
customer: user.stripeCustomerId,
payment_method: savedPaymentMethodId,
off_session: true,
confirm: true,
});

Subscriptions and invoices handle much of this automatically; see Subscriptions in Stripe.

Default payment method and Customer Portal

Set invoice_settings.default_payment_method on the Customer so subscriptions and invoices pick the right card. The Customer Portal (configured in the Dashboard) lets customers update cards without custom UI—useful alongside Subscriptions in Stripe.

Next: Products and prices in Stripe.

Check your understanding

Question 1 of 5

0 of 5 checked

  1. 1. What should you persist on your user record after stripe.customers.create?

Search articles

Type a word to search published articles.

Open the search page