Transak
Developer-first ramp with the widest local rails.
What it is
Transak is a fiat-to-crypto on/off-ramp built around a white-label, embedded developer experience. Apps drop in a widget or SDK and Transak handles KYC, payment acceptance, fraud, fiat settlement, and the on-chain payout. Beyond plain buy/sell it offers Transak One (fund a smart-contract interaction with fiat in a single transaction) and Stream (send crypto to a personal deposit address and get auto fiat payout). It covers 100+ countries, 70+ fiat currencies, 130+ cryptocurrencies, and 75+ blockchains.
How it works
- A developer registers for an API key, then calls the Create Widget URL API server-side with widget params to mint a short-lived, single-use widgetUrl (sessionId).
- The @transak/ui-js-sdk renders that widgetUrl as a hosted/embedded iframe; the user completes KYC once and pays via a local rail.
- Pay-in rails: UPI (India), PIX (Brazil), SEPA Instant (EU), ACH + card (US), Faster Payments (UK), PayID (AU) — Transak sources crypto liquidity and pays out to the user's wallet.
- Off-ramp: the reverse via the widget, or via Stream — a one-time setup provisions a per-asset/per-network deposit address; any crypto sent there auto-pays fiat to the registered bank/card.
- Transak One: the partner passes a smart-contract address + calldata; Transak converts fiat to the source token and executes the contract call (mint, deposit, swap, stake) in one transaction, delivering receipt tokens to the user.
- Order state flows back to the partner via the SDK events, the Get Order(s) REST API, webhooks (JWT-encrypted), and WebSockets.
Differentiators
- Widest local payment-method coverage of any ramp — deep emerging-market rails (UPI, PIX) plus EU/US/UK/AU instant rails.
- White-label + server-side widget-URL model keeps the API key off the client and lets partners pre-configure the entire flow.
- Transak One turns a ramp into a payments primitive: fiat straight into an arbitrary smart-contract call, not just a wallet balance.
- Broad multi-jurisdiction licensing (US FinCEN MSB, UK FCA, EU VASP, Canada, Australia, India) underpins 100+ markets and 75+ chains across 450+ integrations.
Business model
Spread + fee on each on/off-ramp transaction (card typically ~3.5–5.5%, lower for bank/local rails by region) [verify exact tiers]; revenue share with partners on volume.
Depends on
- Local payment rails (UPI, PIX, SEPA, ACH, Faster Payments, PayID)
- Card networks & banking partners
- Liquidity / market makers for crypto pricing + FX
- Supported chains and stablecoin issuers (USDC, USDT, EURC, USDG)
Risks
- Compliance overhead across 100+ countries with divergent VASP/MSB regimes (MiCA in the EU, MTLs in the US).
- Card fraud + chargebacks on the on-ramp; FX/liquidity volatility in emerging-market corridors.
- Fee pressure as ramps commoditize (e.g. Coinbase zero-fee USDC).
- Reliance on a single-use, 5-minute widget URL adds a server round-trip that partners must wire up correctly.
The product lines
On-Ramp
Buy crypto with local fiat rails.An embeddable widget/SDK that lets a partner's users buy 130+ cryptocurrencies across 75+ chains with cards or local bank rails, after a one-time KYC. The differentiator is breadth of local pay-in methods.
- User picks asset + amount; pays via UPI, PIX, SEPA Instant, ACH, Faster Payments, PayID, or card.
- Transak sources crypto liquidity, charges a fee/spread, and pays out on-chain to the user's wallet.
- Partner pre-configures asset/network/amount/wallet via widget params; KYC is reused across sessions.
Off-Ramp
Sell crypto to fiat via the widget.The reverse flow — users sell crypto and receive fiat to a bank account or card, handled in the same embedded widget with KYC and payout compliance built in.
- User sends crypto to Transak; fiat is paid out to a registered bank/card.
- SEPA Instant and fast-funds-eligible cards settle quickly; standard rails take longer.
- Live in 40+ countries with 20+ networks supported. [verify]
Transak One
Fiat straight into a smart-contract call, in one transaction.A single-transaction product where fiat is converted to a source token and used to execute an arbitrary smart-contract interaction — mint an NFT, deposit to Aave, stake, swap, borrow/lend — with receipt tokens delivered to the user's wallet. Removes the 'buy crypto, then do the thing' two-step.
- Partner passes the target smartContractAddress + calldata for the contract function.
- Transak converts fiat to the required source token, executes the call, and delivers any receipt tokens (e.g. LSTs) back to the user.
- Gas + source token amounts are estimated via params like estimatedGasLimit and sourceTokenData. [verify param names]
Stream
Address-based automatic off-ramp.A 'one-click crypto-to-fiat' off-ramp: after a one-time KYC + payout-details setup, the user gets a unique deposit address per crypto/network. Any crypto sent to that address triggers an automatic fiat payout — no widget needed per transaction.
- One-time setup: KYC + register payout bank/card.
- User is provisioned a persistent per-asset/per-network deposit address.
- Crypto sent to the address auto-converts and pays out fiat (SEPA Instant / fast-funds cards near-instant).
Architecture & mechanics
Integration flow (server-minted widget URL)
Transak's current model splits work between backend and frontend so the API key never reaches the browser. The result is a slightly heavier integration than a pure publishable-key widget, but a more secure one.
- Backend exchanges API key (+ secret) for an access token via refresh-access-token.
- Backend calls Create Widget URL with widgetParams → receives a single-use widgetUrl (sessionId), valid ~5 minutes.
- Frontend mounts the widgetUrl with @transak/ui-js-sdk into a containerId via new Transak(config).init().
- Order tracking layered: client events (TRANSAK_ORDER_CREATED/SUCCESSFUL) for UX, plus webhooks / WebSockets / Get Order By ID for truth.
Local rails & coverage
Transak's edge is the breadth of local pay-in/pay-out methods — particularly in emerging markets where card rails are weak — layered on top of standard card and instant-bank rails in developed markets.
- India: UPI; Brazil: PIX; EU: SEPA Instant; US: ACH + card; UK: Faster Payments; Australia: PayID.
- On-ramp across 64+ countries / 115+ overall, 70+ fiat currencies, 130+ crypto, 75+ chains. [verify exact counts]
- Off-ramp narrower: 40+ countries, 20+ networks, expanding.
- Stablecoin breadth includes USDC, USDT, EURC (Circle) and USDG (Paxos) for MiCA-aligned EU flows.
Compliance & licensing
A multi-jurisdiction license stack is the real moat — it's what lets partners switch on a market by changing a config rather than acquiring their own licenses.
- US: FinCEN-registered MSB; UK: FCA-registered; EU: VASP registration (migrating toward MiCA/CASP). [verify MiCA CASP status]
- Canada: FINTRAC; Australia: AUSTRAC; India: FIU-IND.
- KYC is collected once per user and reused across partner sessions; sanctions screening + fraud handled in-platform.
- Webhook payloads are JWT-encrypted with the partner's access token so order data isn't exposed in transit.
Fees & risk
- Card on-ramp fees typically ~3.5–5.5% by region; bank/local rails cheaper. [verify current tiers]
- Revenue = fee + spread on each transaction, with partner revenue-share on volume.
- Chargeback/fraud risk on card on-ramps; FX + liquidity risk in emerging-market corridors.
- Fee-compression pressure from zero-fee USDC rivals (Coinbase Onramp) and aggregators routing for best quote.
How it's built
Architecture
Transak sits between local payment rails / card acquirers / banks and the chains. Unlike a pure publishable-key model, the current flow is server-assisted: the partner backend calls the Create Widget URL API (authenticated with the API key) to encapsulate all widget params into a single-use, 5-minute widgetUrl carrying a sessionId. The frontend SDK only ever sees that opaque URL, so the API key never touches the client. Transak runs KYC, payment acceptance, fraud, liquidity sourcing, and the on-chain payout (and the reverse for off-ramp). For Transak One, Transak additionally executes a partner-supplied smart-contract call after converting fiat to the source token. Order state is pushed back via SDK events, webhooks (JWT-encrypted with the partner's access token), WebSockets, and the Get Order(s) REST API.
Integration shape
Primary path: the @transak/ui-js-sdk (successor to the legacy @transak/transak-sdk) renders the widgetUrl as a hosted or embedded iframe; one Transak instance = one widget mounted to a containerId. Native iOS, Android, React Native, and Flutter SDKs exist, plus a REST/Whitelabel API for headless flows. apiKey and referrerDomain are mandatory; productsAvailed selects BUY/SELL; the rest of the flow (asset, network, fiat, amount, wallet, payment method, partnerOrderId, redirectURL, theme) is configured via widget params.
API surface
POST Create Widget URL- Server-side: pass widgetParams (apiKey, referrerDomain, productsAvailed, cryptoCurrencyCode, network, walletAddress, fiatCurrency, fiatAmount…) → returns a single-use widgetUrl + sessionId, valid 5 minutes.
POST refresh-access-token- Exchange the API key + secret for an access token used to sign widget URLs and decrypt webhook payloads; issuing a new token invalidates the prior one.
GET Get Orders / Get Order By ID- Poll order objects and current status (e.g. AWAITING_PAYMENT_FROM_USER → PROCESSING → COMPLETED / FAILED / EXPIRED).
Webhooks- Real-time order lifecycle callbacks to the partner backend; the data field is a JWT you decrypt with your access token — treat as source of truth.
WebSockets- Live order-status stream as an alternative to polling for in-session UI updates.
new Transak(config) + transak.init()- Client SDK: mount the widget from a widgetUrl into a containerId; configure widgetHeight/widgetWidth.
transak.on(Transak.EVENTS.*)- Subscribe to TRANSAK_ORDER_CREATED, TRANSAK_ORDER_SUCCESSFUL, and TRANSAK_WIDGET_CLOSE to advance your own UI.
Minimal integration
Two-step flow: mint a widgetUrl server-side, then render + listen for the order client-side.
// 1) SERVER: mint a single-use widgetUrl (keeps the API key off the client)
const res = await fetch('https://api.transak.com/api/v2/widget-url', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: TRANSAK_API_KEY, // secret — server-side only
referrerDomain: 'rails.app',
widgetParams: {
productsAvailed: 'BUY', // or 'SELL' for off-ramp
cryptoCurrencyCode: 'USDC',
network: 'base',
fiatCurrency: 'EUR',
fiatAmount: 50,
walletAddress: '0xabc...def',
partnerOrderId: 'order_123',
},
}),
});
const { widgetUrl } = await res.json(); // valid ~5 min, single use
// 2) CLIENT: render the widget and react to order events
import { Transak } from '@transak/ui-js-sdk';
const transak = new Transak({ widgetUrl, containerId: 'transak-mount' });
transak.init();
transak.on(Transak.EVENTS.TRANSAK_ORDER_SUCCESSFUL, (order) => {
console.log('paid', order); // confirm via webhook server-side too
transak.close();
});
transak.on(Transak.EVENTS.TRANSAK_WIDGET_CLOSE, () => transak.cleanup());Build notes
- The legacy @transak/transak-sdk (apiKey + environment passed on the client) is deprecated — new integrations use @transak/ui-js-sdk with the server-minted widgetUrl. [verify the exact widget-url endpoint path/version against current docs]
- widgetUrl/sessionId is single-use and expires in ~5 minutes; mint a fresh one per user flow rather than caching it.
- Treat webhooks (JWT-decrypted with your access token) or Get Order By ID as the source of truth for settlement — the client TRANSAK_ORDER_SUCCESSFUL event only means payment was initiated.
- Use the STAGING environment + staging API key first; switch to PRODUCTION by swapping credentials.
- Transak One uses extra widget params (smartContractAddress, sourceTokenData, calldata, estimatedGasLimit, cryptoCurrencyData) to fund and execute a contract call in one transaction. [verify exact param names against docs]