Save a customer's payment method for future payments
Use Fintoc's Checkout Session API to save a customer's payment method so their next payments take fewer steps.
Build a flow that saves a customer's payment method during a payment or through a standalone setup session.
For payment flows where customers pay often, like ride sharing or delivery apps, you can let your customers save a payment method for future payments. A saved payment method can be a card or a bank account, so their next payments take fewer steps.
You can save a customer's payment method in two ways:
- Save during a payment: create a Checkout Session with
flowset topaymentandsave_payment_methodset toenabled. Your customer gets the option to save the payment method for future payments. - Save without a current payment: create a Checkout Session with
flowset tosetupto enroll a payment method without processing a payment.
Option 1: Save during a payment (recommended)
The customer pays and their payment method is saved in a single step.
Create or choose a Customer
Every saved payment method must belong to a Customer. If you already have one, reuse its id. Otherwise, you can either create it first with the Customers API or send customer_data in the Checkout Session to create the Customer inline.
Server
curl --request POST "https://api.fintoc.com/v2/customers" \
--header "Authorization: YOUR_SECRET_API_KEY" \
--header "Content-Type: application/json" \
--data-raw '{
"name": "Felipe Castro",
"email": "[email protected]"
}'const { Fintoc } = require('fintoc');
const fintoc = new Fintoc('YOUR_SECRET_API_KEY');
const customer = await fintoc.customers.create({
name: 'Felipe Castro',
email: '[email protected]'
});from fintoc import Fintoc
client = Fintoc('YOUR_SECRET_API_KEY')
customer = client.customers.create(
name='Felipe Castro',
email='[email protected]'
)Fintoc responds with the created Customer:
{
"id": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"object": "customer",
"address": null,
"created_at": "2026-03-16T19:41:17Z",
"email": "[email protected]",
"metadata": {},
"mode": "live",
"name": "Felipe Castro",
"phone": null,
"tax_id": null,
"updated_at": "2026-03-16T19:41:17Z"
}Save the returned id (e.g. cus_3B2bODrQFje7ZVkT69xyaTSDwXQ).
If a Customer with the same tax_id already exists, the request returns a 409 Conflict error. To reuse an existing Customer, send its id in customer instead of customer_data.
Create a Checkout Session with save_payment_method
save_payment_methodCreate a Checkout Session with the customer ID, flow set to payment, and save_payment_method set to enabled. Fintoc processes the payment and, if your customer chooses to save the payment method during the flow, stores their credentials for future use.
Server
curl --request POST "https://api.fintoc.com/v2/checkout_sessions" \
--header "Authorization: YOUR_SECRET_API_KEY" \
--header "Content-Type: application/json" \
--data-raw '{
"flow": "payment",
"customer": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"amount": 5000,
"currency": "CLP",
"success_url": "https://merchant.com/success",
"cancel_url": "https://merchant.com/cancel",
"save_payment_method": "enabled",
"payment_method_types": ["bank_transfer"]
}'const { Fintoc } = require('fintoc');
const fintoc = new Fintoc('YOUR_SECRET_API_KEY');
const checkoutSession = await fintoc.checkoutSessions.create({
flow: 'payment',
customer: 'cus_3B2bODrQFje7ZVkT69xyaTSDwXQ',
amount: 5000,
currency: 'CLP',
success_url: 'https://merchant.com/success',
cancel_url: 'https://merchant.com/cancel',
save_payment_method: 'enabled',
payment_method_types: ['bank_transfer']
});from fintoc import Fintoc
client = Fintoc('YOUR_SECRET_API_KEY')
checkout_session = client.checkout_sessions.create(
flow='payment',
customer='cus_3B2bODrQFje7ZVkT69xyaTSDwXQ',
amount=5000,
currency='CLP',
success_url='https://merchant.com/success',
cancel_url='https://merchant.com/cancel',
save_payment_method='enabled',
payment_method_types=['bank_transfer']
)Fintoc responds with the created CheckoutSession, including its redirect_url:
{
"id": "cs_VvO7kpUMWlq2N10B",
"object": "checkout_session",
"flow": "payment",
"status": "created",
"amount": 5000,
"currency": "CLP",
"customer": {
"id": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"object": "customer",
"email": "[email protected]",
"metadata": {},
"name": "Felipe Castro",
"tax_id": null
},
"save_payment_method": "enabled",
"payment_method_types": ["bank_transfer"],
"success_url": "https://merchant.com/success",
"cancel_url": "https://merchant.com/cancel",
"redirect_url": "https://pay.fintoc.com/checkout/cs_VvO7kpUMWlq2N10B",
"metadata": {}
}| Parameter | Example | Description |
|---|---|---|
flow | payment | Required. Flow the session runs. One of payment, setup, or subscription. |
amount | 5000 | Required. A positive integer representing the amount to charge in the smallest currency unit. CLP has no minor unit, so 5000 charges $5000 CLP. |
currency | CLP | Required. Three-letter ISO 4217 currency code. Only CLP supports saving a payment method. |
success_url | https://merchant.com/success | Required. URL Fintoc redirects your customer to after a successful payment. |
cancel_url | https://merchant.com/cancel | Required. URL Fintoc redirects your customer to if they cancel the payment and return to your website. |
customer | "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ" | Required if no customer_data. ID of an existing Customer. |
customer_data | {"email": "[email protected]"} | Required if no If a |
metadata | {"order": "987654321"} | Set of key-value pairs you can attach to an object. Useful for storing additional information about the object in a structured format. |
payment_method_types | ["bank_transfer"] | Required. Payment method types available for the session. For the Only |
payment_method_options | bank_transfer object with sender_account information | Options for a specific payment method type, like preselecting a specific bank. See the complete example in the API Reference. |
save_payment_method | enabled | Whether your customer gets the option to save the payment method during the flow. One of enabled or disabled. Defaults to disabled. |
Redirect the customer
Use the redirect_url returned in the response to redirect your customer to the Fintoc-hosted page, where they complete the payment and can choose to save their credentials for future payments.
Client
window.location.assign(REDIRECT_URL_FROM_YOUR_BACKEND);Handle post-payment events
Always use webhooks to determine the final outcome. Your customer may close the tab, lose connection, or never reach your success_url.
Checkout Session events
-
checkout_session.finished: Sent when a Checkout Session reaches a final successful state. The event includes the payment outcome and, if your customer opted in, the savedpayment_method.Example
dataobject:{ "id": "cs_VvO7kpUMWlq2N10B", "flow": "payment", "mode": "test", "amount": 5000, "object": "checkout_session", "status": "finished", "currency": "CLP", "customer": { "id": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ", "mode": "test", "name": null, "email": "[email protected]", "phone": null, "object": "customer", "tax_id": { "type": "cl_rut", "value": "11.111.111-1" }, "address": null, "metadata": {}, "created_at": "2026-03-16T19:41:17Z" }, "metadata": {}, "cancel_url": "https://merchant.com/cancel", "created_at": "2026-03-30T20:47:41Z", "expires_at": "2026-03-31T20:47:41Z", "line_items": null, "success_url": "https://merchant.com/success", "redirect_url": "https://pay.fintoc.com/checkout/cs_VvO7kpUMWlq2N10B", "setup_intent": null, "subscription": null, "session_token": "cs_VvO7kpUMWlq2N10B_sec_UuSuPYRuEQTcWKXT6ba9LDTh", "customer_email": null, "payment_method": "pm_3BgHP7aSqsqLiEcotFQfyx7Of8u", "business_profile": null, "payment_resource": { "payment_intent": { "id": "pi_3BgHFvey4Qj4QZvTTZwyLL9OfSA", "mode": "test", "amount": 5000, "object": "payment_intent", "status": "succeeded", "currency": "CLP", "metadata": {}, "created_at": "2026-03-30T20:48:12Z", "expires_at": null, "next_action": null, "error_reason": null, "payment_type": "bank_transfer", "reference_id": "575930", "widget_token": null, "customer_email": null, "sender_account": { "type": "checking_account", "number": "19831940978", "holder_id": "11.111.111-1", "institution_id": "cl_banco_falabella" }, "business_profile": null, "transaction_date": "2026-03-30T20:49:00Z", "recipient_account": { "type": "checking_account", "number": "922358017", "holder_id": "11.111.111-1", "institution_id": "cl_banco_security" }, "payment_type_options": {} } }, "save_payment_method": "enabled", "payment_method_types": [ "bank_transfer" ], "payment_method_options": {} }
Payment Method events
If your customer chose to save the method, Fintoc also sends a payment_method.activated event. The event's data field contains a PaymentMethod like this:
{
"id": "pm_3BgHP7aSqsqLiEcotFQfyx7Of8u",
"object": "payment_method",
"card": null,
"created_at": "2026-03-30T20:49:12Z",
"customer": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"mode": "test",
"metadata": {},
"bank_transfer": {
"account_holder_id": "11.111.111-1",
"account_number": "19831940978",
"account_type": "checking_account",
"institution_id": "cl_banco_falabella",
"status": "active"
},
"type": "bank_transfer"
}Subscribe to the following post-session events:
| Event | Description | Recommended action |
|---|---|---|
checkout_session.finished | Session successfully completed. | Store customer + payment_method. Update your records based on the final status. |
checkout_session.expired | Session expired before completion. | Allow your customer to retry. |
payment_method.activated | Method becomes available for future charges. | Enable "pay with saved method" experiences for that customer. |
payment_intent.succeeded | Payment succeeded. | Fulfill the order. |
payment_intent.failed | Payment failed. | Ask your customer to retry or use another payment method. |
Option 2: Save a method without a current payment
Create a Setup session
The Checkout Session object represents your intent to save a payment method without processing a payment.
Using your Secret Key, create a Checkout Session from your backend with flow set to setup:
Server
curl --request POST "https://api.fintoc.com/v2/checkout_sessions" \
--header "Authorization: YOUR_SECRET_API_KEY" \
--header "Content-Type: application/json" \
--data-raw '{
"flow": "setup",
"currency": "CLP",
"success_url": "https://merchant.com/success",
"cancel_url": "https://merchant.com/cancel",
"customer_data": {
"email": "[email protected]"
},
"metadata": {}
}'const { Fintoc } = require('fintoc');
const fintoc = new Fintoc('YOUR_SECRET_API_KEY');
const checkoutSession = await fintoc.checkoutSessions.create({
flow: 'setup',
currency: 'CLP',
success_url: 'https://merchant.com/success',
cancel_url: 'https://merchant.com/cancel',
customer_data: {
email: '[email protected]'
},
metadata: {}
});from fintoc import Fintoc
client = Fintoc('YOUR_SECRET_API_KEY')
checkout_session = client.checkout_sessions.create(
flow='setup',
currency='CLP',
success_url='https://merchant.com/success',
cancel_url='https://merchant.com/cancel',
customer_data={
'email': '[email protected]'
},
metadata={}
)Fintoc responds with the created CheckoutSession, including its redirect_url:
{
"id": "cs_VvO7kpUMWlq2N10B",
"object": "checkout_session",
"flow": "setup",
"status": "created",
"currency": "CLP",
"customer": {
"id": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"object": "customer",
"email": "[email protected]",
"metadata": {},
"name": null,
"tax_id": null
},
"success_url": "https://merchant.com/success",
"cancel_url": "https://merchant.com/cancel",
"redirect_url": "https://pay.fintoc.com/checkout/cs_VvO7kpUMWlq2N10B",
"metadata": {}
}| Parameter | Example | Description |
|---|---|---|
flow | setup | Required. Flow the session runs. One of payment, setup, or subscription. |
currency | CLP | Required. Three-letter ISO 4217 currency code. Only CLP supports the setup flow. |
success_url | https://merchant.com/success | Required. URL Fintoc redirects your customer to after a successful setup. |
cancel_url | https://merchant.com/cancel | Required. URL Fintoc redirects your customer to if they cancel the setup and return to your website. |
customer | "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ" | Required if no customer_data. ID of an existing Customer. |
customer_data | {"email": "[email protected]"} | Required if no If a |
metadata | {"order": "987654321"} | Set of key-value pairs you can attach to an object. Useful for storing additional information about the object in a structured format. |
payment_method_types | ["pac", "direct_debit", "card"] | Payment method types available for the session. For the setup flow, one or more of pac, direct_debit, or card. Send this parameter if your customer already selected the method on your website. |
payment_method_options | pac object with sender_account information | Options for a specific payment method type, like preselecting a specific bank. See the complete example in the API Reference. |
Sendpayment_method_optionsto preselect a bank for your customerYou can create the Checkout Session with a specific bank by sending its
institution_idinside thesender_accountofpayment_method_options. Your customer can then only save a bank account of that institution. You can also send the customer's Chilean tax ID (RUT) as theholder_id, so the flow pre-fills it.We recommend this option when your customer selects their bank in your flow before you create the session, so they do not have to select a bank twice.
Redirect the customer
After creating a session, you receive a redirect_url that you use to redirect your customer so they can enroll their bank account as a saved payment method.
Client
window.location.assign(REDIRECT_URL_FROM_YOUR_BACKEND);
Handle post-session events
Subscribe to checkout_session.finished, checkout_session.expired, and payment_method.activated for the standalone setup flow.
Create a payment session with a saved payment method
If your customer has a saved bank_transfer payment method, you can create a payment Checkout Session that uses the saved method. Fintoc redirects your customer directly to the bank approval step, without asking them to log in with their bank credentials.
Server
curl --request POST "https://api.fintoc.com/v2/checkout_sessions" \
--header "Authorization: YOUR_SECRET_API_KEY" \
--header "Content-Type: application/json" \
--data-raw '{
"amount": 100000,
"currency": "CLP",
"flow": "payment",
"success_url": "https://merchant.com/success",
"cancel_url": "https://merchant.com/cancel",
"customer": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"payment_method": "pm_1NkL7QKs215JZ1LyW4c1m9Ut",
"payment_method_types": [
"bank_transfer"
]
}'const { Fintoc } = require('fintoc');
const fintoc = new Fintoc('YOUR_SECRET_API_KEY');
const checkoutSession = await fintoc.checkoutSessions.create({
amount: 100000,
currency: 'CLP',
flow: 'payment',
success_url: 'https://merchant.com/success',
cancel_url: 'https://merchant.com/cancel',
customer: 'cus_3B2bODrQFje7ZVkT69xyaTSDwXQ',
payment_method: 'pm_1NkL7QKs215JZ1LyW4c1m9Ut',
payment_method_types: ['bank_transfer']
});from fintoc import Fintoc
client = Fintoc('YOUR_SECRET_API_KEY')
checkout_session = client.checkout_sessions.create(
amount=100000,
currency='CLP',
flow='payment',
success_url='https://merchant.com/success',
cancel_url='https://merchant.com/cancel',
customer='cus_3B2bODrQFje7ZVkT69xyaTSDwXQ',
payment_method='pm_1NkL7QKs215JZ1LyW4c1m9Ut',
payment_method_types=['bank_transfer']
)Fintoc responds with the created CheckoutSession, including its redirect_url:
{
"id": "cs_VvO7kpUMWlq2N10B",
"object": "checkout_session",
"flow": "payment",
"status": "created",
"amount": 100000,
"currency": "CLP",
"customer": {
"id": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"object": "customer",
"email": "[email protected]",
"metadata": {},
"name": "Felipe Castro",
"tax_id": null
},
"payment_method": "pm_1NkL7QKs215JZ1LyW4c1m9Ut",
"payment_method_types": ["bank_transfer"],
"success_url": "https://merchant.com/success",
"cancel_url": "https://merchant.com/cancel",
"redirect_url": "https://pay.fintoc.com/checkout/cs_VvO7kpUMWlq2N10B",
"metadata": {}
}Redirect the customer
Use the redirect_url to redirect your customer to the Fintoc-hosted page, where they go directly to the bank approval step without logging in with their bank credentials.
Client
window.location.assign(REDIRECT_URL_FROM_YOUR_BACKEND);Handle post-payment events
After the payment, Fintoc sends checkout_session.finished, checkout_session.expired, payment_intent.succeeded, or payment_intent.failed, depending on the outcome:
| Event | Description | Recommended action |
|---|---|---|
checkout_session.finished | Session successfully completed. | Store customer + payment_method. Update your records based on the final status. |
checkout_session.expired | Session expired before completion. | Allow your customer to retry. |
payment_intent.succeeded | Payment succeeded. | Fulfill the order. |
payment_intent.failed | Payment failed. | Ask your customer to retry or use another payment method. |
Test your integration
Using your test mode API Secret Key, you can create Checkout Sessions that simulate successful and failed outcomes without moving any money.
This lets you validate your full setup and payment flow end-to-end:
- Your backend API requests (creating sessions and handling responses)
- The redirect flow from your frontend to the
redirect_urland back to thesuccess_urlorcancel_urlafter the setup or payment - The webhooks for post-session events that save the
customer, thepayment_method, and the payment result- After a successful setup or payment that saves a
payment_method, test creating a payment session with the customer's saved method
- After a successful setup or payment that saves a
To learn how to trigger specific scenarios, use the test credentials and special test values described in our testing guide.
For a bank_transfer flow in test mode, open the redirect_url, select the test bank, and log in with the test credentials user_good and pass_good. This combination simulates a successful enrollment and payment.
After a successful run, Fintoc sends a checkout_session.finished event with status set to finished:
{
"id": "cs_VvO7kpUMWlq2N10B",
"object": "checkout_session",
"flow": "payment",
"mode": "test",
"status": "finished",
"customer": {
"id": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"object": "customer",
"email": "[email protected]",
"metadata": {},
"name": "Felipe Castro",
"tax_id": null
},
"payment_method": "pm_3BgHP7aSqsqLiEcotFQfyx7Of8u"
}If your customer opted in, Fintoc also sends a payment_method.activated event with status set to active:
{
"id": "pm_3BgHP7aSqsqLiEcotFQfyx7Of8u",
"object": "payment_method",
"customer": "cus_3B2bODrQFje7ZVkT69xyaTSDwXQ",
"mode": "test",
"type": "bank_transfer",
"bank_transfer": {
"account_holder_id": "11.111.111-1",
"account_number": "19831940978",
"account_type": "checking_account",
"institution_id": "cl_banco_falabella",
"status": "active"
}
}