Quickstart
Create an EUDI wallet verification session from your backend. The API key stays server-side; the end user's browser and wallet never receive it.
Before you start
Prefer a typed client? Start with the JavaScript / TypeScript SDK. For terminal login and local webhook testing, install the CLI.
Get a Test API key from your DLBR Console. Both Test and Live API keys use https://api.dlbr.app; the key selects the environment. Export them in your shell or configure them in your server's secret manager. This sample uses an SD-JWT VC age-over-18 request; replace the example issuer and credential type with values supported by your relying-party configuration.
export DLBR_GATEWAY_URL="https://api.dlbr.app"
export DLBR_API_KEY="YOUR_TEST_API_KEY"Get a request that matches your workspace
The issuer URLs in this page are illustrative, not a shared test issuer. For a request with your approved values, open Create session → Try it, choose Continue with Console, and select your tenant. Under Use an approved request, choose the registered purpose and credential profile, then Use this request. Review the JSON and copy the generated server-side request.
| Approved configuration | Request field |
|---|---|
| Issuer identifier | credentials[].issuer_id |
| SD-JWT credential type | credentials[].vct_values |
| Registered purpose | intended_use_id |
| Active relying-party instance, when needed | relying_party_instance_id |
If no approved profiles are available, ask your workspace owner to complete the relying-party setup in Console Integration. A Test API key alone does not configure issuers or permitted claims. See Authentication for the difference between backend API keys and Docs sign-in.
Create a session
Request only the credential and claims your relying-party configuration allows.
curl --fail-with-body "$DLBR_GATEWAY_URL/v1/sessions" \
-H "Authorization: Bearer $DLBR_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"credentials": [{
"id": "age-over-18",
"format": "vc+sd-jwt",
"issuer_id": "https://issuer.example.gov",
"vct_values": ["https://sandbox.example/credentials/age-over-18"],
"trust_domain": "pid",
"claims": ["is_over_18"],
"claim_filters": {"is_over_18": {"type": "boolean", "const": true}}
}]
}'const response = await fetch(`${process.env.DLBR_GATEWAY_URL}/v1/sessions`, {
method: 'POST',
headers: {
authorization: `Bearer ${process.env.DLBR_API_KEY}`,
'content-type': 'application/json',
},
body: JSON.stringify({
credentials: [{
id: 'age-over-18',
format: 'vc+sd-jwt',
issuer_id: 'https://issuer.example.gov',
vct_values: ['https://sandbox.example/credentials/age-over-18'],
trust_domain: 'pid',
claims: ['is_over_18'],
claim_filters: { is_over_18: { type: 'boolean', const: true } },
}],
}),
});
if (!response.ok) {
throw new Error(`DLBR API returned ${response.status}: ${await response.text()}`);
}
const session = await response.json();
console.log(session.session_id, session.qr_code_url);The response includes session_id, expires_at, qr_code_url, and wallet deep_links. Render the QR code or use a supported deep link to let the user open their wallet.
The same request can be made with the built-in fetch API in Node.js. Store the key in a server-side secret manager, not a browser bundle, URL, or client-side storage.
Show the wallet QR in your frontend
Install qrcode in your frontend project. Your backend sends the created session's qr_code_url to the UI; it keeps the API key. The value is a wallet invocation URI, not an image URL. Generate the QR locally with this bundled browser code:
<canvas id="wallet-qr" role="img" aria-label="Scan with your wallet"></canvas>import QRCode from 'qrcode';
async function showWalletQr(qrCodeUrl) {
const canvas = document.querySelector('#wallet-qr');
if (!canvas) throw new Error('Wallet QR canvas is missing');
await QRCode.toCanvas(canvas, qrCodeUrl, {
width: 320, margin: 4, errorCorrectionLevel: 'M',
color: { dark: '#000000', light: '#ffffff' },
});
}
// Call showWalletQr(session.qr_code_url) with your backend's response.Offer a supported wallet deep link beside the QR for same-device use and as a fallback if QR generation fails. Do not send wallet invocation URIs to a third-party QR image service.
Read session status
Wallet verification is asynchronous. Poll the status from your backend or listen on the session status WebSocket. A 201 from session creation means the session was created; it does not mean verification completed.
export SESSION_ID="<session_id from the create response>"
curl --fail-with-body "$DLBR_GATEWAY_URL/v1/sessions/$SESSION_ID" \
-H "Authorization: Bearer $DLBR_API_KEY"const statusResponse = await fetch(
`${process.env.DLBR_GATEWAY_URL}/v1/sessions/${session.session_id}`,
{ headers: { authorization: `Bearer ${process.env.DLBR_API_KEY}` } },
);
if (!statusResponse.ok) {
throw new Error(`DLBR API returned ${statusResponse.status}: ${await statusResponse.text()}`);
}
const result = await statusResponse.json();
// This single read may still return PENDING; keep polling until terminal.
const age = result.claims?.['age-over-18'];
const eligible = result.status === 'VERIFIED' && age?.is_over_18 === true;
// Grant access only when eligible is true. Do not log disclosed claims.A verified response for this SD-JWT request can look like this (illustrative):
{
"session_id": "sess_example_7f3a1b2c",
"status": "VERIFIED",
"livemode": false,
"claims": {
"age-over-18": { "is_over_18": true }
}
}Claims are grouped by your request's credential id. Only VERIFIED plus the required claim value authorizes your business decision. FAILED and EXPIRED are terminal failures; CREATED, PENDING, and VERIFYING require another status read. For a complete bounded polling loop, use the SDK wait-for-completion example.
Read verified claims promptly: their result-retention window is up to 30 seconds, or until earlier deletion. Consume the result and delete the session immediately afterward; a later read may return 404.
Watch status on your Node.js backend
For real-time updates, use the session status WebSocket. This SDK example runs on Node.js 22+ with a global WebSocket; install @dlbr/eid-sdk first. It reuses the session created above. The API key and authenticated WebSocket stay on your backend.
import { EidClient } from '@dlbr/eid-sdk';
const eid = new EidClient({ apiKey: process.env.DLBR_API_KEY, mode: 'test' });
const stream = eid.sessions.events.connect(session.session_id, {
signal: AbortSignal.timeout(120_000),
});
let terminalStatus;
try {
for await (const event of stream) {
// Status frames contain lifecycle metadata, not disclosed claims.
if (['VERIFIED', 'FAILED', 'EXPIRED'].includes(event.status)) {
terminalStatus = event.status;
break;
}
}
} finally {
stream.close();
}
if (!terminalStatus) {
throw new Error('Status stream ended early; poll or reconnect with after = stream.lastEventId');
}The SDK authenticates using the dlbr-id-v1 subprotocol and API key. On disconnect, reconnect with after: stream.lastEventId to request missed events, or fall back to the GET polling example above. After a terminal status, fetch the authenticated session result promptly; only VERIFIED indicates success, and claims expire after their short retention window. Delete the session after consuming the result.
Delete the session
curl --request DELETE "$DLBR_GATEWAY_URL/v1/sessions/$SESSION_ID" \
-H "Authorization: Bearer $DLBR_API_KEY"Test environment
Use test credentials and test endpoints while integrating. Do not send real personal data or production credentials to the test environment.
The server-rendered content remains readable when JavaScript is disabled.