Stored Payment Methods
A stored payment method is a tokenized payment instrument — a card or bank account — saved in the payment provider's vault. AccruPay represents it as a PaymentMethod record linked to a customer identifier (merchantInternalCustomerCode) and a specific provider account. Once stored, you can charge it from your server at any time without involving the customer again.
Two ways to store a payment method
1. During a payment session
Set storePaymentMethod: true when you start a payment session. AccruPay automatically saves the instrument after a successful verify().
import AccruPay, { TRANSACTION_PROVIDER, CURRENCY, COUNTRY_ISO_2 } from '@accrupay/node';
const sdk = new AccruPay({ apiSecret: process.env.ACCRUPAY_API_SECRET });
const session = await sdk.transactions.clientSessions.payments.start({
transactionProvider: TRANSACTION_PROVIDER.YOUR_PROVIDER,
data: {
amount: 10000n,
currency: CURRENCY.USD,
merchantInternalCustomerCode: 'customer-123',
merchantInternalTransactionCode: 'txn-456',
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
storePaymentMethod: true,
},
});
// After the customer pays:
const transaction = await sdk.transactions.clientSessions.payments.verify({
id: session.id,
});
// transaction.paymentMethodId holds the saved PaymentMethod ID
2. Dedicated add-payment-method session
Save a card or bank account without charging anything. Useful for onboarding flows where you want to collect payment details before a purchase decision.
const session = await sdk.transactions.clientSessions.paymentMethod.add.start({
transactionProvider: TRANSACTION_PROVIDER.YOUR_PROVIDER,
data: {
currency: CURRENCY.USD,
merchantInternalCustomerCode: 'customer-123',
merchantInternalTransactionCode: 'add-pm-789',
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
},
});
// Customer fills in card details via the React SDK, then:
const result = await sdk.transactions.clientSessions.paymentMethod.add.verify({
id: session.id,
});
// result.id is the PaymentMethod ID
Charging a stored payment method
Once you have a PaymentMethod ID, charging it is a fully server-side operation — no frontend or customer interaction required.
const transaction = await sdk.transactions.payments.paymentMethod.charge({
transactionProvider: TRANSACTION_PROVIDER.YOUR_PROVIDER,
data: {
merchantCustomerPaymentMethodId: result.id,
amount: 10000n,
currency: CURRENCY.USD,
merchantInternalTransactionCode: 'charge-101',
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
},
});
PaymentMethod fields
Core fields
| Field | Type | Description |
|---|---|---|
id | string | AccruPay's stable identifier for this payment method. |
methodType | PAYMENT_METHOD | Enum: CARD, ACH, or OTHER. |
providerCode | string | The provider's internal token for this instrument. |
customerId | string | AccruPay customer ID. |
merchantInternalCustomerCode | string | Your own customer identifier, as supplied at save time. |
isDefault | boolean | Whether this is the customer's default payment method. |
isEnabled | boolean | Whether the method is currently usable for charges. |
expiresAt | Date | null | When the instrument expires (cards only). null for ACH. |
status | string | Provider-reported lifecycle status. |
paymentMethodInfo union
paymentMethodInfo holds instrument-specific details. Its shape depends on methodType:
CreditCardInfo — returned when methodType is CARD
{
cardBrand: string; // e.g. "VISA", "MASTERCARD"
cardNumberMasked: string; // e.g. "************4242"
expirationMonth: number; // 1–12
expirationYear: number; // four-digit year
}
AchInfo — returned when methodType is ACH
{
accountNumber: string; // masked account number
bankName: string;
routingNumber: string;
secCode: string; // e.g. "WEB", "CCD", "PPD"
}
GenericInfo — returned when methodType is OTHER
{} // no additional fields
Syncing with the provider
A stored card's status can change without any action on your part — for example, when a card network issues an updated card number or expiry. Call syncOne() to pull the latest state from the provider.
const updated = await sdk.paymentMethods.syncOne({
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
providerCode: paymentMethod.providerCode,
// customer is optional — include to scope by customer
customer: { merchantInternalCustomerCode: 'customer_abc' },
});
A stored payment method is scoped to the provider account where it was saved. It cannot be used across different provider accounts, even within the same AccruPay integration.
Common patterns
Default method selection. Query the customer's saved methods and filter for isDefault: true when you want to charge without asking the customer to pick.
Pre-charge validation. Check isEnabled: true and expiresAt before initiating a charge. An expired or disabled method will fail at the provider level; catching it early lets you prompt the customer to update their details.
Deduplication. merchantInternalCustomerCode is your join key — use the same value across sessions to group all payment methods for a given customer.