Customers & stored methods

Represent buyers and securely store their payment methods for reuse.

View as MarkdownInstall skills

A customer object groups one buyer's identity, billing details, payment history, and any payment methods they've saved with you. Storing a method once lets you charge it again later — for one-click checkout, subscriptions, and loyalty payouts — without ever touching raw card data.

The customer objectAsk

A customer is a long-lived record keyed by cust_. Create one when a buyer first registers or completes their first purchase, then reuse the same ID forever.

import { Vinr } from '@vinr/sdk';

const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

const customer = await vinr.customers.create({
  email: 'ada@example.com',
  name: 'Ada Lovelace',
  metadata: { internalId: 'user_8821' },
});

// customer.id → "cust_9Kp2v..."

Prop

Type

Look customers up by your own key with vinr.customers.list({ email }) or by storing your user ID in metadata. Avoid creating duplicate customers for the same buyer — stored methods do not transfer between them.

Saving a payment methodAsk

Raw card numbers never reach your server. The customer enters details on a VINR-hosted surface, VINR vaults them, and you receive a method token (pm_) attached to the customer. The simplest path is to run a setup flow.

const setup = await vinr.customers.setupMethod({
  customerId: customer.id,
  returnUrl: 'https://yoursite.com/wallet/saved',
});

// Redirect the buyer to setup.checkoutUrl to enter and verify their card.
// On return, the verified method is attached to the customer.

You can also save the method used during a normal payment by passing savePaymentMethod: true when you create the payment. Either way, the stored method captures only what's needed to reuse it — brand, last four digits, and expiry — never the full PAN.

In sandbox, drive these flows with the test cards: 4242 4242 4242 4242 succeeds, 4000 0000 0000 0002 is declined, and 4000 0000 0000 3220 forces a 3DS challenge so you can exercise the authentication path.

Reusing stored methodsAsk

Once a method is attached, charge it server-side with no buyer interaction by referencing the customer and method on a new payment.

const payment = await vinr.payments.create({
  amount: 2500,                 // €25.00
  currency: 'EUR',
  customerId: customer.id,
  paymentMethodId: 'pm_4Tz9q...',  // omit to use the customer's default
  offSession: true,             // buyer is not present
  description: 'Order #4471',
});

offSession: true signals that the buyer isn't in the checkout flow. Some cards still require a fresh authentication — when that happens the payment returns status requires_action rather than completing, and you should fall back to an on-session flow. See authentication & 3DS for handling that branch.

Updating, listing & detachingAsk

Manage the methods on a customer without recreating the customer.

Set a default

await vinr.customers.update(customer.id, {
  defaultMethodId: 'pm_4Tz9q...',
});

List saved methods

const methods = await vinr.customers.listMethods(customer.id);
// → [{ id: 'pm_4Tz9q...', brand: 'visa', last4: '4242', expMonth: 12, expYear: 2028 }]

Detach a method

await vinr.customers.detachMethod(customer.id, 'pm_4Tz9q...');

Detaching is immediate and irreversible — the token can no longer be charged. Detach a method as soon as a buyer removes a card from their wallet, and prompt for a new one before their stored card's expYear passes.

Listen for payment_method.expiring to email buyers before a saved card lapses, and payment_method.updated when a network auto-updater refreshes a card on file. Verify every event with vinr.webhooks.verify(payload, signature) using the x-vinr-signature header.

Shared with Billing & EngagementAsk

The customer is a single object across all three pillars. A method saved during a one-off payment is the same method a subscription bills against each cycle, and the customer's id is what links a buyer to their loyalty account so points earned at checkout map to the right person. Store the buyer once, reuse everywhere.

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page