Charge a Stored Card
Once a card is saved, you can charge it entirely server-side — no frontend session or checkout form required.
When to use this flow:
- Recurring billing and subscription renewals
- Scheduled charges (e.g. usage-based billing run overnight)
- Re-order or one-click purchase flows where the customer does not re-enter card details
For flows where the customer needs to enter card details, use Card Checkout instead.
Prerequisite
You need a merchantCustomerPaymentMethodId — the ID of a stored payment method obtained from a previous payment or add-card session. See Save a Card for how to obtain one.
Charge the stored card
import AccruPay, { CURRENCY, COUNTRY_ISO_2, TRANSACTION_STATUS } from '@accrupay/node';
const sdk = new AccruPay({
apiSecret: process.env.ACCRUPAY_API_SECRET!,
});
export async function chargeStoredCard(
paymentMethodId: string,
transactionCode: string,
) {
const transaction = await sdk.transactions.payments.paymentMethod.charge({
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
data: {
merchantCustomerPaymentMethodId: paymentMethodId,
merchantInternalTransactionCode: transactionCode,
amount: 10000n, // $100.00
currency: CURRENCY.USD,
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
},
});
return transaction;
}
Amounts are bigint in the smallest currency unit. 10000n = $100.00.
Handle the response
charge() returns a MerchantTransaction directly — there is no session to verify separately. Check transaction.status before fulfilling.
import { TRANSACTION_STATUS } from '@accrupay/node';
const transaction = await chargeStoredCard('pm_abc123', `charge_${Date.now()}`);
switch (transaction.status) {
case TRANSACTION_STATUS.SUCCEEDED:
// Charge captured — fulfill the order
await fulfillOrder(transaction);
break;
case TRANSACTION_STATUS.DECLINED:
// Card declined — notify the customer to update their payment method
await notifyPaymentDeclined(transaction);
break;
case TRANSACTION_STATUS.PENDING:
// Still processing — wait for a webhook or poll
await markChargePending(transaction);
break;
case TRANSACTION_STATUS.FAILED:
case TRANSACTION_STATUS.ERROR:
// Technical failure — retry with exponential backoff or alert your team
throw new Error(`Charge failed with status: ${transaction.status}`);
default:
throw new Error(`Unexpected charge status: ${transaction.status}`);
}
Server-side charges can still fail or be declined. Never assume a charge succeeded because the API call returned without throwing. transaction.status is the authoritative result.
Status reference
| Status | Meaning | Action |
|---|---|---|
SUCCEEDED | Charge captured | Fulfill the order |
DECLINED | Declined by issuer | Notify customer to update payment method |
PENDING | Still processing | Wait for webhook or poll |
FAILED | Terminal failure | Retry or alert |
ERROR | Technical error | Retry or alert |
CANCELED | Charge was canceled | Investigate and restart if needed |
UNKNOWN | Status undetermined | Contact support |