Integration flow for Payment Intents

Fintoc uses the Payment Intent object to represent a bank transfer.

To make a transfer, you must follow some steps:

Create a Payment lntent

From your backend, create a Payment Intent with the amount, currency and recipient of the payment. Always create the Payment Intent from your backend, or a malicious user could alter any of those fields.

Here's an example:

curl --request POST "https://api.fintoc.com/v1/payment_intents" \
-- header 'Authorization: sk_live_0000000000000000' \
-- header 'Content-Type: application/json' \
--data-raw '{
  "amount": 1000,
  "currency": "CLP",
  "recipient_account": {
    "holder_id": "111111111",
    "number": "123123123",
    "type": "checking_account",
    "institution_id": "cl_banco_de_chile"
  }
}'
const fetch = require('node-fetch');

const payment_intent = {
  amount: 1000,
  recipient_accout: {
    holder_id: "111111111",
    number: "123123123",
    type: "checking_account",
    institution_id: "cl_banco_de_chile"
  },
}

fetch('https://api.fintoc.com/v1/payment_intents', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
      'Authorization': 'sk_live_000000000000'
    },
    body: JSON.stringify(payment_intent),
  },
)
import requests

payment_intent = {
  'amount': 1000,
  'currency': 'clp',
  'recipient_account': {
    'holder_id': '111111111',
    'number': '123123123',
    'type': 'checking_account',
    'institution_id': 'cl_banco_de_chile'
  }
}

headers = {
  'Accept': 'application/json', 'Authorization': 'sk_live_000000000000'
}

r = requests.post(
  'https://api.fintoc.com/v1/payment_intents',
  data=payment_intent,
  headers=headers
)
require 'net/http'
require 'uri'
require 'json'

payment_intent = {
  amount: 1000,
  currency: 'clp',
  recipient_account: {
    holder_id: '111111111',
    number: '123123123',
    type: 'checking_account',
    institution_id: 'cl_banco_de_chile'
  }
}

header = {
  Accept: 'application/json', Authorization: 'sk_live_000000000000'
}

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

response = http.request(request)

The response should look like this:

{
  "id": "pi_BO381oEATXonG6bj",
  "object": "payment_intent",
  "amount": 1000,
  "currency": "CLP",
  "widget_token": "pi_BO381oEATXonG6bj_sec_a4xK32BanKWYn",
  "status": "created",
  "reference_id": null,
  "recipient_account": {
    "holder_id": "183917137",
    "number": "123456",
    "type": "checking_account",
    "institution_id": "cl_banco_de_chile"
  },
  "sender_account": null,
  "created_at": "2021-10-15T15:23:11.474Z",
}

When creating a Payment Intent, a widget_token will be created too (unique for that transfer). You need to use that token to complete the payment process through the widget. The next section contains more details about this.

Open the widget for Payment Intents

Once the Payment Intent is created, you must send its widget_token to your frontend. Use that widget_token to configure the widget and the workflow that the user must follow.

Here's an example of the widget configured with the widget_token:

<head>
  <script src="https://js.fintoc.com/v1/"></script>
</head>

<body>
  <script>
    const widget = Fintoc.create({
      holderType: 'individual',
      widgetToken: 'pi_XXXXXXXX_sec_YYYYYYYY',
      product: 'payments',
      publicKey: 'pk_live_0000000000',
      onSuccess: () => {},
    })
    </script>
</body>

📘

Widget Token

When using the widget_token, Fintoc configures every internal data relevant for the payment: amount, currency and recipient.

The widget_token is temporary and will expire 10 minutes after its creation.

To read more about the widget and its configuration, head over to the widget section.

Finish the transfer

Once the transfer is completed, we will send you an event with payment_intent as its type using a webhook.

To subscribe to the event, you must first have created a Webhook Endpoint using Fintoc and assign to it the events that you want to receive.

It is very important that you subscribe to these events, as you can use them to identify successful transfers from failed ones.

Remember that with the Payment Intent object we can send you 3 different events using webhooks:

Event

Description

payment_intent.succeeded

Event that triggers when a transfer is validated as successful.

payment_intent.failed

Event that triggers when a transfer fails due to a problem with the bank or with Fintoc.

payment_intent.rejected

Event that triggers when a transfer is rejected by the user. This may happen when the user rejects the MFA or if it is entered incorrectly.

📘

Backend's webhook vs widget's onSuccess

It is very important that you wait for the webhook to your backend with the event to finish the flow. You should never finish the flow solely based on the onSuccess function from the widget because your users may close the widget just before the callback to send the webhook to your backend gets executed.

A Payment Intent may fail when the transfer takes more than usual to execute or if the user closes the widget ahead of time.

Once again, we urge you to wait for the webhook to hit your backend before making any post-payment actions like sending confirmation emails to your users, entering the sale on your database or starting the shipping process of some product.

To subscribe to the webhook with the corresponding event, you can read the Webhooks section of our documentation. Remember that these events all start with payment_intent.


Did this page help you?