Server-to-server payments
Once you have a Processing Key (tp_sk_…) + a storeId, the entire payment lifecycle is yours. No checkout session, no funnel, no UI assumptions on our side.
The four steps
Step 1 — Tokenize the card (browser)
Use@tagadapay/core-js. The card data goes directly to BasisTheory’s vault — never to your server, never to ours:
Alternative: you already hold the card (server-side tokenization)
If you are already PCI-compliant and hold card numbers in your own environment (your own vault, your own collection form), you can skip the browser step entirely and hand the card to the SDK from your server. It tokenizes straight into Tagada’s PCI vault and returns a ready payment instrument — steps 1 and 2 in one call.Where the card goes.
createFromCard() posts the card from your process straight to Tagada’s
PCI vault over TLS, then sends only the resulting vault token to the Tagada API. The card number and
CVC never reach the Tagada API and are never logged. Your PCI scope is unchanged — it is already
whatever it was before, since you were holding the PAN; ours stays out of it.paymentInstrument.
Step 2 — Create a payment instrument (server)
Convert the single-usetagadaToken into a reusable paymentInstrument:
customer is reused if you provide a matching email — one customer can hold multiple instruments.
Address field names. The platform stores and validates addresses as
address1, address2, postal, city, state, country (ISO 3166-1 alpha-2), plus firstName / lastName. The SDK still accepts the legacy line1 / line2 / postalCode aliases and maps them for you, but prefer the canonical names.Addresses are optional — including for digital products. Neither
billingAddress nor shippingAddress is required to charge: selling digital goods with no shipping address works out of the box. If you do provide an address, it is only forwarded to the acquirer when it carries a valid ISO 3166-1 alpha-2 country — an incomplete address (e.g. missing country) is safely omitted from the acquirer call instead of failing the payment. Providing a complete billingAddress is still recommended: it improves issuer approval rates (AVS) and 3DS frictionless outcomes.Step 3 — 3DS (usually nothing to do)
Most integrations skip this step. Whether 3-D Secure runs, and how, is decided by the PSP/acquirer behind your TPA — and most of them handle it themselves. There are two ways it can happen:
Option 1 — PSP/acquirer-hosted 3DS (the default)
Modern PSPs (Adyen, Stripe, …) own the 3DS challenge. You don’t callthreeds.createSession. You just charge (Step 4) with a returnUrl; if the issuer requires SCA, payments.process comes back with requireAction: 'redirect' and a redirectUrl pointing at the processor’s own hosted 3DS page. You send the customer there, they authenticate, and they return to your returnUrl. Nothing to collect, nothing to pass through — the processor reconciles the authentication internally.
This is the path the rest of this guide uses. If your TPA is on a hosted-3DS PSP, ignore the code below and go straight to Step 4.
Option 2 — Tagada standalone 3DS (the exception)
Some gateway-style processors (e.g. NMI) don’t host 3DS, but they do accept pre-authenticated 3DS values (CAVV, ECI, DS transaction id…) on the charge. For those — and only when the acquirer is compatible and takes those values as input — Tagada can run the 3DS flow for you, collect the values, and pass them raw to the acquirer. You opt in explicitly:Option 3 — Bring your own 3DS (you already run an MPI)
You collect cards and run 3-D Secure in your own PCI environment — your own 3DS server, Basis Theory 3DS, Ravelin, … — and only want Tagada to charge. Don’t run a second authentication: report the final values and Tagada stores them as an already-authenticated session.- Only
transStatusY/Acreate a usable session.N/U/R/Iare stored as failed and the charge is declined at the 3DS step. dsTransIDis mandatory for an authenticated 3DS 2.x result — acquirers reject the charge without it.- The target processor must accept externally-authenticated values: NMI, RouteSense, Mastercard MPGS, Adyen, Airwallex. Hosted-3DS PSPs (Stripe, Checkout.com) ignore them and run their own 3DS (Option 1). The processor needs
enable3DSon and the payment flowthreeDsEnabled. - For a MIT on a card you authenticated once (3RI), create the session with
type: 'merchant'and charge withinitiatedBy: 'merchant'+reasonType.
When does 3DS trigger? When the card flow has
threeDsEnabled: true (set per-merchant via Payment Flows) or the issuer requests SCA. How it runs is up to the processor: hosted PSPs return requireAction: 'redirect' (Option 1); gateways that need raw values use the standalone session (Option 2). When in doubt, skip this step and just handle the requireAction that the charge returns.Step 4 — Charge
Handling the response
Multi-TPA routing (cascade & weighted)
payments.process doesn’t hit a processor directly — it runs the payment
flow attached to the storeId. A single merchant can own several TPAs (e.g. an
Adyen sub-merchant and a Stripe Merchant-of-Record account) and route across
them with no code change on your side: same process call, different
storeId.
- Cascade (failover) — the flow has a primary processor and an ordered
fallback list (
fallbackMode: true). If the primary declines (non-terminal), Tagada automatically retries the same charge on the next TPA, with a fresh payment method per attempt. Your code just sees the finalcaptured. - Weighted — multiple processors with weights; each charge is routed to one TPA by weight.
A processing key restricted to one TPA resolves to that TPA’s merchant
account, so it can charge any store of that merchant — including a store
whose flow spans several of the merchant’s TPAs. You don’t need a separate key
per processor.
partners-examples/02-merchant-checkout.
Auth + capture (split-flow)
Authorize now, capture later (hotels, car rentals, pre-orders, marketplaces):payments.cancel(auth.id) to release the authorization without capturing.
Refunds
Full refund:Merchant-initiated transactions (MIT)
For subscription renewals, retry logic, or any charge initiated without the customer present:Listing and retrieving payments
Webhooks
To learn about asynchronous events (3DS callbacks, settlement, disputes), set up webhooks at the TPA level:Errors you should handle
The SDK throws typed errors:
