Skip to content

Quickstart

An integration has three parts:

  1. Your server signs in to Prove ID and creates a transaction token for the user.
  2. Your page starts the SDK with that token. The SDK talks to Prove ID on its own.
  3. Your server reads the verification result from Prove ID with the transactionId the page sends back.

The SDK uses a transaction token to connect to Prove ID on the user’s behalf. Your server creates it in two calls:

Call Purpose Lifetime
POST /oauth/access_token Signs your server in with your API credentials (form-encoded, client_credentials grant). 30 minutes by default (expires_in). Cache it and reuse it for every user.
POST /link/create-token Creates one transaction token for one verification. Until expiresAt in the response, and only until that flow finishes: a finished flow can’t be started again with the same token.

The optional idTypes field limits the documents allowed in this transaction (IDCARD, OLDIDCARD, DRIVERCARD, PASSPORT, BLUECARD, FOREIGNID). customerId attaches the transaction to a customer you already created in Prove ID.

// Node.js 18+ (built-in fetch)
const API = process.env.PROVEID_API ?? 'https://demo.api.proveid.io';
let cached; // { token, expiresAt }
async function accessToken() {
if (cached && cached.expiresAt > Date.now() + 60_000) return cached.token;
const res = await fetch(`${API}/oauth/access_token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.PROVEID_CLIENT_ID,
client_secret: process.env.PROVEID_CLIENT_SECRET,
}),
});
if (!res.ok) throw new Error(`Prove ID sign-in failed: ${res.status}`);
const data = await res.json();
cached = { token: data.access_token, expiresAt: Date.now() + data.expires_in * 1000 };
return cached.token;
}
export async function createTransactionToken() {
const res = await fetch(`${API}/link/create-token`, {
method: 'POST',
headers: {
Authorization: `Bearer ${await accessToken()}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ idTypes: ['IDCARD'] }),
});
if (!res.ok) throw new Error(`Creating the transaction token failed: ${res.status}`);
return res.json(); // { transactionToken, expiresAt }
}

Expose this through an endpoint of your own (for example POST /api/kyc/token) that only signed-in users can call, and return just transactionToken to the page. Create a new token for every verification.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
<title>Identity verification</title>
<style>
html, body, techsign-kyc { margin: 0; height: 100%; }
</style>
</head>
<body>
<techsign-kyc
token="TRANSACTION_TOKEN"
domain="https://demo.api.proveid.io"
lang="en"
enable-face="true"
></techsign-kyc>
<script type="module">
import '/sdk/techsign-kyc.js';
const kyc = document.querySelector('techsign-kyc');
kyc.addEventListener('complete', (e) => {
// send e.detail.transactionId to your server
console.log('complete', e.detail);
});
kyc.addEventListener('error', (e) => {
// e.detail.code, e.detail.message, e.detail.retryable
console.error('error', e.detail);
});
</script>
</body>
</html>

The component starts the flow as soon as it is added to the page. Set domain to the environment you use.

Render TRANSACTION_TOKEN into the page from your server template, or fetch it first and add the component afterwards:

const res = await fetch('/api/kyc/token', { method: 'POST' });
const { transactionToken } = await res.json();
const kyc = document.createElement('techsign-kyc');
kyc.setAttribute('token', transactionToken);
kyc.setAttribute('domain', 'https://demo.api.proveid.io');
kyc.setAttribute('lang', 'en');
// add the complete / error listeners as above, then:
document.body.append(kyc);

The complete event tells you the flow has finished. Don’t base your decision on the result in the browser: send transactionId to your server and read the result from Prove ID with GET /id/id-info-with-tid/{transactionId}.

The checks run during the flow are listed in controlResults, each with its entryType, entryScore and entryInterpretation (true when the check passed). The examples below reuse accessToken() from step 1 and accept the verification only when every check passed; adapt the rule to your own risk policy.

export async function getVerification(transactionId) {
const res = await fetch(`${API}/id/id-info-with-tid/${encodeURIComponent(transactionId)}`, {
headers: { Authorization: `Bearer ${await accessToken()}` },
});
if (!res.ok) throw new Error(`Reading the result failed: ${res.status}`);
const info = await res.json();
const controls = info.controlResults ?? [];
const passed = controls.length > 0 && controls.every((c) => c.entryInterpretation === true);
return { passed, info };
}

The full response model and the other result services are in the API Reference tab.

For pages that can’t use type="module":

<script src="/sdk/techsign-kyc.iife.js"></script>
<techsign-kyc token="TRANSACTION_TOKEN" lang="en" enable-face="false"></techsign-kyc>
<script>
const kyc = document.querySelector('techsign-kyc');
kyc.addEventListener('complete', (e) => console.log(e.detail));
kyc.addEventListener('error', (e) => console.error(e.detail));
</script>
import '@techsign/kyc';
import { warmupAssets } from '@techsign/kyc';
// Optional: download the models before the user reaches the flow
void warmupAssets({ enableFace: true });

Then use the <techsign-kyc> tag in your template.