Skip to main content

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 by beneficiary_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 registered beneficiary_id or a Paysera account number paid directly, without prior registration.
Activation required

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.

Prerequisites

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 the account field, 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โ€‹

  1. Have the merchant request activation (support enables the features and sets up the policy).
  2. Read the split policy to learn its slot_ids and roles.
  3. Register beneficiaries for the recipients you will reference by id.
  4. On each order, attach splits and/or split_overrides.
  5. 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 }
]
}
FieldTypeDescription
configuredbooleanWhether the policy template is fully set up. An order with splits fails if this is false.
slots[].slot_idstring (UUID)Stable id of the slot. Bind variadic entries and overrides to this value.
slots[].positioninteger0-based order of the slot in the policy.
slots[].rolestringmerchant, beneficiary (fixed recipient), or variadic (per-order recipient).
slots[].rule_typestringfixed, percentage, remainder, or null (not yet configured).
slots[].valueintegerCents for fixed; basis points for percentage (1 bp = 0.01%; 10000 = 100%); null for remainder.
slots[].beneficiary_idstring (UUID)Fixed recipient configured on the slot, if any.
slots[].beneficiary_account_numberstringThe fixed recipient's EVP account, if any.
slots[].beneficiary_namestringThe fixed recipient's display name, if any.
slots[].beneficiary_missingbooleantrue 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
}
FieldTypeRequiredDescription
account_numberstringโœ“Recipient's Paysera EVP account (EVP followed by digits). Must exist and not be the merchant's own account.
namestringโœ“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 account

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.

FieldTypeRequiredDescription
splits[].typestringโœ“variadic or tip
splits[].beneficiary_idstring (UUID)โœ“Id of the registered beneficiary to pay
splits[].slot_idstring (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, set slot_id on 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 / value per slot: fixed โ†’ cents (value > 0); percentage โ†’ basis points (1โ€“10000); remainder โ†’ omit value. Exactly one remainder slot is required, and the percentage slots must sum to less than 100%.
  • recipient per slot โ€” provide exactly one of beneficiary_id or account:
    • 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 variadic slot, optional for a beneficiary slot (supplying it replaces the policy recipient), and must be omitted for the merchant slot.
FieldTypeRequiredDescription
split_overrides.slots[].slot_idstring (UUID)โœ“Which policy slot is being restated
split_overrides.slots[].typestringโœ“fixed, percentage, or remainder
split_overrides.slots[].valueintegerconditionalCents (fixed) or basis points (percentage); omit for remainder
split_overrides.slots[].recipient.beneficiary_idstring (UUID)conditionalRegistered beneficiary (exactly one of beneficiary_id / account)
split_overrides.slots[].recipient.accountstringconditionalPaysera EVP account paid directly, no registration
Tips with overrides

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" }
]
}

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.

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) and paysera.fund-distributor.distribution.failed (the distribution failed). These use a flat envelope (the event kind is the top-level type):

    {
    "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, data is { "error_code": "...", "reason": "..." }. See Webhook Events for the full reference. Two caveats: held legs are not surfaced as their own event; and recipient.settled identifies the leg by beneficiary_id, so legs paid to a direct account (override mode) and the merchant's own leg are not individually reported.

  • Order read โ€” GET /merchant-order/integration/v1/orders/{id} returns split_config_id (the split configuration's id, or null if 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 .../orders creates a second order (the order reference is 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 returns 409 conflict โ€” treat that as already-registered and fetch its id from the beneficiary list. (Refunds, by contrast, take an idempotency-key header โ€” 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" } }
]
}
}'

Errorsโ€‹

When a split request is rejected, the API returns an error code naming the specific problem. Match on the code programmatically. Request-validation problems return 400; policy, beneficiary, and override conflicts return 422. Some codes add details under error_properties.

The most common ones:

CodeHTTPMeaningResolution
intermediary_account_required400The project's split setup is not complete on Paysera's sideAsk the merchant to request split activation from Paysera support
invalid_properties400Request validation failed โ€” e.g. splits[].type not variadic/tip, or split_overrides.slots[].type not fixed/percentage/remainder. Offending fields are under error_propertiesFix the fields named in error_properties
validation_split_expiration_not_allowed400A split order's payment link has a finite lifetimeSet lifetime: 0 on the payment link
validation_split_amount_mismatch400A split order's payment link amount does not equal the order's full amountSet the link amount equal to the order amount
variadic_entry_required422The policy has a variadic slot but no variadic entry was sentAdd a {type:"variadic", beneficiary_id:"..."} entry
split_beneficiary_not_found422A beneficiary_id is not registered for the projectRegister the beneficiary, then reference its id
tip_entries_without_tips_enabled422Tip entries were sent but payer tips are disabledHave payer tips enabled, or drop the tip entries
overrides_not_enabled422Per-order overrides are not enabled on the projectRequest the per-order overrides capability (Paysera support)
split_overrides_incomplete422Not every policy slot was restated in split_overridesRestate every policy slot exactly once

See Split Payment Errors for the complete list โ€” including all variadic slot_id, override, and recipient-resolution codes and the error_properties they carry.

  • Payment Orders โ€” adding splits[] / split_overrides to order creation
  • Payment Links โ€” lifetime constraints when splits are active
  • Webhook Events โ€” distribution (recipient.settled / failed) webhook payloads
  • Error Codes โ€” full split error reference