Split Payments
Route portions of an order's funds to additional accounts when the customer pays.
A split policy describes how the funds collected for an order are distributed among the merchant and additional recipients. The policy is configured ahead of time on the project; your integration supplies the per-order pieces that vary.
There are two per-order mechanisms, used independently:
- Splits (
splits[]) โ fill the policy's variadic slot(s) with a recipient chosen per order, and/or add payer tips. Recipients are referenced bybeneficiary_id(a pre-registered beneficiary). - Per-order rule overrides (
split_overrides) โ restate the whole policy for a single order: change each slot's rule (amount/percentage) and recipient. Override recipients may be a registeredbeneficiary_idor a Payseraaccountnumber paid directly, without prior registration.
Splits, payer tips, and per-order overrides are not enabled by default and there is no self-serve toggle โ the merchant requests them from Paysera customer support. To avoid a round-trip, include in the request:
- the project id the capabilities are for;
- which capabilities you need: automatic splits (the split policy + beneficiary feature), payer tips, and/or per-order overrides;
- the split-policy shape you want (each slot's role and rule โ e.g. "merchant keeps 10%, remainder to a per-order seller").
Until the project is fully configured, order requests that include splits are rejected โ see Errors. After activation, confirm by calling Get split policy (it returns configured: true). A tips-only project has no split policy, so Get split policy returns 404 โ confirm activation there by registering a beneficiary and placing a tip order instead.
All calls below use the integration API with an Authorization: Bearer token โ see Authentication for how to obtain one. The token is scoped to a single project; the project is taken from the token, so you don't pass a project id.
Glossaryโ
- EVP account โ Paysera's internal account format, e.g.
EVP5210018145214. Split recipients are paid to Paysera EVP accounts. - Split policy โ the project's template describing each share (slot) of the payment. Set up by Paysera support; your integration reads it but cannot change its structure.
- Slot โ one share of the policy, identified by a stable
slot_id, with a role:merchantโ the merchant's own share. Never has a per-order recipient.beneficiaryโ a fixed recipient configured on the policy.variadicโ a recipient that changes per order; your integration supplies it at order creation.
- Beneficiary โ a recipient registered on the project. Registering one returns a
beneficiary_id(UUID). Standard splits reference recipients by this id. - Direct account (
account) โ in override mode only, a Paysera EVP account paid directly via theaccountfield, without registering a beneficiary first. The account must already exist as a Paysera account. - Tip โ an extra amount the customer adds on top of the order total, routed to a beneficiary. Independent of the policy template.
The setup โ order flowโ
- Have the merchant request activation (support enables the features and sets up the policy).
- Read the split policy to learn its
slot_ids and roles. - Register beneficiaries for the recipients you will reference by id.
- On each order, attach
splitsand/orsplit_overrides. - Create a non-expiring payment link (
lifetime: 0).
Discover your split policyโ
Read the project's policy to learn each slot's slot_id, role, and configured rule. You need the slot_ids to bind variadic entries (when the policy has more than one variadic slot) and to build per-order overrides.
curl https://api.paysera.com/checkout-project/integration/v1/project/split-policy \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
// Response โ a two-slot marketplace policy: the merchant (platform) keeps 10%,
// the per-order seller (variadic) gets the remainder.
{
"project_id": "b7c3d4e5-6f7a-8b9c-0d1e-2f3a4b5c6d7e",
"configured": true,
"slots": [
{ "slot_id": "11111111-1111-1111-1111-111111111111", "position": 0, "role": "merchant", "rule_type": "percentage", "value": 1000, "beneficiary_id": null, "beneficiary_account_number": null, "beneficiary_name": null, "beneficiary_missing": false },
{ "slot_id": "22222222-2222-2222-2222-222222222222", "position": 1, "role": "variadic", "rule_type": "remainder", "value": null, "beneficiary_id": null, "beneficiary_account_number": null, "beneficiary_name": null, "beneficiary_missing": false }
]
}
| Field | Type | Description |
|---|---|---|
configured | boolean | Whether the policy template is fully set up. An order with splits fails if this is false. |
slots[].slot_id | string (UUID) | Stable id of the slot. Bind variadic entries and overrides to this value. |
slots[].position | integer | 0-based order of the slot in the policy. |
slots[].role | string | merchant, beneficiary (fixed recipient), or variadic (per-order recipient). |
slots[].rule_type | string | fixed, percentage, remainder, or null (not yet configured). |
slots[].value | integer | Cents for fixed; basis points for percentage (1 bp = 0.01%; 10000 = 100%); null for remainder. |
slots[].beneficiary_id | string (UUID) | Fixed recipient configured on the slot, if any. |
slots[].beneficiary_account_number | string | The fixed recipient's EVP account, if any. |
slots[].beneficiary_name | string | The fixed recipient's display name, if any. |
slots[].beneficiary_missing | boolean | true if the slot expects a recipient that hasn't been configured yet. |
Returns 404 if the project has no policy template. Full reference: Get split policy.
Register beneficiariesโ
Standard splits[] entries (variadic and tip) reference a recipient by beneficiary_id. Register each recipient once; the returned id is the beneficiary_id.
The endpoint accepts Paysera EVP accounts only โ the account must already exist as a Paysera account and must not be the merchant's own.
curl -X POST https://api.paysera.com/checkout-project/integration/v1/split-beneficiaries \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"account_number": "EVP5210018145214",
"name": "Marketplace Seller #42"
}'
// Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"account_number": "EVP5210018145214",
"name": "Marketplace Seller #42",
"created_at": 1716200000
}
| Field | Type | Required | Description |
|---|---|---|---|
account_number | string | โ | Recipient's Paysera EVP account (EVP followed by digits). Must exist and not be the merchant's own account. |
name | string | โ | Display name for the beneficiary |
List or remove beneficiaries with the same resource:
# List (cursor-paginated); each item includes id, account_number, name, created_at, consent_status
curl https://api.paysera.com/checkout-project/integration/v1/split-beneficiaries \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Remove
curl -X DELETE https://api.paysera.com/checkout-project/integration/v1/split-beneficiaries/{beneficiaryId} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Full reference: Register ยท List ยท Delete.
The merchant's own share is handled automatically by the policy. The merchant self-beneficiary is created for you and cannot be referenced in an order โ only register and reference additional recipients.
Per-order splitsโ
Attach a splits array to fill the policy's variadic slot(s) and/or add payer tips. The merchant share, fixed shares, and percentages come from the policy template โ you only send the per-order pieces.
| Field | Type | Required | Description |
|---|---|---|---|
splits[].type | string | โ | variadic or tip |
splits[].beneficiary_id | string (UUID) | โ | Id of the registered beneficiary to pay |
splits[].slot_id | string (UUID) | Variadic slot to bind to. Required only when the policy has more than one variadic slot; auto-binds for a single variadic slot. Ignored for tips. |
- Variadic โ send exactly one entry per variadic slot in the policy. With one variadic slot you may omit
slot_id; with several, setslot_idon each (from the split-policy response). - Tip โ one entry per tip recipient. Tips are extra money on top of the order total and require payer tips to be enabled (see Payer tips).
"splits": [
{ "type": "variadic", "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000" },
{ "type": "tip", "beneficiary_id": "660e8400-e29b-41d4-a716-446655440111" }
]
Per-order rule overridesโ
When the project has per-order overrides enabled, send a split_overrides block to restate the entire policy for a single order โ changing each slot's rule and/or recipient without altering the saved policy. This is the only path that accepts a recipient account directly, without registering a beneficiary.
Override mode requires a configured split policy and the per-order overrides capability; otherwise the order is rejected (see Errors).
The example below restates the two-slot policy from Discover your split policy: the variadic slot pays a courier a fixed โฌ15 directly by account, and the merchant keeps the remainder. (Every slot of the policy must appear.)
"split_overrides": {
"slots": [
{ "slot_id": "11111111-1111-1111-1111-111111111111", "type": "remainder" },
{ "slot_id": "22222222-2222-2222-2222-222222222222", "type": "fixed", "value": 1500,
"recipient": { "account": "EVP5210018145214" } }
]
}
Rules:
- Restate every slot of the policy exactly once, identified by
slot_id. Missing, unknown, or duplicated slots are rejected. type/valueper slot:fixedโ cents (value > 0);percentageโ basis points (1โ10000);remainderโ omitvalue. Exactly oneremainderslot is required, and the percentage slots must sum to less than 100%.recipientper slot โ provide exactly one ofbeneficiary_idoraccount:beneficiary_idโ a beneficiary registered for the project.accountโ a Paysera EVP account paid directly, no prior registration (it must still exist as a Paysera account).- The recipient is required for a
variadicslot, optional for abeneficiaryslot (supplying it replaces the policy recipient), and must be omitted for themerchantslot.
| Field | Type | Required | Description |
|---|---|---|---|
split_overrides.slots[].slot_id | string (UUID) | โ | Which policy slot is being restated |
split_overrides.slots[].type | string | โ | fixed, percentage, or remainder |
split_overrides.slots[].value | integer | conditional | Cents (fixed) or basis points (percentage); omit for remainder |
split_overrides.slots[].recipient.beneficiary_id | string (UUID) | conditional | Registered beneficiary (exactly one of beneficiary_id / account) |
split_overrides.slots[].recipient.account | string | conditional | Paysera EVP account paid directly, no registration |
Tips are always sent in the splits array as type:"tip" entries โ they are not part of split_overrides. You may send split_overrides together with tip entries in splits, but a variadic entry in splits is rejected in override mode (the override block already restates the variadic slot).
Override the policy and add a payer tip in the same order โ split_overrides restates the policy slots, while the tip travels in splits:
{
"purchase": { "reference": "ORDER-99002", "amount": 100000, "currency": "EUR" },
"split_overrides": {
"slots": [
{ "slot_id": "11111111-1111-1111-1111-111111111111", "type": "remainder" },
{ "slot_id": "22222222-2222-2222-2222-222222222222", "type": "fixed", "value": 1500,
"recipient": { "account": "EVP5210018145214" } }
]
},
"splits": [
{ "type": "tip", "beneficiary_id": "660e8400-e29b-41d4-a716-446655440111" }
]
}
Payer tips and tax-agent consentโ
Tips are added by the payer on top of the order amount and routed to a beneficiary you name per order. They do not come out of the merchant's share. Use cases: hospitality, personal services, delivery, creator platforms, live events.
A tip entry carries no amount โ you only name the recipient. The payer chooses the tip amount during checkout, on Paysera's hosted payment page; it is added on top of the order total at payment time. Your order's purchase.amount and the payment link's amount cover the bill only, not the tip.
Tips do not require a split policy โ a tips-only project works. But if the project also has a configured policy with a variadic slot, every order must still fill that slot, so a tip-only order on such a project is rejected with variadic_entry_required. Send the variadic entry alongside the tip in that case.
Payer tips must be enabled on the project. On Lithuanian projects a tip recipient may additionally need tax-agent consent: an order is rejected with tip_beneficiary_consent_not_given only when the recipient's consent is explicitly not_given. A recipient with no consent record on file (consent_status: null) is not gated โ this is the case for beneficiaries you register through the integration API, so they are never consent-blocked. Consent status is exposed as consent_status on the beneficiary list โ given (ok to pay), not_given (rejected), or null (no applicable consent record: non-LT/tips-disabled projects, and integration-registered recipients). Consent itself is collected by the merchant, outside the integration API.
Payment linksโ
When an order has splits, its payment link must not expire โ pass lifetime: 0. A finite lifetime would make the split impossible to settle if the link expires after the customer starts paying. A non-zero lifetime on a split order is rejected with validation_split_expiration_not_allowed.
The link amount must also equal the order's full amount for a split order โ partial-amount links are not allowed here (they are for non-split orders). A mismatch is rejected with validation_split_amount_mismatch.
Settlement and reading split outcomesโ
Split legs settle to Paysera (EVP) accounts. A leg whose recipient cannot be settled is held and retried rather than failing the order.
You learn split outcomes in two ways:
-
Webhooks โ split-payment integrations additionally receive two distribution events on the order's
callback_url:paysera.fund-distributor.distribution.recipient.settled(a recipient leg paid) andpaysera.fund-distributor.distribution.failed(the distribution failed). These use a flat envelope (the event kind is the top-leveltype):{
"id": "evt_019eba8f-f582-71ef-b404-5a20b51b8e3e",
"type": "paysera.fund-distributor.distribution.recipient.settled",
"created": 1736433570,
"payment_id": "019eba8b-8c78-7d2d-9153-640e6a9e1c8a",
"order_id": "019eba8a-ffa4-7180-a47c-319fa865dcf0",
"status": "settled",
"data": { "beneficiary_id": "019e2a8a-6dcc-7245-a24d-23e8561f8fda", "amount": 4000, "currency": "EUR" }
}For
distribution.failed,datais{ "error_code": "...", "reason": "..." }. See Webhook Events for the full reference. Two caveats: held legs are not surfaced as their own event; andrecipient.settledidentifies the leg bybeneficiary_id, so legs paid to a directaccount(override mode) and the merchant's own leg are not individually reported. -
Order read โ
GET /merchant-order/integration/v1/orders/{id}returnssplit_config_id(the split configuration's id, ornullif the order has no splits). It tells you an order has splits; it does not return the per-leg rules or settlement status โ use the webhooks for per-leg outcomes.
Testing and operational notesโ
- No sandbox. Checkout has no separate test environment; you integrate against production (
https://api.paysera.com). Because splits move real money to third parties, test with small amounts. You can inspect webhook deliveries with a tool like webhook.site or a tunneled local URL. - No idempotency key on order/link/beneficiary creation. Retrying
POST .../orderscreates a second order (the orderreferenceis not unique โ the server-generated order id is the unique key), so guard order and link retries on your side. Retrying beneficiary registration, by contrast, is safe: a duplicate account returns409 conflictโ treat that as already-registered and fetch its id from the beneficiary list. (Refunds, by contrast, take anidempotency-keyheader โ see Refunds.) - Recipients must already hold a Paysera account. The integration API references existing Paysera (EVP) accounts; it does not open them. A seller, courier, or staff member receiving funds signs up for their own Paysera account at paysera.com and gives you their EVP account number (you collect it during your own onboarding); provisioning recipient accounts is out of scope of the integration API.
End-to-end example โ variadicโ
A marketplace order: the platform keeps a 10% commission (configured on the policy), the remainder goes to the seller (chosen per order).
# 1. Register the seller as a beneficiary (once) โ keep the returned id
curl -X POST https://api.paysera.com/checkout-project/integration/v1/split-beneficiaries \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "account_number": "EVP5210018145214", "name": "Seller #12345" }'
# 2. Create the order, pointing the variadic entry at the seller's beneficiary_id
curl -X POST https://api.paysera.com/merchant-order/integration/v1/orders \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"purchase": { "reference": "ORDER-12345", "amount": 100000, "currency": "EUR" },
"splits": [
{ "type": "variadic", "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000" }
]
}'
# 3. Create a non-expiring payment link for that order
curl -X POST https://api.paysera.com/checkout-payment-link/integration/v1/payment-links \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"order_id": "ORDER_ID_FROM_PREVIOUS_STEP",
"name": "Marketplace order #12345",
"lifetime": 0,
"experience": { "language": "en" },
"purchase": { "amount": 100000 }
}'
End-to-end example โ tipโ
A restaurant order with payer tips enabled. The bill follows the policy; one tip entry routes any tip the payer adds to the staff member's beneficiary.
# 1. Register the staff member (once)
curl -X POST https://api.paysera.com/checkout-project/integration/v1/split-beneficiaries \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "account_number": "EVP5210018145214", "name": "Waiter โ Jane" }'
# 2. Create the order with a tip entry
curl -X POST https://api.paysera.com/merchant-order/integration/v1/orders \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"purchase": { "reference": "ORDER-67890", "amount": 100000, "currency": "EUR" },
"splits": [
{ "type": "tip", "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000" }
]
}'
# 3. Create a non-expiring payment link (lifetime: 0) as above.
End-to-end example โ per-order overrideโ
A one-off order that pays a courier directly (by account, no registration) and keeps the rest, overriding the saved policy for this order only.
# 1. Read the policy to get slot_ids and roles
curl https://api.paysera.com/checkout-project/integration/v1/project/split-policy \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# 2. Create the order, restating every slot
curl -X POST https://api.paysera.com/merchant-order/integration/v1/orders \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"purchase": { "reference": "ORDER-99001", "amount": 100000, "currency": "EUR" },
"split_overrides": {
"slots": [
{ "slot_id": "MERCHANT_SLOT_ID", "type": "remainder" },
{ "slot_id": "VARIADIC_SLOT_ID", "type": "fixed", "value": 1500,
"recipient": { "account": "EVP5210018145214" } }
]
}
}'