Payouts, balances & fees
Every TPA settles into a balance account at the acquirer. This page covers how funds flow out of it, how to observe that over the API, and how fees are taken along the way.The money model in 30 seconds
- Standalone TPAs (
non_mor) — each merchant is the legal merchant. The net remainder settles to their balance account, and Tagada pays out to their bank. Your markup is carved out automatically at charge time and lands on your partner balance account — you never have to invoice or collect it. - MoR sub-merchants (
mor) — you are the Merchant-of-Record. All sub-merchants share your root TPA’s balance account: the whole net remainder (after Tagada’s commission) settles to you, and Tagada pays out to your bank. Redistributing to sub-merchants is your responsibility, off-platform. Your “fees” are implicit: you receive everything and keep your share when you redistribute.
MoR partners: always query your root TPA. Sub-merchant children (
parentTpaId set) have no balance account or payouts of their own — payout and ledger data lives on the parent TPA. Money-movement operations are blocked on children by design.Prerequisite: a payout bank account
Payouts require a bank account registered on the TPA (the bank must belong to the TPA’s legal entity). Once it’s on file, Tagada wires the daily bank sweep: any positive settled balance is pushed to the bank automatically. If your TPA processes but has no bank account registered yet, funds simply accumulate safely on the balance account — nothing is lost, payouts start as soon as banking details are in place. Register the account withtpas.createBankAccount() (or submit the banking.iban requirement via tpas.requirements.update() during onboarding).
Check which bank accounts are on file
tpas.getBanking() lists the registered payout bank accounts, masked — one per currency, plus an optional catch-all that receives converted residual balances:
GET https://api.tagadapay.io/api/tagadapay/v1/partner/tpas/:id/banking.
A TPA can hold one bank account per currency — each gets its own daily sweep in that currency, so EUR funds go to the EUR account and USD funds to the USD account, with no FX. MoR sub-merchants return an empty list by design — funds pool on your root TPA.
Register a bank account (self-serve)
tpas.createBankAccount() registers the payout bank account for a currency — no ops ticket needed:
POST https://api.tagadapay.io/api/tagadapay/v1/partner/tpas/:id/banking with body { "currency": "USD", "bankAccount": { … } }.
Bank account fields by country: { iban } (SEPA) · { accountNumber, routingNumber, country: 'US' } (US) · { accountNumber, sortCode } (UK) · { accountNumber, bsb } (AU). Always pass holderName.
Rules to know:
status: 'pending'first. The acquirer verifies the bank belongs to the TPA’s legal entity (name matching, sometimes a bank statement). It flips toactiveautomatically — pollgetBanking(). Funds accumulate safely on the balance while verification runs.- Adding is self-serve, replacing is not. A currency that already has an account returns
409 bank_account_exists— bank swaps are the classic payout-fraud vector, so replacements stay ops-reviewed. Contact your account manager. - MoR sub-merchants →
409 mor_sub_merchant_banking. Register on your root TPA; children share its balance. - Pairs with acquiring routes:
enableRoute('EUR')makes EUR settle natively, this endpoint makes it pay out natively. Without the matching bank account, the sweep converts at payout.
Read your payouts over the API
Payout history (bank settlements) is on the Processing API — same base and auth as charging: a Processing Key (tp_sk_…) scoped to the TPA, or your Partner Key with the account parameter.
GET https://api.tagadapay.io/api/tagadapay/v1/payouts?account=tpa_xxx.
Trigger a payout on demand
Don’t want to wait for the daily sweep?tpas.payout() pays the available balance to the TPA’s registered bank account immediately:
POST https://api.tagadapay.io/api/tagadapay/v1/partner/tpas/:id/payout (body { "amountMinor": 50000 } optional).
What is paid: available balance − rolling reserve − outstanding debt, same engine and safety gates as the automated sweep. When no payout is possible the call returns 409 with skipped: true and a reason:
A verified bank account must be on file (see prerequisite above) — otherwise the payout is refused with an explicit error. On multi-currency balances the payout targets the largest balance covered by an active bank account in that currency; check coverage first with
tpas.getBanking().Read your live balance
balance.retrieve() reads the balance live from the acquirer at request time — no waiting for ledger ingestion. One bucket per currency, in minor units:
GET https://api.tagadapay.io/api/tagadapay/v1/balance?account=tpa_xxx.
availableMinor— settled funds, eligible for the next bank sweep.pendingMinor— captured but not yet settled (“available soon”).reservedMinor— held back as reserve.- Stripe-backed TPAs also return
instantAvailableMinor(instant-payout-eligible subset).
MoR sub-merchants share the root balance. Querying a sub-merchant child returns the root TPA’s shared balance (
shared: true, heldBy = the root) — there is no per-sub-merchant balance. For that reason the call requires a key authorized for the root TPA (your partner key qualifies); a key scoped to the sub-merchant alone gets a 403 shared_balance_access_denied.409 balance_unavailable.
Which currency do funds settle in? Each charge settles in the currency of its acquiring route — by default your TPA’s home currency (other currencies are converted at settlement). To settle EUR charges natively in EUR (no FX), enable an acquiring route: see Settlement currencies & acquiring routes.
Read your balance ledger (fees included)
The balance transactions ledger shows every movement on the balance account — charges credited, refunds debited, payouts leaving — with the fee breakdown per entry:GET https://api.tagadapay.io/api/tagadapay/v1/balance_transactions?account=tpa_xxx.
The same key also gives you charges.list, disputes.list and chargebackAlerts.list on the same base — see API keys.
Ledger depth varies by acquirer. Stripe-backed TPAs have full per-entry fee detail today. For Adyen-backed TPAs the enriched per-entry ledger is progressively rolling out — payout history is live, and the detailed fee ledger is being backfilled. If a query returns less than you expect, it’s an ingestion-coverage matter, not missing money: the balance account at the acquirer is always the source of truth, and your account manager can pull a full statement on demand.
Payout webhooks
Rather than polling, subscribe your TPA webhook endpoint to money-movement events:payout.created,payout.paid,payout.failedbalance_transaction.createdplatform_fee.created/partner_fee.created(and.refunded)
How fees are collected
You never have to collect anything — fees are carved out at charge time via acquirer-level splits:
Your contractual pricing (buy rate, markup grid, passthrough fees) is queryable at any time:
tpas.create({ markup }) or later with tpas.updateMarkup() replaces your partner-level grid for that merchant. See Accounts → Per-merchant pricing.
For MoR, remember the simplification: there is no per-sub-merchant markup settlement — everything net of Tagada’s commission lands on your root balance account, and your margin is whatever you keep when redistributing.
What’s coming next
Actively being built (talk to your account manager for timelines):- Full Adyen per-entry fee ledger — interchange / scheme / commission breakdown per settlement line.
- Partner-level rollup — payouts and earnings aggregated across all your merchants and sub-merchants in one call, plus a partner dashboard view.
