Skip to navigation

Headless KYC

Embed multi-step KYC flow in your own interface without building custom UI against the KYC APIs.

View as Markdown

Headless KYC is a UI module that enables partners to integrate the multi-step KYC flow directly into their applications by simply loading Transak’s KYC widget.

Current Limitations

LimitationDetails
Headless KYC APIs (Transaction Session API)

APIs are to be called only from the partner backend and subjected to the whitelisting of partner IP addresses. We don’t support API calls from the frontend due to security restrictions.

Camera permission

Partner app must grant camera permission at the manifest or browser level. If permission isn’t available, the module shows fallback automatically.

Supported for JS, React, and React Native integrations

The Transak UI SDK is available for JS, React, and React Native integrations.

KYC approved but FCA submission pending (For UK Users)

A UK user can be KYC approved in the Get User Details API but still be unable to place an order if FCA is not completed. Before placing an order, always check the user’s status as follows:

  1. Call the Get KYC Requirement API. If FCA is pending, it returns ADDITIONAL_FORMS_REQUIRED.
  2. Call the Get Additional Requirements API. If the response includes a form with type: FCA, open the Headless KYC module so the user can complete the FCA flow.

How to integrate?

1

Whitelist Your API Key & Enable Headless KYC

Action
Follow the steps in the Need help in Integration section
Request API key whitelisting
Share your public IP addresses with Transak for whitelisting to use our APIs in your backend
2

User Authentication

You can use either of the following authentication options:

OptionDescription
White-label AuthUse the standard Transak authentication flow to generate a user access token. Partners can do this by calling the Send User OTP API followed by the Verify User API to generate the access token.

Learn more
Auth RelianceUse Auth Reliance by passing these headers with every request: x-user-identifier and x-access-token

Please refer to the tutorial on how to create partner access token.

3

Generate a quote using the Quote API

Call the Get Quote API to get a quote for the transaction. Pass the apiKey, fiat amount, fiat currency, crypto currency, network, and order type.

A successful response returns a quoteId.

4

Create a transaction session (using Backend only)

Call the Transaction Session API from your backend, passing the quoteId from the previous step and a new module field set to "kyc".

ParameterDescription
quoteIdQuote ID returned by the Get Quote API in the previous step
moduleSet to "kyc" to initialize a Headless KYC session
configOptional. colorMode (DARK or LIGHT) to theme the KYC component and colors object to override individual theme colors

A successful response returns a sessionId.

5

Load the Headless KYC Component via Transak UI SDK

Use the Transak UI SDK to render the KYC component. Pass the sessionId received in the previous step.

The module renders no Next/Back buttons of its own, wire your own UI to the SDK’s next() / back() methods.

npm install @transak/ui-components
import { createTransakKyc } from '@transak/ui-components';
// Your own Back/Next buttons and step title
const backBtn = document.getElementById('back-btn');
const nextBtn = document.getElementById('next-btn');
const title = document.getElementById('step-title');
const kyc = createTransakKyc({
sessionId, // sessionId from previous step
environment, // 'STAGING' | 'PRODUCTION'
onReady: () => {
// Component is ready
},
onStateChange: (state) => {
// Current step state changed. No user data included.
// Use this to update your own Back/Next buttons and step title.
backBtn.disabled = !state.canGoBack;
nextBtn.hidden = state.ctaText === null;
nextBtn.disabled = !state.canGoNext || state.isSubmitting;
nextBtn.textContent = state.isSubmitting ? 'Submitting...' : state.ctaText ?? '';
title.textContent = state.name ?? '';
},
onSubmitted: ({ kycStatus }) => {
// All required forms submitted. kycStatus is 'SUBMITTED' (KYC is under review);
// track final approval separately via the KYC status API or webhook.
},
onError: ({ code }) => {
// Handle error
},
onDismiss: () => {
// Close the KYC module and navigate the user back to your app.
kyc.unmount();
},
});
await kyc.mount('kyc-slot');
// Call back() and next() when the user clicks on back and next buttons
backBtn.addEventListener('click', () => kyc.back());
nextBtn.addEventListener('click', () => kyc.next());

Call kyc.unmount() to remove the component from the page when the user leaves the KYC screen.

onStateChange callback

The callback returns an object with these fields:

{
canGoBack: boolean,
canGoNext: boolean,
isSubmitting: boolean,
ctaText: string | null,
name?: string
}
FieldMeaningMap to
nameTitle of the current stepStep title
canGoBackUser can go to the previous stepBack button enabled/disabled
canGoNextCurrent step is complete and validNext button enabled/disabled
isSubmittingCurrent step is being submittedNext button loading state
ctaTextLabel for the Next button. If null, no label is presentNext button text and visibility

The callback fires only after onReady, and only when a value changes.

back() and next() methods

These methods are mandatory and help the user navigate between KYC forms. Add your own Back and Next buttons, and call these methods when the user clicks them.

MethodDescription
back()Returns the user to the previous form so they can update it. On the first step it does nothing, with no event and no error
next()Submits the current form, and navigates to the next form. If the form is invalid, the field errors show inline and the flow stays on that form.

Both methods do nothing before mount() or after unmount().

onSubmitted callback

Completion is signalled only by onSubmitted({ kycStatus }). There is no completion state in onStateChange.

  • kycStatus is always SUBMITTED, which means the KYC is under review. The final approval comes from the KYC Webhooks.
  • If the user has already completed every step, onSubmitted fires immediately on load.

onDismiss callback

The onDismiss callback has no parameters. When it fires, close the KYC module and take the user back to your app.

onError callback

The onError callback returns { code, message? }. Use the code to handle each failure case, and treat any unknown code as a generic error.

CodeDescription
INVALID_OPTIONSInvalid or missing options passed to the SDK
INVALID_STATEThe component is already mounted
IFRAME_LOAD_FAILEDThe KYC component failed to load
CONFIG_LOAD_FAILEDThe sessionId is invalid or expired. Create a new session and mount again
STEP_SUBMIT_FAILEDThe current step failed to submit. The user can correct it and continue
FILE_UPLOAD_FAILEDDocument upload failed
KYC_PROVIDER_UNAVAILABLEThe KYC provider is temporarily unavailable
CAMERA_PERMISSION_DENIEDCamera access was denied. Ask the user to allow camera access
USER_BLOCKEDA UK user failed the risk assessment and is blocked
6

Handle the ID proof and selfie step

The ID proof and selfie step is handled inside the module via Onfido, no separate integration is required. Keep the following in mind:

  • Your app is responsible for granting camera permission (native app manifest or browser).
  • If permission isn’t available, the module automatically shows a fallback.
  • If the user denies camera access, onError returns CAMERA_PERMISSION_DENIED.
  • This step has its own in-frame buttons, so onStateChange returns ctaText: null. Hide your Next button on this step.
7

Track the final KYC status

The module’s onSubmitted callback fires once all required forms are submitted with kycStatus: SUBMITTED, it does not guarantee final approval. Use the Get KYC Requirement API to poll for the final status.

Partner can also use the KYC Webhooks to receive a notification when the final status is available.

API Overview

API Errors

Status CodeError CodeMessage
4011002Invalid or missing authentication token.
4226003This feature is not enabled for your account. Please contact support.
4226005Quote not found or could not be loaded.
5006005Failed to create a session for the user.