split_type: "percentage"(default) — split off a percentage of the deposit’s credited amount, capped by the platform’smax_split_percentage(§1).split_type: "fixed"— split off a fixed amount in the deposit’s own currency, viafixed_amount. Must be less than or equal to the deposit’s net credited amount — if it isn’t, deposit creation is rejected up front (§2 errors) rather than letting the deposit succeed with a split that can never actually clear.
Environments
- Sandbox API:
https://smtp.yativo.com - Production API:
https://api.yativo.com
Authentication
Every endpoint needs an authenticated request, and the account must have passed KYC. Server-to-server requests use your team’s API key and secret:Authorization: Bearer <ACCESS_TOKEN>
instead. Since 15 October 2026, bearer tokens are only accepted from the
dashboard, and the legacy POST /api/v1/auth/login (account_id +
app_secret) flow is deprecated. Don’t send a bearer token together with the
key pair. See Authentication.
How It Works
- You create a deposit as usual (
POST /api/v1/wallet/deposits/new), and attach an optionalrevenue_splitobject to that same request body. - If present, it’s validated immediately (destination ownership, percentage
range/cap) — an invalid
revenue_splitpayload rejects the whole deposit-creation call before anything is created. - The deposit proceeds through its normal payment flow (checkout URL, wire instructions, etc. — unchanged). Splitting never happens at creation time.
- Once — and only once — that specific deposit’s status flips to
success(confirmed by the payment provider), the requested percentage is:- transferred instantly to another Yativo account’s wallet
(
destination_type: internal_wallet), or - paid out to one of your saved beneficiaries
(
destination_type: beneficiary) — through the exact same payout pipeline asPOST /api/v1/wallet/payout, so normal processing times for that beneficiary’s rail apply.
- transferred instantly to another Yativo account’s wallet
(
- The attempt (successful, failed, or skipped) is recorded and visible via
GET /api/v1/revenue-split/executions.
Important constraints
- Opt-in, per deposit. Omit
revenue_splitentirely and nothing changes about that deposit — 100% of it lands in your wallet as normal. There’s nothing to “turn off” elsewhere; just don’t send it. - No FX conversion. A
beneficiarysplit pays out in the same currency the deposit is credited in. If your beneficiary’s rail requires a different settlement currency, use the regular manual withdrawal flow instead for that leg. - The beneficiary must belong to you.
beneficiary_payment_method_idmust reference a payment method already saved under your own account (fromPOST /api/v1/beneficiary/form/createor the withdrawal beneficiary endpoints). - The sub-account must be a different Yativo account. An
internal_walletsplit’sdestination_user_idcannot be your ownuser_id— it’s another Yativo platform account, not one of your ownCustomerrecords. - Percentage is capped platform-wide. An admin sets a maximum
split_percentageany single deposit is allowed to request (default 100%).GET /api/v1/revenue-split/settingstells you the current cap. - Only deposits you actively create can be split. This only applies to
deposits created through
POST /api/v1/wallet/deposits/new(the endpoint documented below). Funds that arrive passively into a standing virtual account or crypto wallet address — i.e. you never called an API to create that specific incoming payment — have norevenue_splitto attach and are never split. - Idempotent and safe on retries. A given deposit only ever triggers its split once — repeated webhook deliveries or status re-saves for the same deposit will not double-split it.
Response Envelope
Every endpoint returns one of two shapes. Non-paginated success/error:executions):
Gotcha — HTTP status on success is always200. Thestatus_codefield inside the JSON body is decorative (may show201, etc.); branch on thestatusfield (“success” vs “failed”), not the raw HTTP status, to detect success. Error responses do use a real, meaningful HTTP status.
Gotcha — decimal fields are strings.split_percentage,source_amount,fixed_amount,split_amount,payout_fee_amount,net_payout_amountare MySQLdecimalcolumns and are serialized as strings (e.g."5.00"), not JSON numbers. Run them throughparseFloat()/Number()before doing arithmetic.
1) Check Platform Settings
Read-only. Tells you whether the feature is enabled, and the maximum percentage any single deposit’s split can request.Endpoint
Sample Response
eligible_currencies: null means every currency is eligible. If it’s an
array (e.g. ["USD", "EUR"]), a revenue_split on a deposit in any other
currency is silently never executed (the deposit itself still succeeds
normally).
2) Create a Deposit With a Revenue Split
Endpoint
gateway, amount,
currency, customer_id, return_url, and any gateway-specific fields all
work exactly as they do without a split. revenue_split is the only new,
fully optional field.
Request Body — Split to an Internal Sub-Account
Request Body — Split to an External Beneficiary
Request Body — Fixed Amount Instead of a Percentage
fixed_amount is in the deposit’s own currency (ARS here) and must be
<= the deposit’s net credited amount (calc.credited_amount — the amount
after deposit fees, not the raw amount you sent). Requesting a fixed
amount larger than that always fails deposit creation with a 400 (§2
errors) — it can never be satisfied by retrying.
Request Body — No Split (unchanged, existing behavior)
revenue_split fields
Sample Response
Identical to a normal deposit-creation response, plus an echoedrevenue_split block confirming what was captured:
deposit_url (or show the returned wire/QR/reference
instructions) so they can actually complete payment, same as always.
Errors
Sent back as a normal deposit-creation error — the deposit is not created at all ifrevenue_split fails validation:
After that field-level validation passes, the split is also previewed
against the deposit’s actual computed credited amount before the deposit is
created (simulating the eventual payout’s fees and the destination
gateway’s min/max limits), so a split that could never clear isn’t allowed
to exist as a “pending forever” liability:
3) Wait for the Deposit to Complete
Creating the deposit never credits your wallet, and never executes the split, by itself. Every payin rail is asynchronous: the deposit is createdpending/processing, and only flips to success once the
payment provider confirms funds landed — which Yativo receives via that
provider’s own webhook. The split fires at that exact success transition,
the same moment your own wallet gets credited.
Poll for the transition:
status is one of pending, processing, success, failed,
cancelled, expired. The instant it flips to success, check §4 below —
the resulting split execution is already there.
4) List Split Execution History
Paginated audit log of every split that’s run (or was skipped) on your deposits, most recent first. Use this to reconcile “where did the rest of my deposit go” or to confirm a specific deposit’s split actually landed.Endpoint
Sample Response
source_deposit_id matches the id from the deposit-creation response
(deposit_data.id) — that’s how you tie an execution back to the deposit
that triggered it. source_amount is the deposit’s credited amount the
percentage was applied to; split_amount is what actually moved.
status values
End-to-End Example (JavaScript)
Quick Reference
Admin
Platform admins manage the global guardrails and oversee every business’s split executions from the admin panel:- Default Settings —
/admin/revenue-split-settings— enable/disable the feature globally, set the max split percentage any deposit can request, minimum deposit amount, and eligible currencies. - Executions —
/admin/revenue-split-executions— the full audit trail across every business, filterable by status and business.

