Saved cards

Tokenise a card during checkout, attach it to a customer, and charge it later without the payer present.

Borga can save a card at the end of a successful checkout. The card is tokenised by the processor, Borga stores only the token plus brand, last four digits and expiry, and the result is a PaymentMethod (pm_…) attached to a Customer (cus_…).

A saved card can then be charged off-session: subscriptions charge the customer's default card every period, and POST /v1/payments charges any saved card on demand.

Save a card during checkout

Create a customer, then a session with customer and save_payment_method: true. The session can charge a real amount for a purchase, or a small amount if you only want to collect the card.

Node.jsts
const customer = await borga.customers.create({
  email: "anna@example.is",
  name: "Anna Jónsdóttir",
});

const session = await borga.paymentSessions.create({
  amount: 2990,
  currency: "ISK",
  customer: customer.id,
  save_payment_method: true, // tokenise the card after this payment
  return_url: "https://yoursite.is/account/cards?saved=1",
  cancel_url: "https://yoursite.is/account/cards",
});

When the payment succeeds, Borga tokenises the card and sends payment_method.attached with the PaymentMethod as data. Store data.id if you need to refer to the card later. If you did not pass customer, Borga creates one from the email the payer typed at checkout.

Sessions with subscription save the card automatically; you do not need to set save_payment_method.

Manage saved cards

Node.jsts
const { data: cards } = await borga.paymentMethods.list({
  customer: "cus_8Jk2Lm4Np6Qr8St0Uv2Wx4Yz",
});

for (const pm of cards) {
  console.log(pm.id, pm.card?.brand, pm.card?.last4, pm.status);
}

// Choose which card subscriptions charge.
await borga.paymentMethods.setDefault(cards[0].id);

// Remove a card the customer no longer wants on file.
await borga.paymentMethods.detach(cards[1].id);
  • list returns the customer's active cards.
  • set_default chooses which card subscriptions charge. The first saved card becomes the default automatically.
  • detach removes a card. Detached cards cannot be charged again and stay visible with status: "detached" for your records.

A PaymentMethod's card object has brand, last4, exp_month, exp_year and wallet_type (apple_pay or google_pay when the card came from a wallet). Expired cards move to status: "expired".

Charge a saved card

Pass the card's id as payment_method when you create a payment. Borga charges it during the request and hands back the resulting payment; there is no checkout page and the payer does not need to be there.

Node.jsts
const { data: cards } = await borga.paymentMethods.list({
  customer: "cus_8Jk2Lm4Np6Qr8St0Uv2Wx4Yz",
});

const payment = await borga.payments.create(
  {
    amount: 2990,
    currency: "ISK",
    payment_method: cards[0].id,
    description: "Coffee subscription top-up",
    external_reference: "order_5678",
  },
  // Required. Reuse the same key if you retry: it replays this payment
  // instead of charging the card a second time.
  { idempotencyKey: "order_5678" },
);

if (payment.status === "processing") {
  // The processor has not answered yet. Leave it alone: the outcome
  // arrives as a payment.succeeded / payment.failed webhook.
  console.log(`${payment.id} is still settling`);
}

The Idempotency-Key is required, and it is what makes the call safe to retry: a repeat of the same request replays the original payment rather than charging the card again.

A declined card raises a payment_error (402) and records the payment as failed. If the outcome is not recorded by the time Borga replies, the payment comes back as processing and settles itself. Wait for the payment.succeeded or payment.failed webhook rather than polling or re-charging. Create a payment covers each outcome.

Charge only what your customer has agreed to. The mandate you collect when the card is saved is what makes a later charge legitimate; the card being on file is not consent on its own.

Security

Borga never sees the card number. The processor returns an opaque recurring token that is valid only for your merchant, and Borga stores it encrypted. Nothing in the API returns the token.