How to use Authentication APIs

Onboard and authenticate users before starting a transaction
View as Markdown

In this tutorial guide, we will be exploring the user onboarding flow for Transak’s Whitelabel APIs. Before a user can place an order, they must be onboarded and authenticated. Transak supports two distinct paths for this. Transak can either own the user’s identity and authentication lifecycle, or your platform can rely on its own authentication and pass a signed token to Transak. This guide will walk you through both paths.

Two Onboarding Paths

PathWho authenticates the userBest for
Transak Onboarding APIsTransakPartners who want Transak to own the full user identity and auth lifecycle
Auth Reliance FlowPartnerPartners who already have a verified user base and want to bring their own identity

Path 1: Transak Onboarding APIs

In this path, your app calls Transak APIs to create a user account and issue a session token. Transak owns the user’s identity record. Users authenticate through Transak.

How it Works

1

Send OTP to the user

Trigger OTP delivery. Transak emails a time-limited one-time code to the user and returns a stateToken. Store this token — it is required for the verification step.

$curl -X POST https://api-gateway-stg.transak.com/api/v2/user/otp/send \
> -H "x-api-key: YOUR_API_KEY" \
> -H "x-user-ip: USER_IP_ADDRESS" \
> -H "Content-Type: application/json" \
> -d '{ "userId": "USER_ID" }'
2

Verify OTP and receive access token

The user enters the code from their email. Pass the stateToken from the previous step along with the OTP. On success, Transak returns an accessToken that authenticates all subsequent API calls for this user session.

$curl -X POST https://api-gateway-stg.transak.com/api/v2/user/otp/verify \
> -H "x-api-key: YOUR_API_KEY" \
> -H "x-user-ip: USER_IP_ADDRESS" \
> -H "Content-Type: application/json" \
> -d '{ "stateToken": "STATE_TOKEN", "otp": "123456" }'

Store the accessToken in memory (not localStorage). Attach it to every user-scoped API call as Authorization: <accessToken>.

3

Use the access token for user operations

After the user is authenticated, you can call the following APIs to retrieve user information, check transaction limits, or log out the user.

Get user details

Retrieve the authenticated user’s profile, KYC status, and account information.

$curl -X GET https://api-gateway-stg.transak.com/api/v2/user \
> -H "x-api-key: YOUR_API_KEY" \
> -H "x-user-ip: USER_IP_ADDRESS" \
> -H "Authorization: ACCESS_TOKEN"

Get user transaction limits

Check how much the user can buy or sell based on their KYC level and jurisdiction.

$curl -X GET https://api-gateway-stg.transak.com/api/v2/user/limits \
> -H "x-api-key: YOUR_API_KEY" \
> -H "x-user-ip: USER_IP_ADDRESS" \
> -H "Authorization: ACCESS_TOKEN"

Log out the user

Invalidate the current session token. Call this when the user explicitly signs out of your app.

$curl -X POST https://api-gateway-stg.transak.com/api/v2/user/logout \
> -H "x-api-key: YOUR_API_KEY" \
> -H "x-user-ip: USER_IP_ADDRESS" \
> -H "Authorization: ACCESS_TOKEN"

User Onboarding APIs

Sample Code

useTransakAuth.ts
1import { useState } from "react";
2
3const BASE = "https://api-gateway-stg.transak.com/api/v2/user";
4
5interface AuthState {
6 step: "email" | "otp" | "done";
7 userId: string;
8 stateToken: string;
9 accessToken: string;
10 error: string | null;
11 loading: boolean;
12}
13
14export function useTransakAuth(apiKey: string, userIp: string) {
15 const [state, setState] = useState<AuthState>({
16 step: "email",
17 userId: "",
18 stateToken: "",
19 accessToken: "",
20 error: null,
21 loading: false,
22 });
23
24 const headers = {
25 "x-api-key": apiKey,
26 "x-user-ip": userIp,
27 "Content-Type": "application/json",
28 };
29
30 async function createUserAndSendOtp(email: string) {
31 setState(s => ({ ...s, loading: true, error: null }));
32 try {
33 // Step 1 — create user
34 const createRes = await fetch(BASE, {
35 method: "POST",
36 headers,
37 body: JSON.stringify({ email }),
38 });
39 const createData = await createRes.json();
40 if (!createRes.ok) throw new Error(createData.message ?? `HTTP ${createRes.status}`);
41 const userId: string = createData.data.userId;
42
43 // Step 2 — send OTP, receive stateToken
44 const otpRes = await fetch(`${BASE}/otp/send`, {
45 method: "POST",
46 headers,
47 body: JSON.stringify({ userId }),
48 });
49 const otpData = await otpRes.json();
50 if (!otpRes.ok) throw new Error(otpData.message ?? `HTTP ${otpRes.status}`);
51 const stateToken: string = otpData.data.stateToken;
52
53 setState(s => ({ ...s, userId, stateToken, step: "otp", loading: false }));
54 } catch (err: unknown) {
55 setState(s => ({
56 ...s,
57 loading: false,
58 error: err instanceof Error ? err.message : "Failed to create user",
59 }));
60 }
61 }
62
63 async function verifyOtp(otp: string) {
64 setState(s => ({ ...s, loading: true, error: null }));
65 try {
66 const res = await fetch(`${BASE}/otp/verify`, {
67 method: "POST",
68 headers,
69 body: JSON.stringify({ stateToken: state.stateToken, otp }),
70 });
71 const data = await res.json();
72 if (!res.ok) throw new Error(data.message ?? `HTTP ${res.status}`);
73
74 const accessToken: string = data.data.accessToken;
75 setState(s => ({ ...s, accessToken, step: "done", loading: false }));
76 return accessToken;
77 } catch (err: unknown) {
78 setState(s => ({
79 ...s,
80 loading: false,
81 error: err instanceof Error ? err.message : "OTP verification failed",
82 }));
83 return null;
84 }
85 }
86
87 return { state, createUserAndSendOtp, verifyOtp };
88}
OnboardingScreen.tsx
1import { useState } from "react";
2import { useTransakAuth } from "../hooks/useTransakAuth";
3
4const API_KEY = "YOUR_PARTNER_API_KEY";
5const USER_IP = "USER_IP_ADDRESS";
6
7export function OnboardingScreen({ onAuthenticated }: { onAuthenticated: (token: string) => void }) {
8 const { state, createUserAndSendOtp, verifyOtp } = useTransakAuth(API_KEY, USER_IP);
9 const [email, setEmail] = useState("");
10 const [otp, setOtp] = useState("");
11
12 async function handleEmailSubmit(e: React.FormEvent) {
13 e.preventDefault();
14 await createUserAndSendOtp(email);
15 }
16
17 async function handleOtpSubmit(e: React.FormEvent) {
18 e.preventDefault();
19 const token = await verifyOtp(otp);
20 if (token) onAuthenticated(token);
21 }
22
23 if (state.step === "email") {
24 return (
25 <form onSubmit={handleEmailSubmit}>
26 <h2>Create your account</h2>
27 <input
28 type="email"
29 placeholder="your@email.com"
30 value={email}
31 onChange={e => setEmail(e.target.value)}
32 required
33 />
34 {state.error && <p style={{ color: "red" }}>{state.error}</p>}
35 <button type="submit" disabled={state.loading}>
36 {state.loading ? "Sending…" : "Continue"}
37 </button>
38 </form>
39 );
40 }
41
42 return (
43 <form onSubmit={handleOtpSubmit}>
44 <h2>Enter verification code</h2>
45 <p>We sent a code to {email}</p>
46 <input
47 type="text"
48 inputMode="numeric"
49 maxLength={6}
50 placeholder="000000"
51 value={otp}
52 onChange={e => setOtp(e.target.value)}
53 required
54 />
55 {state.error && <p style={{ color: "red" }}>{state.error}</p>}
56 <button type="submit" disabled={state.loading}>
57 {state.loading ? "Verifying…" : "Verify"}
58 </button>
59 </form>
60 );
61}

Path 2: Auth Reliance Flow

In this path, your platform authenticates the user. You call Transak’s Onboard User Auth API to register that user with Transak. Because the partner owns the authentication, the user never receives an OTP from Transak — your partner access token is the credential for all subsequent API calls.

Use this path when
You already have a verified and authenticated user base.
You want a seamless, no-extra-login experience for your users.
You are responsible for your users’ identity verification at your platform level.

How it Works

1

Authenticate the user on your platform

Your existing auth system verifies the user (session cookie, JWT, OAuth — whatever your platform uses). This step happens entirely on your side.

2

Onboard the user with Transak

Call Transak’s Onboard User Auth API from your server, passing the user’s email in the request body and your partner access token in the x-access-token header.

$curl -X POST https://api-gateway-stg.transak.com/api/v2/user/auth-reliance/onboard \
> -H "x-api-key: YOUR_API_KEY" \
> -H "x-access-token: YOUR_PARTNER_ACCESS_TOKEN" \
> -H "x-user-ip: USER_IP_ADDRESS" \
> -H "Content-Type: application/json" \
> -d '{
> "email": "user@example.com"
> }'
3

Use email and partner access token for subsequent API calls

Once the user is onboarded, all subsequent Transak API calls on behalf of this user are authenticated by passing the user’s email and your partner access token in the request headers. No OTP or user-specific token is required.

$curl -X GET https://api-gateway-stg.transak.com/api/v2/user \
> -H "x-api-key: YOUR_API_KEY" \
> -H "x-access-token: YOUR_PARTNER_ACCESS_TOKEN" \
> -H "x-user-ip: USER_IP_ADDRESS" \
> -H "x-user-email: user@example.com"

Auth Reliance User Onboarding API

Sample Code

server/transakAuth.ts
1// Express route — runs on your server, never in the browser
2import express from "express";
3
4const router = express.Router();
5
6const TRANSAK_API_KEY = process.env.TRANSAK_API_KEY!;
7const TRANSAK_PARTNER_ACCESS_TOKEN = process.env.TRANSAK_PARTNER_ACCESS_TOKEN!;
8const TRANSAK_BASE = "https://api-gateway-stg.transak.com";
9
10router.post("/api/transak-onboard", async (req, res) => {
11 // Your existing session/auth middleware must gate this route
12 const currentUser = req.user; // populated by your auth middleware
13 if (!currentUser) return res.status(401).json({ error: "Unauthorized" });
14
15 try {
16 const response = await fetch(`${TRANSAK_BASE}/api/v2/user/auth-reliance/onboard`, {
17 method: "POST",
18 headers: {
19 "x-api-key": TRANSAK_API_KEY,
20 "x-access-token": TRANSAK_PARTNER_ACCESS_TOKEN,
21 "Content-Type": "application/json",
22 },
23 body: JSON.stringify({ email: currentUser.email }),
24 });
25
26 const data = await response.json();
27 if (!response.ok) throw new Error(data.message ?? `HTTP ${response.status}`);
28
29 res.json({ success: true });
30 } catch (err: unknown) {
31 res.status(500).json({ error: err instanceof Error ? err.message : "Onboarding failed" });
32 }
33});
34
35export default router;
server/transakUserApi.ts
1// All user-scoped Transak API calls use the partner access token + user email in headers
2const TRANSAK_API_KEY = process.env.TRANSAK_API_KEY!;
3const TRANSAK_PARTNER_ACCESS_TOKEN = process.env.TRANSAK_PARTNER_ACCESS_TOKEN!;
4const TRANSAK_BASE = "https://api-gateway-stg.transak.com";
5
6async function getUserDetails(userEmail: string) {
7 const response = await fetch(`${TRANSAK_BASE}/api/v2/user`, {
8 method: "GET",
9 headers: {
10 "x-api-key": TRANSAK_API_KEY,
11 "x-access-token": TRANSAK_PARTNER_ACCESS_TOKEN,
12 "x-user-email": userEmail,
13 },
14 });
15 return response.json();
16}