AsseteraAssetera Docs
Integrate

KYC integration (MetaKYC SDK)

Embed Assetera's KYC flow with the @asseteragmbh/metakyc React SDK. Create a session token on your server, then render the workflow in your app.

Assetera's identity verification runs through the MetaKYC SDK, published as @asseteragmbh/metakyc. You embed it in two moves: create a short-lived session token on your server, then render the KYC workflow in the browser using that token.

For a tied agent, Assetera provisions the MetaKYC client ID, API key, secret key, and allowed workflow keys after the partner tenant is approved. The customer must sign up with Assetera first. Use that signed-in customer's Keycloak sub as externalRefId for every MetaKYC session.

Ignore examples/nextjs in the SDK repo

The examples/nextjs sample is currently stale: it imports the wrong package name (@metakyc/sdk) and uses a frontend API key instead of the session-token flow. Follow this page and the SDK README, not that example.

The flow

Integrate

Install

npm install @asseteragmbh/metakyc

Create a session token on your server

Call MetaKYCSession.createToken from your backend. The secrets stay server side; the browser only ever receives the returned accessToken.

app/api/kyc/session/route.ts (server)
import { MetaKYCSession } from '@asseteragmbh/metakyc';

export async function POST(req: Request) {
  const identitySession = await getValidatedAsseteraSession(req);
  if (!identitySession?.claims.sub) {
    return Response.json({ error: 'not signed in' }, { status: 401 });
  }

  const sdkSession = await MetaKYCSession.createToken({
    baseUrl: process.env.METAKYC_BASE_URL!,
    clientId: process.env.METAKYC_CLIENT_ID!,   // or tenantId
    apiKey: process.env.METAKYC_API_KEY!,       // server only
    secretKey: process.env.METAKYC_SECRET_KEY!, // server only
    externalRefId: identitySession.claims.sub,   // Keycloak sub, read server-side
    workflowKey: 'INDIVIDUAL_KYC',
    email: identitySession.claims.email,
  });

  // Return only what the browser needs
  return Response.json({
    accessToken: sdkSession.accessToken,
    expiresInSeconds: sdkSession.expiresInSeconds,
  });
}

getValidatedAsseteraSession represents your BFF's server-side session lookup. Do not replace it with a userId accepted from the request body.

Request the session token in the browser

Request the token from your server route after the customer starts verification. Do not send a user ID in the request body and do not put the API key in the browser.

app/kyc/page.tsx (client)
'use client';
import { useEffect, useState } from 'react';
import { MetaKYC, MetaKYCProvider } from '@asseteragmbh/metakyc';

export function KycPage() {
  const [accessToken, setAccessToken] = useState<string>();

  useEffect(() => {
    fetch('/api/kyc/session', { method: 'POST' })
      .then((response) => {
        if (!response.ok) throw new Error('Unable to start verification');
        return response.json();
      })
      .then((session) => setAccessToken(session.accessToken));
  }, []);

  if (!accessToken) return <p>Opening verification...</p>;

  return (
    <MetaKYCProvider
      config={{
        getAccessToken: () => accessToken,
        baseUrl: process.env.NEXT_PUBLIC_METAKYC_BASE_URL!,
        clientId: process.env.NEXT_PUBLIC_METAKYC_CLIENT_ID!,
      }}
    >
      <MetaKYC
        onComplete={(result) => {/* refresh status and route to the next step */}}
        onError={() => {/* show a retry action */}}
      />
    </MetaKYCProvider>
  );
}

Read the result

Use the onComplete callback as a signal to refresh the authoritative KYC status from Assetera. Do not grant access based only on a browser callback. A review may still be in progress after the embedded flow finishes.

Get these right

  • Secrets are server only. apiKey and secretKey never reach the browser. The browser gets a short-lived accessToken.
  • externalRefId is required and scopes the session to one user. For tied agents it is the customer's Keycloak sub, read from the validated BFF session. A mismatch is rejected.
  • workflowKey selects the flow (for example INDIVIDUAL_KYC).
  • KYC status is separate from the login account. Trading is gated on completed KYC, and Assetera is the responsible party for KYC/AML (see Tenancy & responsibility).

Use your tenant handover

Concrete values (baseUrl, clientId / tenantId, available workflowKeys, the endpoints.pattern) are issued with your tenant setup. Pin the SDK version supplied in that handover and upgrade through a tested dependency change.

On this page