- Save the card. A customer completes a checkout, and Bachs keeps their card against their customer record.
- Charge it. Days or months later, you call
POST /v1/chargeswith that customer and an amount.
Saving and charging cards this way is in beta. The behavior below might change, including field names and the shape of the response. Pin your integration to what you test, and check back before you rely on it in production.
If you want Bachs to run the billing cycle for you, use Subscriptions instead. This guide is for when you decide what to charge and when.
Your side of keeping a card
Storing a customer’s card and charging it later carries obligations that are yours, not ours.- Tell them, and let them agree. Card network rules require the cardholder’s consent to store their card for later use. Our checkout page states this on the card form, but your own terms, and how you present the choice, are yours to get right.
- Say what you will charge and when. A customer who agreed to one amount has not agreed to any amount. Be specific about what you will bill and how often.
- Let them stop it. Give them a way to remove a saved card and to cancel whatever it is paying for.
Before you start
- A sandbox API key (
sk_sandbox_...) with thepayments:writepermission. See Authentication and Permissions. - A webhook endpoint to receive the result. See Set up webhooks.
Steps
1
Create the customer
A saved card belongs to a customer, and charging it later names that customer by id. Create them first, and keep the Already have the customer? Reuse their id and skip this step. See the customer object.
cust_ id: you will use it twice.2
Save the card during a checkout
You have two ways to save a card, and they differ only in whether the customer pays at the same time.Send the customer to the
- Save without charging
- Save while they pay
Send
save_payment_method with a customer and no price. The checkout collects a card, charges nothing, and saves it. Use this when a customer signs up before they owe you anything.checkout_url either way. See Accept a payment with Checkout for the full checkout flow.3
Wait for the card to be saved
The card is saved when the customer finishes the checkout, not when you create it. Bachs sends Store the
payment_method.saved when the card is ready to charge.payment_method.saved
pm_ id against your own record of the customer. You can charge without it, but then you are charging whichever card is their default, and you cannot show them which card you are about to bill.is_default tells you whether this is the card a charge picks when you name none. The first card a customer saves becomes their default.4
Charge the saved card
Call
POST /v1/charges with the customer and an amount. There is no checkout and no page for the customer to visit.amount is what the card is charged. It is larger than the 29.00 you asked for because this account passes the processing fee to the customer. On an account that absorbs the fee, the card is charged 29.00 and you settle less. See Fees.Leave payment_method out and Bachs charges the customer’s default saved card.5
Confirm the outcome with a webhook
The charge comes back If the card is refused you get
processing, which means the card has been submitted and nobody has told us yet whether it worked. The answer arrives as a webhook.collection.succeeded
collection.failed instead, and the charge ends at failed with amount_paid still "0.00". No money moved and nothing is owed.Charging in a currency the card does not use
You do not have to bill in the currency the card was saved in. Ask for the amount you are owed and Bachs converts it. Say a customer saved a card that bills inUSD, and you invoice in NGN:
45000.00 NGN into USD at the prevailing rate and charges the card that amount. currency is the currency you are owed and settle in; the card is billed in its own. This is the same conversion a normal checkout does when a customer pays you in their currency.
A declined card is an answer, not an error
POST /v1/charges always answers with a charge. A refused card is an outcome you read from status, never an exception you catch.
A refused card returns 201 with a charge like this:
Refused card
status, and do not rely on the request raising.
Most charges come back processing and settle a few seconds later. Some come back already failed, when the card is refused while your request is still open. Both are normal, and both are the same response shape, so read status rather than assuming which one you got.
Retrying a failed charge
A failed charge is final. To try again, create a new charge with a newIdempotency-Key.
Before you retry, consider why it failed. A card refused for insufficient funds may work in three days; a card refused because it expired will never work, and the customer has to save a new one. Send them to a new checkout that saves a card to replace it.
Test it in the sandbox
The sandbox takes test cards, so you can run the whole flow, save a card and charge it, without moving real money.
Any future expiry date and any CVC work.
The second one is worth spending time on. A card that saves and then fails is the case most integrations get wrong, because it only goes wrong long after the customer has gone.
Errors
These are refusals at the request itself, before any card is charged. They are the ones worth handling.Next steps
- The payment object for every field on a charge
- Set up webhooks to receive
payment_method.saved,collection.succeededandcollection.failed - Idempotency for safe retries
- Subscriptions if you want Bachs to run the billing cycle
- Refunds to return money from a charge

