Processing provisioning (TPAs)
To process payments through TagadaPay, a merchant needs a TagadaPay Account (TPA) — identifier prefixtpa_xxx. The TPA is the unit of KYB, payment routing, settlement, and authorization scope on the Processing domain (/api/tagadapay/v1/partner/*).
A merchant (
acc_xxx) can own 0..N TPAs (tpa_xxx). One TPA per settlement region is the common pattern (e.g. an EU TPA and a US TPA under the same merchant). Provision a merchant first, then attach TPAs to it via accountId.What gets created
stores.list({ accountId }). If you pass an accountId, the TPA attaches to that existing merchant; otherwise the surface infers/creates the owning merchant from the calling key.
The merchant is never auto-invited to TagadaPay. No welcome email and no portal login are created automatically. Your platform remains the primary interface unless you later request merchant portal access through your account manager.
The onboarding sequence
Driving a TPA from creation toactive is always the same five steps, in order:
banking.*(bank account) — without it the merchant can never be paid out. Submit it with the other requirements, don’t defer it.- Documents — after
provision()runs, calldocuments.list()and look forstatus: 'rejected': therejectionReasontells you exactly what to fix.
Create a TPA
US businesses are supported. Pass
country: 'US' (and typically currency: 'USD') — the KYB requirement set adapts to the entity’s country (e.g. EIN + US bank details instead of an EU VAT number + IBAN). The rest of the flow (requirements → documents → provision()) is identical.Who assigns the acquirer — two partner situations
What happens after processing intake depends on whether you have signed payfac / processing terms with TagadaPay:- Processing partner (signed acquirers)
- CRM-only partner (no processing contract)
You have an active buy-rate annex + PSP schedule for at least one acquirer (
acquirers.list() returns them). Two options:- Pin the acquirer yourself: pass
acquirer: 'adyen'atcreate(). The TPA skips the operator queue and goes straight topending_provisioning— you own the full self-serve path toactive. - Let the router pick: omit
acquirerand, if your partner profile has a default routing config, the TPA is auto-assigned from your signed set.
entityId/submit lifecycle as tagadapay.io/apply, partner-branded — or push data yourself via requirements / documents (API intake).Capability matrix — CRM-only vs processing partner
The SDK surface is mostly shared. What changes for CRM-only is that entity applications replace shelltpas.create:
Idempotency
Callingcreate() again with the same externalRef returns the same TPA — no duplicates, safe to retry:
(partnerId, externalRef) pair is permanent. Use a stable, unique ref — when a merchant has multiple TPAs, suffix your own id (merchant_42_eu, merchant_42_us).
Per-merchant pricing (markup)
Each merchant’s price is Tagada’s buy rate (your signed annex) + a markup — your margin. By default the markup is your partner-level grid (seeacquirers.list()), but you can price any merchant individually:
- Pass
markupattpas.create()(above), or - Set / change it at any time — the new price applies to the very next charge:
- Wholesale replacement, not a merge. A per-TPA markup replaces your partner-level grid entirely for that merchant — fields you omit mean “no margin on that fee”.
updateMarkup('tpa_xxx', {})prices the merchant at Tagada’s buy rate (zero margin for you). - Additive only. Every field must be ≥ 0 — you can never price a merchant below Tagada’s signed buy rate.
- Instant. The call refreshes the TPA’s charge-time price snapshot before returning;
sellRatein the response is what the merchant pays from the next charge on. - Your margin is carved out per charge and lands on your partner balance account automatically — see Payouts, balances & fees.
GET | PUT | DELETE https://api.tagadapay.io/api/tagadapay/v1/partner/tpas/:id/markup.
Retrieve / list
There is no general “update TPA fields” endpoint. Status transitions and KYB outcomes are operator-driven (your account manager moves them, or our auto-router does), so they are not settable from the SDK. Store ↔ processor routing is handled by the CRM payment orchestration layer.
Mint a Processing Key
A Processing Key (tp_sk_…) is scoped to this one TPA and used for charging and reporting.
KYB requirements
Every newly-created TPA is seeded with a default set of KYB requirements:US merchants: the US has no separate company registration number, so the
federal EIN (e.g.
98-1923816) is both business.tax_id and
business.registration_number — submit the same 9-digit value for both.applicationPreferences.defaultRequirements — talk to your account manager.
List + satisfy requirements
pending_verification — never directly to satisfied. Tagada ops (or a downstream provider) verify the value before it becomes satisfied. Document requirements (documents.*) are satisfied by documents.record(), not this call.
Upload a document (recommended)
The most reliable way to submit a document is to send the bytes directly — no storage URL to keep alive:Record a document by URL
Alternatively,record() a storageUrl. The URL must be fetchable server-to-server at the moment you call record() — we download and pin a copy immediately. Private buckets or already-expired presigned URLs are rejected with 422 document_unreachable (a presigned URL that is valid now is fine, even if it expires later). The signature is record(tpaId, params):
Accepted kind values
kind is validated at the API boundary: an unknown value (e.g. your own internal enum like INCORPORATION_CERTIFICATE) is rejected immediately with 400 invalid_document_kind listing the accepted values — it can never sit in the pipeline and fail silently later. Obvious variants are normalized for you (case/separators, certificate_of_incorporation → company_registration, driving_license → drivers_license, …), but send the canonical value. Specific identity kinds (passport, drivers_license, national_id) are also accepted when you know the exact document type.
Validation & idempotency
Recording a document linked to a requirement automatically flips that requirement to
pending_verification. We don’t auto-approve — manual review (or processor-driven verification) flips it to satisfied.
Run provisioning
Once requirements and documents are in, callprovision() — and treat it as a converge loop, not a one-shot:
Fix what the response points at, then call
provision() again — completed steps are never redone.
The merchant agreement (mandatory signature)
Signing the Merchant Service Agreement is a hard activation condition for every live TPA. You never send it yourself: once provisioning completes, Tagada emails the signing request to the merchant representative automatically. How the contract is branded depends on your partnership tier:active automatically the moment the required signatures are in — no further API call needed. Test-mode TPAs and MoR sub-merchants never require a signature (required: false).
Common integration mistakes
Merchant portal access policy
By default, sub-merchants have no TagadaPay portal access — they use your platform, not ours. If you ever want a specific merchant to be able to log in directly to TagadaPay, three policy modes exist:
Set the partner-wide default via
applicationPreferences.merchantPortalAccess (talk to your account manager), or override per-TPA at creation time.
For the typical embedded-payments partner (your merchants don’t know TagadaPay exists),
'never' is the right setting and prevents any accidental email leak.