Save a payment method for future charges

Save a customer's payment method once and charge it later for on-demand or variable-amount payments, without creating a recurring subscription.

Unlike the subscription flow, the setup flow does not couple enrollment with recurring billing, so you decide when and how much to charge.

Set up a payment method and charge it later in four steps:

  1. On your backend, create a Checkout Session with flow: setup.
  2. Redirect your customer to complete the enrollment at the Fintoc-hosted checkout page.
  3. Handle post-session events to save the payment_method and customer.
  4. Create charges against the saved payment method using the Payment Intent API.

The following diagram shows how the setup flow works:


Create a Checkout Session

The Checkout Session with the setup flow represents your intent to save a payment method for future charges, without creating a recurring subscription.

Using your Secret Key, create a Checkout Session on 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": {
      "tax_id": {
        "type": "cl_rut",
        "value": "11.111.111-1"
      },
      "name": "Felipe Castro",
      "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: {
    tax_id: {
      type: 'cl_rut',
      value: '11.111.111-1'
    },
    name: 'Felipe Castro',
    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={
        'tax_id': {
            'type': 'cl_rut',
            'value': '11.111.111-1'
        },
        'name': 'Felipe Castro',
        'email': '[email protected]'
    },
    metadata={}
)

After creating the Checkout Session, Fintoc responds with the session details and a redirect_url:

{
  "id": "cs_li5531onlFDi235",
  "object": "checkout_session",
  "flow": "setup",
  "status": "created",
  "currency": "CLP",
  "customer": {
    "id": "cus_NffrFeUfNV2Hib",
    "object": "customer",
    "email": "[email protected]",
    "metadata": {},
    "name": "Felipe Castro",
    "tax_id": {
      "type": "cl_rut",
      "value": "11.111.111-1"
    }
  },
  "success_url": "https://merchant.com/success",
  "cancel_url": "https://merchant.com/cancel",
  "redirect_url": "https://pay.fintoc.com/checkout/cs_li5531onlFDi235",
  "metadata": {}
}
ParameterExampleDescription
flowsetupRequired. Flow type for the session. One of payment, setup, or subscription. Use setup to save a payment method without charging.
currencyCLPRequired. Three-letter ISO 4217 currency code. One of CLP or MXN.
success_urlhttps://merchant.com/successRequired. URL to redirect the customer after a successful enrollment.
cancel_urlhttps://merchant.com/cancelRequired. URL to redirect the customer if they cancel the enrollment.
payment_method_types["pac"]Payment methods available for the enrollment. One or more of pac (Chilean direct debit), direct_debit (Mexico), or card.
customercus_3B2bODrQFje7ZVkT69xyaTSDwXQRequired if no customer_data. ID of an existing Customer.
customer_data{ tax_id: {...}, ... }Required if no customer. Data for inline customer creation. Send at least one of email or tax_id. 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.
payment_method_options{ pac: { ... } }Options specific to each payment method, keyed by payment method type. Keys match the values in payment_method_types (for example, pac).
metadata{ "order": "987654321" }Set of key-value pairs for storing additional information.
📘

Difference from the subscription flow

When you create a Checkout Session with flow: setup, Fintoc enrolls the customer's payment method and creates a PaymentMethod, but does not create a subscription or schedule any recurring charges. You control when and how much to charge by creating future payment intents.

Include customer data

When creating a Checkout Session for setup, you must include customer information.

AttributeTypeDescription
tax_idobjectRequired if no email. Object that identifies the customer at a fiscal or regulatory level. The type is one of cl_rut (Chilean tax ID, RUT) or mx_rfc (Mexican tax ID, RFC), and value is the tax identifier as a string. See the Customer object. 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.
namestringFull name of the customer.
emailstringRequired if no tax_id. Email used to notify the customer about the enrollment and charges.
metadataobjectSet of key-value pairs for storing additional information.

Redirect the customer to complete the enrollment

Next, redirect the customer to the redirect_url from the response. The customer sees the Fintoc-hosted checkout page where they complete the enrollment.

After the customer completes the enrollment, Fintoc automatically redirects them to your success_url or cancel_url, depending on the outcome.

Client

window.location.assign(REDIRECT_URL_FROM_YOUR_BACKEND);

Handle post-session events

Always use webhooks to determine the final outcome. Customers may close the tab, lose connection, or never reach your success_url.

Checkout Session events

When the enrollment completes, Fintoc sends a checkout_session.finished event with the customer and payment_method information:

{
  "id": "evt_a4xK32BanKWYn",
  "object": "event",
  "type": "checkout_session.finished",
  "data": {
    "id": "cs_li5531onlFDi235",
    "object": "checkout_session",
    "mode": "live",
    "flow": "setup",
    "status": "finished",
    "currency": "CLP",
    "customer": {
      "id": "cus_NffrFeUfNV2Hib",
      "name": "Felipe Castro",
      "email": "[email protected]",
      "tax_id": {
        "type": "cl_rut",
        "value": "11.111.111-1"
      }
    },
    "payment_method": "pm_NffrFeUfNV2Hib",
    "metadata": {},
    "success_url": "https://merchant.com/success",
    "cancel_url": "https://merchant.com/cancel"
  }
}

Payment Method events

Fintoc also sends a payment_method.activated event. The event's data field contains a PaymentMethod like this:

{
  "id": "pm_NffrFeUfNV2Hib",
  "object": "payment_method",
  "card": null, 
  "created_at": "2021-10-15T15:22:11.474Z",
  "customer": "cus_NffrFeUfNV2Hib",
  "mode": "live",
  "metadata": {},
  "pac": {
    "account_holder_id": "11.111.111-1",
    "account_number": "19831940978",
    "account_type": "checking_account",
    "institution": {
      "id": "cl_banco_falabella",
      "country": "cl",
      "name": "Banco Falabella"
    },
    "status": "active"
  },
  "type": "pac"
}

Store both the customer ID and the payment_method ID. You need them to create charges later.

Events summary

You should subscribe to all the following post-session events:

EventDescriptionRecommended action
checkout_session.finishedSession successfully completed. Method enrolled.Store customer + payment_method.
checkout_session.expiredSession expired before the customer completed enrollment.Allow the customer to retry.
payment_method.activatedPayment method is active and ready for charges.Create charges against this method when needed.
payment_method.canceledPayment method is canceled and not available for charges.Stop creating charges against the method.

Create a charge against the saved payment method

Once you have a saved payment_method, charge it by creating a Payment Intent with the payment_method and customer IDs:

Server

curl --request POST "https://api.fintoc.com/v2/payment_intents" \
  --header "Authorization: YOUR_SECRET_API_KEY" \
  --header "Content-Type: application/json" \
  --data-raw '{
    "amount": 150000,
    "currency": "CLP",
    "customer": "cus_NffrFeUfNV2Hib",
    "payment_method": "pm_NffrFeUfNV2Hib",
    "metadata": {
      "order_id": "order_98765"
    }
  }'
const { Fintoc } = require('fintoc');

const fintoc = new Fintoc('YOUR_SECRET_API_KEY');

const paymentIntent = await fintoc.paymentIntents.create({
  amount: 150000,
  currency: 'CLP',
  customer: 'cus_NffrFeUfNV2Hib',
  payment_method: 'pm_NffrFeUfNV2Hib',
  metadata: {
    order_id: 'order_98765'
  }
});
from fintoc import Fintoc

client = Fintoc('YOUR_SECRET_API_KEY')

payment_intent = client.payment_intents.create(
    amount=150000,
    currency='CLP',
    customer='cus_NffrFeUfNV2Hib',
    payment_method='pm_NffrFeUfNV2Hib',
    metadata={
        'order_id': 'order_98765'
    }
)
ParameterExampleDescription
amount150000Required. A positive integer representing the amount to charge in the smallest currency unit (for example, 150000 for CLP 150000, since CLP has no minor unit, or 10000 for MXN 100.00).
currencyCLPRequired. Three-letter ISO 4217 currency code. One of CLP or MXN.
customercus_NffrFeUfNV2HibRequired. ID of the Customer to charge.
payment_methodpm_NffrFeUfNV2HibRequired. The saved payment method ID.
metadata{ "order_id": "order_98765" }Set of key-value pairs for storing additional information.

Fintoc responds with the created Payment Intent:

{
  "id": "pi_34i0T5AWRfIDMOJnhq9BgxXUiyt",
  "object": "payment_intent",
  "status": "created",
  "amount": 150000,
  "currency": "CLP",
  "customer": "cus_NffrFeUfNV2Hib",
  "payment_method": "pm_NffrFeUfNV2Hib",
  "metadata": {
    "order_id": "order_98765"
  }
}

Handle payment events

Subscribe to the following events to track the payment outcome:

EventDescriptionRecommended action
payment_intent.succeededThe charge was successful.Fulfill the order and confirm to the customer.
payment_intent.failedThe charge failed.Retry the charge or ask for another payment method.

Test your integration

Using your test mode API Secret Key, create Checkout Sessions that simulate the full setup and payment flow without moving any money.

1) Create a setup Checkout Session using test credentials

Create a Checkout Session with flow: setup using your test mode Secret Key. Complete the enrollment flow on the Fintoc-hosted page using the following credentials:

Test credentials:

PAC:

  • Username (RUT): 11.111.111-1
  • Password: jonsnow

Select the account based on the final outcome you want to test:

Account numberType of MFACorrect code
813990168Security device000000
422159212Mobile Application - SuccessN/A
5233137377Mobile Application - FailureN/A
170086177SMS0000
746326042Coordinate Card['00', '00', '00']

Card:

Card NumberExpiration DateCVVHolder Name3DS Challenge CodeFinal Result
4111111111111111Any future dateAnyAny-✅ Succeeded
4456524869770255Any future dateAnyAny1234✅ Succeeded if code is correct
4574441215190335Any future dateAnyAny-❌ Failed due to invalid credentials
4349003000047015Any future dateAnyAny-❌ Failed due to rejected transaction

2) Verify the saved payment method

After completing the test enrollment, you should receive the checkout_session.finished and payment_method.activated webhook events. Verify that:

  • The payment_method ID is present in the event payload.
  • The customer ID matches the customer you enrolled.

3) Create a test charge against the saved method

Using the customer and payment_method IDs from step 2, create a Payment Intent against the saved method. Verify that:

  • You receive the payment_intent.succeeded event.
  • The amount matches what you sent.
  • The payment method used is the saved PAC or card.
📘

Test mode does not yet support saving a Payment Method in Mexico.