Accept recurring payments

There are three steps to accept recurring payments using Fintoc:

  1. On your backend, create a Checkout Session with flow: subscription
  2. Redirect your user to complete the enrollment at the Fintoc-hosted checkout page
  3. Handle post-enrollment and recurring payment events (webhooks)

The following diagram shows how Fintoc interacts with both your backend and your frontend:

fintoc-recurring-payment-diagram

Create a Session

The Checkout Session object represents your intent to enroll a payment method for recurring charges, and to create a subscription with a fixed amount and periodicity.

Using your Secret Key, create a Checkout Session on your backend with flow set to subscription.

curl --request POST "https://api.fintoc.com/v2/checkout_sessions" \
  --header "Authorization: YOUR_TEST_SECRET_API_KEY" \
  --header "Content-Type: application/json" \
  --data-raw '{
    "flow": "subscription",
    "amount": 350000,
    "currency": "CLP",
    "success_url": "https://merchant.com/success",
    "cancel_url": "https://merchant.com/987654321",
    "payment_method_types": [
      "pac"
    ],
    "customer_data": {
      "tax_id": {
        "type": "cl_rut",
        "value": "12088191"
      },
      "name": "Felipe Castro",
      "email": "[email protected]",
      "metadata": {}
    },
    "line_items": [
      {
        "price_data": {
          "currency": "CLP",
          "unit_amount": 350000,
          "product_data": {
            "name": "Plan 1"
          },
          "recurring": {
            "interval": "month",
            "interval_count": 1
          }
        },
        "quantity": 1
      }
    ],
    "metadata": {
      "subscription_external_id": "sub_987654321"
    }
  }'
const { Fintoc } = require('fintoc');

const fintoc = new Fintoc('YOUR_TEST_SECRET_API_KEY');

const checkoutSession = await fintoc.checkoutSessions.create({
  flow: 'subscription',
  amount: 350000,
  currency: 'CLP',
  success_url: 'https://merchant.com/success',
  cancel_url: 'https://merchant.com/987654321',
  payment_method_types: ['pac'],
  customer_data: {
    tax_id: {
      type: 'cl_rut',
      value: '12088191'
    },
    name: 'Felipe Castro',
    email: '[email protected]',
    metadata: {}
  },
  line_items: [
    {
      price_data: {
        currency: 'CLP',
        unit_amount: 350000,
        product_data: {
          name: 'Plan 1'
        },
        recurring: {
          interval: 'month',
          interval_count: 1
        }
      },
      quantity: 1
    }
  ],
  metadata: {
    subscription_external_id: 'sub_987654321'
  }
});
from fintoc import Fintoc

client = Fintoc('YOUR_TEST_SECRET_API_KEY')

checkout_session = client.checkout_sessions.create(
    flow='subscription',
    amount=350000,
    currency='CLP',
    success_url='https://merchant.com/success',
    cancel_url='https://merchant.com/987654321',
    payment_method_types=['pac'],
    customer_data={
        'tax_id': {
            'type': 'cl_rut',
            'value': '12088191',
        },
        'name': 'Felipe Castro',
        'email': '[email protected]',
        'metadata': {},
    },
    line_items=[
        {
            'price_data': {
                'currency': 'CLP',
                'unit_amount': 350000,
                'product_data': {
                    'name': 'Plan 1',
                },
                'recurring': {
                    'interval': 'month',
                    'interval_count': 1,
                },
            },
            'quantity': 1,
        }
    ],
    metadata={
        'subscription_external_id': 'sub_987654321',
    },
)
require 'net/http'
require 'uri'
require 'json'

checkout_session = {
  flow: 'subscription',
  amount: 350000,
  currency: 'CLP',
  success_url: 'https://merchant.com/success',
  cancel_url: 'https://merchant.com/987654321',
  payment_method_types: ['pac'],
  customer_data: {
    tax_id: {
      type: 'cl_rut',
      value: '12088191'
    },
    name: 'Felipe Castro',
    email: '[email protected]',
    metadata: {}
  },
  line_items: [
    {
      price_data: {
        currency: 'CLP',
        unit_amount: 350000,
        product_data: {
          name: 'Plan 1'
        },
        recurring: {
          interval: 'month',
          interval_count: 1
        }
      },
      quantity: 1
    }
  ],
  metadata: {
    subscription_external_id: 'sub_987654321'
  }
}

uri = URI('https://api.fintoc.com/v2/checkout_sessions')

header = {
  'Accept' => 'application/json',
  'Authorization' => 'YOUR_TEST_SECRET_API_KEY',
  'Content-Type' => 'application/json'
}

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, header)
request.body = checkout_session.to_json

response = http.request(request)
ParameterExampleDescription
amount2476

Amount of money that needs to be paid. It's represented as integer with no decimals in the smallest possible unit of the currency you are using.

If your payment uses Chilean peso, an amount of CLP 2476 is represented as 2476.

If your payment uses Mexican peso, an amount of MXN 24.76 is represented as 2476.

Read here to learn more.

currencyCLPCurrency that is being used for the recurring payments. Currently Fintoc only supports CLP or MXN
flowsubscriptionRequired type of the flow for the session. The types available are payment, setup and subscription
success_urlhttps://merchant.com/successRequired URL to redirect the user in case of payment succeeded.
cancel_urlhttps://merchant.com/987654321Required URL to redirect the user in case they decide to cancel the payment and return to your website.
customercus_alm1321knjl1233Id of an already created customer. One of customer or customer_data is required.
customer_data(object)Data for inline customer creation. One of customer or customer_data is required.
payment_method_types["pac"]Optional list of allowed payment methods during enrollment. Currently, pac (charges on bank account in Chile), direct_debit (charges on bank account in México) and card are available.
line_items(array)Required subscription items.
metadata{"order": "987654321"}Optional set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format.

Include Customer Data (Required for subscriptions)

When creating a Checkout Session with flow: subscription, you must include customer information. You can do this either by referencing an existing customer ID (customer) or by sending customer_data to create one inline:

AttributeTypeDescription
tax_idobject

Required object that identifies the customer at a fiscal or regulatory level.

It includes a type field indicating the format or country-specific identifier, for example, cl_rut for Chilean RUT or mxn_rfc for Mexican RFC number. And a value field containing the actual tax identification number as a string.

namestringOptional full name of the customer.
emailstringOptional customer email linked to a Checkout Session. This is used to notify a user in case of a refund.
metadataobjectOptional custom data that can store additional information about the customer (e.g., internal IDs, CRM references, or tags)

Include a Items list (Required for subscriptions)

When creating a Checkout Session, you can also include information about the items that will be purchased. This enables Fintoc to display this information on the checkout page and show only the payment methods available for specific products.

AttributeTypeDescription
quantityintegerRequirednumber of units of this item being purchased.
price_dataobjectData used to generate a new recurring price inline. One of price or price_data is required.

Each line_item must specify its price_data.

price_data Object

AttributeTypeDescription
product_dataobjectData used to generate a new Product object inline. One of product or product_data is required.
currencystringCurrency used for the subscription. We currently only support CLP or MXN.
unit_amountintegerRequired price per unit of the item, expressed in the smallest currency unit (e.g., CLP without decimals and MXN with 2 decimals).
recurring(object)Required recurring configuration (e.g. interval: month, interval_count: 1).

product_data Object

AttributeTypeDescription
namestringRequired name of the product or service being purchased.
image_urlstringOptional image URL for the product. Must be an HTTPS URL. Recommended aspect ratio: 9:4.

Response when creating a Checkout Session

After making the request to create the Checkout Session, Fintoc should respond with something like this:

{
  "id": "cs_li5531onlFDi235",
  "flow": "subscription",
  "customer": {
      "name": "Felipe Castro",
      "email": "[email protected]",
      "metadata": {},
      "tax_id": {
        "type": "cl_rut",
        "value": "12088191"
      }
    },
  "line_items": [
    {
      "price": {
        "product": {
          "name": "Plan A",
          "description": "Pago recurrente monto fijo"
        },
        "currency": "CLP",
        "unit_amount": 350000,
        "recurring": {
          "interval": "month",
          "interval_count": 1
        }
      },
      "quantity": 1
    }
  ],
  "success_url": "https://merchant.example/success",
  "cancel_url": "https://merchant.example/cancel",
  "redirect_url": "https://pay.fintoc.com/checkout/cs_123"
}

The response will include a redirect_url attribute. In the following step, you'll redirect the user to this location to complete the subscription process.

Redirect the user to complete the payment

Next, you will redirect users to the Fintoc Checkout page. After completing the payment, they'll be automatically redirected back to your site.

Based on the result, the user will be redirected to either the success or cancel URL.

Handle post-session events

Once a Checkout Session finishes, you handle the result in your frontend and complete the subscription in your backend. For your backend, you will use the events sent by webhooks.

Complete the subscription on your backend

Fintoc sends a checkout_session.finished event when the session completes.

In a subscription flow, this event includes information about the session and references to the subscription and payment_method created during enrollment.

{
  "id": "evt_a4xK32BanKWYn",
  "object": "event",
  "type": "checkout_session.finished",
  "data": {
    "id": "cs_li5531onlFDi235",
    "flow": "subscription",
    "customer": {
      "name": "Felipe Castro",
      "email": "[email protected]",
      "metadata": {},
      "tax_id": {
        "type": "cl_rut",
        "value": "12088191"
      }
    },
    "payment_method_types": ["pac"],
    "status": "finished",
    "payment_status": "succeeded",
    "subscription": "sub_NffrFeUfNV2Hib",
    "payment_method": "pm_NffrFeUfNV2Hib"
  }
}

You should handle the following post-session events :

EventDescriptionAction
checkout_session.finishedSent when an subscription Checkout Session reaches a final stateActivate the subscription on your side based on the final status, and store the created ids (subscription, payment_method, customer).
checkout_session.expiredSent when a session expiresOffer the customer another attempt to subscribe.
payment_intent.succeededSent when a payment intent succeeds, like a charge on a bank account or card.Confirm to your customer that the charge of the subscription was successfully done
payment_intent.failedSent when a payment intent failsOffer the customer another attempt to pay the subscription.

Test your integration

To confirm that your integration works correctly, you can simulate subscriptions and scheduled recurring payments without moving any money

1) Create a subscription Checkout Session using test users credencials

Using your test mode API Secret Key, create a Checkout Session of flow: subscription on your backend and complete the subscription enrollment flow on the fintoc-hosted page using the following credentials:

Test credentials

  • Username (RUT): 41614850-3
  • Password: jonsnow

2) Handle simulated scheduled payments of the subscription

In test mode, once the subscription is created, Fintoc will immediately trigger successful and failed payment intents, allowing you to test the handling of all post-session events.

📘

Sandbox to test Recurring Payments in México will be available soon

Managing Invoices

When a subscription is created after a successful checkout enrollment, Fintoc automatically generates an Invoice for each billing cycle. An invoice represents the amount owed by the customer for a given period, and Fintoc will attempt to collect payment for it using the enrolled payment method.

For full details on invoices, see the Invoice Object

Invoices in the subscription flow

After the checkout_session.finished event, the subscription becomes active and Fintoc creates the first invoice. From that point on, you should handle the following invoice-related events alongside the post-session events described above:

EventDescriptionAction
invoice.createdA new invoice was generated for a billing cycle.Log the invoice and update your records.
invoice.finalizedThe invoice was finalized and is ready to be paid.Update your records accordingly.
invoice.payment_succeededThe invoice payment was successfully collected.Confirm the payment to your customer and extend access.
invoice.payment_failedThe payment attempt for the invoice failed.Notify your customer and offer an alternative payment method.

Month 1 — Right after the subscription is created, Fintoc generates the first invoice and attempts payment immediately. You'll receive invoice.created, followed by invoice.finalized, then invoice.payment_succeeded and payment_intent.succeeded on success.

Month 2 onwards — At each billing cycle renewal (based on the subscription's billing_cycle_anchor), a new invoice is created on status draft . After 1 hour, a payment is attempted automatically. On success you receive invoice.payment_succeeded. On failure, invoice.payment_failed.

Test invoice creation with status draft

To test an invoice that is created in draft status, create a subscription with a line item using the product name sandbox_draft:

curl --request POST "https://api.fintoc.com/v2/checkout_sessions" \
  --header "Authorization: YOUR_TEST_SECRET_API_KEY" \
  --header "Content-Type: application/json" \
  --data-raw '{
    "flow": "subscription",
    "amount": 350000,
    "currency": "CLP",
    "success_url": "https://merchant.com/success",
    "cancel_url": "https://merchant.com/cancel",
    "payment_method_types": ["pac"],
    "customer_data": {
      "tax_id": {
        "type": "cl_rut",
        "value": "12088191"
      },
      "name": "Felipe Castro",
      "email": "[email protected]"
    },
    "line_items": [
      {
        "price_data": {
          "currency": "CLP",
          "unit_amount": 350000,
          "product_data": {
            "name": "sandbox_draft"
          },
          "recurring": {
            "interval": "month",
            "interval_count": 1
          }
        },
        "quantity": 1
      }
    ]
  }'

The invoice will be created with status draft, allowing you to edit its Items via the Add Lines endpoints before it transitions to further statuses.