payout / developers
Guide

Transaction splitting

On this page

Transaction splitting turns one incoming payment into several transactions, one for each offer_id of the checkout's products. You can then track, report, refund and pay out each product line separately. Typical uses:

  • insurance companies (MTPL and CASCO products);
  • marketplaces (different sellers);
  • multi-brand retailers (different product lines);
  • service providers (different service types).

How it works

  1. One payment, several transactions. A successful payment creates one transaction per distinct offer_id. Its amount is the sum of unit_price × quantity of the products with that offer_id.
  2. Tagged transactions. Each transaction carries its offer_id, and the payment webhook lists them.
  3. One balance. All the money goes to your Payout account, whatever the offer_id.
  4. Optional routing. Split routing rules can pay out the transactions of an offer_id to a separate IBAN, see Split routing rules.

Note

To have payouts routed by offer_id, send should_split: true even when the checkout has only one product or offer. Only then is the transaction tagged with the offer_id and routed by your rules.

Enabling transaction splitting

Both conditions must be met:

  1. Account feature. Ask support to enable transaction splitting for your account.
  2. Checkout flag. Send "should_split": true (a JSON boolean, not the string "true") when you create the checkout.

Products

Give every product an offer_id. As everywhere in the Payment API, amount and unit_price are integers in cents:

JSON
{
  "amount": 30000,
  "currency": "EUR",
  "should_split": true,
  "products": [
    {
      "name": "Premium Service",
      "offer_id": "PREMIUM",
      "unit_price": 10000,
      "quantity": 1
    },
    {
      "name": "Basic Service",
      "offer_id": "BASIC",
      "unit_price": 20000,
      "quantity": 1
    }
  ]
}

This checkout pays 300.00 EUR: 100.00 EUR for PREMIUM and 200.00 EUR for BASIC. Products without an offer_id are grouped into one transaction with offer_id null, which cannot be refunded or routed by offer_id.

Important

With should_split: true, the sum of unit_price × quantity over all products must equal the checkout amount.

If a condition is not met, creating the checkout fails with HTTP 400:

Problem errors
The sum of the products differs from amount [{"products": "Sum of products (250.00) must equal checkout amount (300.00)."}]
No products [{"products": "Products must be provided when splitting is enabled."}]
Splitting is not enabled for your account [{"shoud_split": "Transaction splitting not available."}]

Examples of offer_id values by industry:

  • Insurance: MTPL, CASCO
  • Marketplace: VENDOR_A, VENDOR_B
  • Retail: ELECTRONICS, CLOTHING

Payment webhook

The checkout webhooks of a split payment, such as checkout.succeeded, have a split_transactions list in data, next to payment:

JSON
{
  "external_id": "order-1001",
  "object": "webhook",
  "type": "checkout.succeeded",
  "data": {
    "object": "checkout",
    "id": 141447,
    "external_id": "order-1001",
    "amount": 30000,
    "currency": "EUR",
    "status": "succeeded",
    "is_status_final": true,
    "payment": {
      "object": "payment",
      "status": "successful",
      "payment_method": "card",
      "fee": 250,
      "net": 9750
    },
    "split_transactions": [
      {
        "transaction_id": 9001,
        "amount": 10000,
        "offer_id": "PREMIUM",
        "bank_account": "SK3112000000198742637541"
      },
      {
        "transaction_id": 9002,
        "amount": 20000,
        "offer_id": "BASIC",
        "bank_account": null
      }
    ]
  },
  "nonce": "UzhER2lFOFZCNkNQVmNuNQ",
  "signature": "<signature>"
}

The example shows only the fields that matter here; the rest of the checkout object is the same as in other webhooks.

Field Description
transaction_id ID of the split transaction
amount Amount of the split transaction, in cents
offer_id The offer_id of its products, or null for products without one
bank_account IBAN of the active routing rule for this offer_id, or null when there is none

split_transactions is present only when the checkout was created with should_split: true and has a successful payment. fee and net in data.payment refer to the first split transaction only.

Split routing rules

Split routing rules say where the payouts of an offer_id go. They are applied by your scheduled automatic payout, so they need an automatic payout to be set up on your account. They do not affect incoming payments.

The rules cannot be managed through the API or the portal; our team sets them up for you.

Setting up a rule

Contact support or your account manager with these details for each offer_id:

Detail Example Notes
offer_id PREMIUM Must match the offer_id of your products
IBAN SK3112000000198742637541 Where the payouts of this offer_id go
Currency EUR Currency of the automatic payout the rule applies to
Description Premium Service Payouts Optional. Used as the beneficiary name; without it, your account name is used

With each automatic payout, Payout sends the net amount of the available transactions of that offer_id, minus their refunds, to the rule's IBAN. The statement descriptor is Split payout: <offer_id>, and the usual withdrawal fee applies.

Transactions without a rule

Transactions whose offer_id has no active rule stay in your general balance. They are paid out by your regular automatic payout or by a manual withdrawal. Any change to the rules goes through our support team.

Refund handling

To refund a checkout created with should_split: true, you must send offer_id. It selects the split transaction to refund.

HTTP
POST /api/v1/refunds
Content-Type: application/json
Authorization: Bearer <token>
JSON
{
  "checkout_id": 141447,
  "offer_id": "PREMIUM",
  "amount": 5000,
  "nonce": "<random string>",
  "signature": "<signature>"
}
  • amount is optional, in cents. Without it, the whole remaining amount of the split transaction is refunded. Card payments processed by CardPay and pay-later payments can only be refunded in full.
  • signature is the SHA-256 of amount|currency|external_id|iban|nonce|client_secret, encoded as lowercase hex. currency and external_id are those of the checkout, and iban is empty unless you send one. If you leave out amount, sign the full checkout amount, not the remaining amount of the split transaction.
Problem HTTP status Body
Invalid signature 403 {"errors": {"signature": "Is invalid"}}
offer_id missing 400 {"errors": {"offer_id": "is required for split refund"}}
No split transaction with this offer_id 422 {"errors": "split_transaction_not_found"}

The response is the usual refund object; it does not repeat the offer_id:

JSON
{
  "id": 5821,
  "object": "refund",
  "amount": 5000,
  "currency": "EUR",
  "external_id": "order-1001",
  "status": "pending",
  "metadata": {},
  "created_at": 1759744800
}

Good to know

  • Splitting works for payment methods that pay the checkout directly, such as cards, online banking and pay later. Payments by bank transfer with payment instructions, which are matched by their reference, are not split.
  • Fees are calculated for each split transaction separately: each one is charged the fixed fee and the percentage fee of its own amount.
  • Each split transaction stays linked to the original payment; the webhook gives you its transaction_id and offer_id.
  • Split routing rules only affect payouts, not incoming payments.

Was this page helpful?