> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fintoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Accept split payments

> Distribute one Fintoc `CheckoutSession` payment across recipient `Entity` objects, transferring each share to its own bank account without manual reconciliation.

Split Payments lets platforms and marketplaces distribute the funds of a single payment across multiple recipients. When a customer pays through a Checkout Session, Fintoc splits the payout according to your rules and transfers each share to the recipient's own bank account. You do not need manual transfers or reconciliation on your side.

Each recipient is an **Entity**: the legal holder that receives a share of the payment. An Entity declares the account where it gets paid as part of its onboarding, so there is no separate account resource to manage.

There are three steps to accept split payments:

1. **Create an Entity** for each recipient
2. **Onboard the Entity**, including the account where it will be paid
3. **Create a Checkout Session with a `split` array**, then send the customer to its `redirect_url`

## Before you begin

Before you start, make sure you have:

* A Fintoc account with **Collects** enabled
* Your [Secret Key and Public Key](/api/fintoc-api/authentication)
* Recipient business and bank account information for each Entity you need to onboard

***

## Step 1: Create an Entity

An Entity represents the legal holder that receives a share of a payment, such as a seller, a partner, a professional, or a business unit.

```bash theme={null}
curl --request POST "https://api.fintoc.com/v2/entities" \
--header 'Authorization: YOUR_TEST_SECRET_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
  "country_code": "CL",
  "holder_name": "Estudio Rojas SpA",
  "holder_id": "761234567"
}'
```

| Param          | Type   | Required | Description                                                                                      |
| -------------- | ------ | -------- | ------------------------------------------------------------------------------------------------ |
| `country_code` | string | Yes      | ISO 3166-1 alpha-2 country code. One of `CL` (Chile) or `MX` (Mexico).                           |
| `holder_name`  | string | Yes      | Legal name of the entity holder.                                                                 |
| `holder_id`    | string | Yes      | Tax ID without formatting. RUT in Chile, RFC in Mexico. Must be unique within your organization. |

```json theme={null}
{
  "id": "ent_2daFu0zqqDtZGJaSi2TGI2Mm1nN",
  "object": "entity",
  "country_code": "cl",
  "holder_id": "111111111",
  "holder_name": "Test Merchant 1 SpA",
  "is_root": false,
  "mode": "live",
  "status": "waiting_initialization"
}
```

A new Entity starts in `waiting_initialization`. It cannot receive a split until it reaches `operational`, which happens once its onboarding is approved.

<Info>
  If the recipient already exists as an Entity in your organization, reuse its `id`. Creating a second Entity with the same `holder_id` returns `409 entity_holder_id_already_exists_for_organization`.
</Info>

List and retrieve entities with `GET /v2/entities` — which accepts `holder_id`, `status` and `is_root` filters — and `GET /v2/entities/{id}`.

***

## Step 2: Onboard the Entity

During onboarding, the Entity declares who it is and the bank account where Fintoc pays split funds. Fintoc reviews the onboarding. After approval, the Entity becomes `operational`.

You complete onboarding through the API in **Chile and Mexico**.

### Create the onboarding

```bash theme={null}
curl --request POST "https://api.fintoc.com/v2/entities/ent_2daFu0zqqDtZGJaSi2TGI2Mm1nN/onboardings" \
--header 'Authorization: YOUR_SECRET_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
  "type": "settlement_recipient",
  "data": {
    "company_information": {
      "business_activity": "Servicios de arquitectura",
      "business_address": "Av. Apoquindo 100, Santiago, Region Metropolitana, 7550000, Chile",
      "phone": "+56 9 1111 1111",
      "settlement_account": {
        "institution_id": "cl_banco_de_chile",
        "account_number": "123456789",
        "account_type": "checking_account"
      }
    },
    "legal_representatives": [
      {
        "first_name": "Camila",
        "last_name": "Rojas",
        "email": "test@mail.com",
        "nationality": "CL",
        "identification_number": "15123456K",
        "position": "Representante legal"
      }
    ]
  }
}'
```

### Onboarding type

**`type` is required when you create the onboarding.** It declares what the Entity will do with Fintoc, it cannot be changed afterwards, and it determines how much information the onboarding asks for.

**`settlement_recipient`** — the Entity only *receives* money. Its share of each split is transferred to the bank account it declares in `settlement_account`, and nothing else: it does not hold a balance at Fintoc, cannot receive transfers from third parties, and cannot send money out. Because it only gets paid, the onboarding asks for the minimum needed to identify who is being paid. **This is the value to use for Split Payments.**

**`account_holder`** — the Entity *operates* an account at Fintoc. It can receive incoming transfers, send outgoing ones and hold a balance. That capability carries a higher risk profile, so the onboarding requires the full set of information: transactional profile, ownership structure and supporting documents.

### The settlement account

Fintoc transfers this Entity's share of every split to `data.company_information.settlement_account`. The `settlement_account` field is the only Split Payments addition to the onboarding.

| Param            | Type   | Required | Description                                                                                                                                                                                  |
| ---------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `institution_id` | string | Yes      | Bank identifier. See [Chile institution codes](/api/fintoc-api/chile-institution-codes) or the [Bank of Mexico institution codes](https://www.banxico.org.mx/cep-scl/listaInstituciones.do). |
| `account_number` | string | Yes      | Account number.                                                                                                                                                                              |
| `account_type`   | string | Yes      | One of `checking_account` or `sight_account`.                                                                                                                                                |

It carries no holder fields: the account holder is the company being onboarded, so the tax ID is already known.

<Warning>
  An Entity has exactly one settlement account. To change it, create a new onboarding. See [Changing the settlement account](#changing-the-settlement-account).
</Warning>

### Onboarding fields

| Block                          | Required | What it declares                                                                                                                                                                                                        |
| ------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                         | Yes      | Onboarding type. One of `settlement_recipient` (receives split payments) or `account_holder` (operates a Fintoc account). Use `settlement_recipient` for Split Payments.                                                |
| `data`                         | Yes      | Container for `company_information` and any optional onboarding blocks.                                                                                                                                                 |
| `data.company_information`     | Yes      | Business information for the Entity. For natural-person Entities, only `settlement_account` is required; for company Entities, `business_activity`, `business_address`, `phone`, and `settlement_account` are required. |
| `data.legal_representatives[]` | No       | Name, email, nationality, identification number, and position of each legal representative.                                                                                                                             |
| `data.transactional_profile`   | No       | Expected monthly volume, number of operations, and origin of funds.                                                                                                                                                     |
| `data.shareholders[]`          | No       | Ownership structure, with each shareholder's tax ID and participation percentage.                                                                                                                                       |
| Documents                      | No       | Supporting files, uploaded per slot with `PUT`. Up to 20 MB each; re-uploading a slot replaces the file.                                                                                                                |

### Submit the onboarding

Once the information is complete, submit it for review:

```bash theme={null}
curl --request POST "https://api.fintoc.com/v2/entities/ent_2daFu0zqqDtZGJaSi2TGI2Mm1nN/onboardings/onbprc_9kQ2mZpLtR4vXn/submit" \
--header 'Authorization: YOUR_SECRET_KEY'
```

The onboarding moves through these statuses:

| Status        | Meaning                                                                    |
| ------------- | -------------------------------------------------------------------------- |
| `pending`     | Created, nothing submitted yet.                                            |
| `in_progress` | Being completed. Fields and documents can still be edited.                 |
| `submitted`   | Under review by Fintoc. No further edits.                                  |
| `approved`    | Review passed. **The Entity is now `operational` and can receive splits.** |
| `rejected`    | Review failed. Create a new onboarding to retry.                           |

Two webhooks tell you the outcome:

* `entity.onboarding.approved`: the Entity is ready to receive splits.
* `entity.onboarding.rejected`: the review failed.

<Info>
  Compliance review typically takes one to two business days. Design your flow so the recipient can be created and shown as pending while the review runs.
</Info>

### Changing the settlement account

Create a **new onboarding** for the same Entity with the new account. While the new onboarding is under review, the previous account stays in effect and the Entity keeps receiving splits. When the new onboarding is approved, the new account replaces the previous one. If the new onboarding is rejected, nothing changes.

***

## Step 3: Create a Checkout Session with `split`

Add a `split` array to the Checkout Session. Each entry names an Entity and its share.

```bash theme={null}
curl --request POST "https://api.fintoc.com/v2/checkout_sessions" \
--header 'Authorization: YOUR_SECRET_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
  "amount": 150000,
  "currency": "CLP",
  "customer_email": "buyer@example.com",
  "success_url": "https://merchant.example/success",
  "cancel_url": "https://merchant.example/cancel",
  "metadata": { "order_id": "ORD-1234" },
  "split": [
    { "entity_id": "ent_3fXq9tLbnKmWzR4dHs2VcJ7yP5N", "type": "flat", "amount": 50000 },
    { "entity_id": "ent_5jMw7rTkqZbNxH3cLs9YdV2pF8Q", "type": "flat", "amount": 45000 },
    { "entity_id": "ent_9hPz4mVtkXbLwN6cRs1YdJ5qG3T", "type": "flat", "amount": 30000 },
    { "entity_id": "ent_1cKp8sWnvYbMtQ5hLr7XdF3jZ2R", "type": "flat", "amount": 25000,
      "charge_processing_fee": true }
  ]
}'
```

| Field                           | Type    | Required                  | Description                                                                                                                                                               |
| ------------------------------- | ------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `split`                         | array   | No                        | Rules used to divide the payment. Omit it and 100% of the payout goes to you. When present, it must contain between 1 and 10 entries.                                     |
| `split[].entity_id`             | string  | Yes                       | ID of an `operational` Entity.                                                                                                                                            |
| `split[].type`                  | string  | Yes                       | `flat` or `percentage`. Every entry must use the same type.                                                                                                               |
| `split[].amount`                | integer | Yes                       | For `flat`, the amount in the smallest currency unit (for example, `150000` for CLP 150,000; CLP has no minor unit). For `percentage`, basis points where `10000` = 100%. |
| `split[].charge_processing_fee` | boolean | Yes, on exactly one entry | The recipient that absorbs the payment's processing fee.                                                                                                                  |
| `split[].metadata`              | object  | No                        | Key-value data attached to this rule. Returned in webhooks.                                                                                                               |

<Warning>
  **Split rules must add up to the payment amount exactly.** No residual remains. If you keep part of the payment, declare your own root Entity as another entry, as in the example above. Retrieve your root Entity with `GET /v2/entities?is_root=true`.
</Warning>

<Info>
  **Percentages are expressed in basis points.** `10000` = 100%, `1000` = 10%, `1` = 0.01%. To assign 90%, send `9000`.
</Info>

The response echoes the `split` array as you sent it, along with the `redirect_url` of the payment page. Send the customer there to complete the payment.

***

## Step 4: Handle post-payment events

`checkout_session.finished` and `payment_intent.succeeded` include a `split_applied` array with the amount resolved for each recipient.

```json theme={null}
{
  "id": "evt_a4xK32BanKWYn",
  "object": "event",
  "type": "checkout_session.finished",
  "data": {
    "id": "cs_li5531onlFDi235",
    "object": "checkout_session",
    "amount": 150000,
    "currency": "CLP",
    "status": "finished",
    "metadata": { "order_id": "ORD-1234" },
    "split": [
      { "entity_id": "ent_3fXq9tLbnKmWzR4dHs2VcJ7yP5N", "type": "flat", "amount": 50000 },
      { "entity_id": "ent_5jMw7rTkqZbNxH3cLs9YdV2pF8Q", "type": "flat", "amount": 45000 },
      { "entity_id": "ent_9hPz4mVtkXbLwN6cRs1YdJ5qG3T", "type": "flat", "amount": 30000 },
      { "entity_id": "ent_1cKp8sWnvYbMtQ5hLr7XdF3jZ2R", "type": "flat", "amount": 25000,
        "charge_processing_fee": true }
    ],
    "split_applied": [
      {
        "entity_id": "ent_3fXq9tLbnKmWzR4dHs2VcJ7yP5N",
        "calculated_amount": 50000,
        "charge_processing_fee": false
      },
      {
        "entity_id": "ent_5jMw7rTkqZbNxH3cLs9YdV2pF8Q",
        "calculated_amount": 45000,
        "charge_processing_fee": false
      },
      {
        "entity_id": "ent_9hPz4mVtkXbLwN6cRs1YdJ5qG3T",
        "calculated_amount": 30000,
        "charge_processing_fee": false
      },
      {
        "entity_id": "ent_1cKp8sWnvYbMtQ5hLr7XdF3jZ2R",
        "calculated_amount": 25000,
        "charge_processing_fee": true
      }
    ],
    "payment_resource": {
      "payment_intent": {
        "id": "pi_38DNJo3rbvGUzKFvCGZ6dxR1Kxx",
        "object": "payment_intent",
        "status": "succeeded"
      }
    }
  }
}
```

<Warning>
  `checkout_session.finished` can arrive before the payment has reached a final state. Mark the order as paid only when `data.payment_resource.payment_intent.status` is `succeeded`.
</Warning>

Events to handle:

| Event                            | When                                                                     |
| -------------------------------- | ------------------------------------------------------------------------ |
| `checkout_session.finished`      | The session reached a final state. Includes `split` and `split_applied`. |
| `checkout_session.expired`       | The session expired before payment.                                      |
| `payment_intent.succeeded`       | The payment succeeded.                                                   |
| `payment_intent.failed`          | The payment failed.                                                      |
| `payment_intent.requires_action` | The payment needs an extra action from the payer.                        |
| `payout.created`                 | A payout to a recipient was created for the settlement cycle.            |
| `payout.succeeded`               | The payout reached the recipient's account.                              |
| `payout.canceled`                | The payout was canceled and will not be sent.                            |
| `payout.returned`                | A successful payout was returned by the bank. Mexico only.               |
| `entity.onboarding.approved`     | The Entity passed review and can receive splits.                         |
| `entity.onboarding.rejected`     | The review failed.                                                       |

### How and when recipients are paid

Payouts follow your organization's settlement schedule. In each cycle, Fintoc groups every share owed to the same Entity into **one transfer** to its settlement account. For example, a recipient that appears in 200 payments during a cycle receives a single transfer.

Retrieve a payout with `GET /v1/payouts/{id}`, list them with `GET /v1/payouts`, and get the payments it covers with `GET /v1/payouts/{id}/resources`.

<Warning>
  `payout.*` events fire only in `live` mode. Payouts settle against real balances, so `test` mode does not emit `payout.created`, `payout.succeeded`, `payout.canceled`, or `payout.returned`.
</Warning>

***

## Rules and validations

Fintoc validates the `split` array when you create a Checkout Session. The request fails with `400 Bad Request` and `invalid_request_error` if any rule is violated.

**Per entry**

* `entity_id` must reference an Entity in `operational` status
* The Entity's `country_code` must match the payment currency
* For `flat`, `amount` must be greater than `0` and less than or equal to the Checkout Session `amount`.
* For `percentage`: `0 < amount <= 10000`

**Global**

* Between 1 and 10 entries
* No duplicate `entity_id` values
* Every entry must use the same `type`
* The sum of all `split[].amount` values, after converting percentages, must equal the Checkout Session `amount` exactly.
* For `percentage`, the values must add up to exactly `10000` bps

**Rounding.** Percentage amounts are calculated as `floor(amount_total * amount / 10000)`. The accumulated rounding difference is assigned to the entry with `charge_processing_fee: true`.

### Errors

| Code                             | Meaning                                                                         |
| -------------------------------- | ------------------------------------------------------------------------------- |
| `ENTITY_NOT_FOUND`               | The `entity_id` does not exist in your organization.                            |
| `ENTITY_NOT_OPERATIONAL`         | The Entity has not completed its onboarding.                                    |
| `DUPLICATE_ENTITY_IN_SPLIT`      | The same `entity_id` appears more than once.                                    |
| `MIXED_SPLIT_TYPES`              | The array mixes `flat` and `percentage`.                                        |
| `SPLIT_SUM_MISMATCH`             | The amounts do not add up to `amount` exactly.                                  |
| `MISSING_CHARGE_PROCESSING_FEE`  | No entry sets `charge_processing_fee` to `true`. Exactly one entry must set it. |
| `MULTIPLE_CHARGE_PROCESSING_FEE` | More than one entry sets `charge_processing_fee` to `true`.                     |

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "message": "Split rules must add up to the total amount",
    "code": "SPLIT_SUM_MISMATCH",
    "param": "split"
  }
}
```
