Skip to content

Understanding results

After a successful verification, call fetchSessionResults() from your backend to retrieve the verified identity data. This guide explains the response format, common field types, and how to handle errors.

fetchSessionResults() returns a SessionResultsData object:

FieldTypeDescription
status'success' | 'error'Whether credential verification passed.
responseRecord<string, Record<string, unknown>>Verified fields, keyed by ISO 18013-5 namespace. Present on both success and error (may contain partial data on error).
errorsRecord<string, unknown>Empty object on success. Contains error details when status is 'error'.
warningsRecord<string, unknown>May be non-empty even on success (e.g., CRL fetch issues that didn’t block verification).

The response object is keyed by namespace strings defined in ISO 18013-5. The standard mDL namespace is org.iso.18013.5.1. Each namespace maps element names to their values:

const mdl = results.response['org.iso.18013.5.1'];
const givenName = mdl.given_name; // "Jane"

Fields you didn’t request or that the wallet omitted will be absent — always check for presence before accessing.

ElementTypeExample
family_name, given_name, issuing_authority, etc.string"Doe"
birth_date, issue_date, expiry_datestring (ISO 8601 date)"1990-03-15"
age_over_18, age_over_21, etc.booleantrue
age_in_yearsinteger34
portraitnumber[] (byte array, typically PNG)[137, 80, 78, ...]
driving_privilegesobject[]Array of privilege objects

The portrait field is a byte array. To display it as an image:

const base64 = btoa(String.fromCharCode(...new Uint8Array(mdl.portrait)));
const imgSrc = `data:image/png;base64,${base64}`;

Using NAMESPACES_MDL_AGE_OVER_18_ONLY:

{
"status": "success",
"response": {
"org.iso.18013.5.1": {
"age_over_18": true
}
},
"errors": {},
"warnings": {}
}
const mdl = results.response['org.iso.18013.5.1'];
if (mdl.age_over_18) {
// User is 18 or older
}

Using launchAgeInYearsVerification():

{
"status": "success",
"response": {
"org.iso.18013.5.1": {
"age_in_years": 34
}
},
"errors": {},
"warnings": {}
}
const mdl = results.response['org.iso.18013.5.1'];
if (mdl.age_in_years >= 21) {
// User is 21 or older
}

Using NAMESPACES_MDL_NAME_ONLY:

{
"status": "success",
"response": {
"org.iso.18013.5.1": {
"family_name": "Doe",
"given_name": "Jane"
}
},
"errors": {},
"warnings": {}
}
const mdl = results.response['org.iso.18013.5.1'];
const fullName = `${mdl.given_name} ${mdl.family_name}`;

Using NAMESPACES_MDL_ALL_MANDATORY:

{
"status": "success",
"response": {
"org.iso.18013.5.1": {
"birth_date": "1990-03-15",
"document_number": "DL123456",
"driving_privileges": [
{
"vehicle_category_code": "C",
"issue_date": "2020-01-01",
"expiry_date": "2028-01-01"
}
],
"expiry_date": "2028-06-30",
"family_name": "Doe",
"given_name": "Jane",
"issue_date": "2020-06-30",
"issuing_authority": "CA DMV",
"issuing_country": "US",
"portrait": [137, 80, 78, 71, 13, 10, 26, 10],
"un_distinguishing_sign": "USA"
}
},
"errors": {},
"warnings": {}
}

Errors fall into two categories: verification errors (returned in the response) and exceptions (thrown as JavaScript Errors).

When credential verification fails, fetchSessionResults() returns a result with status: 'error'. The errors object contains details, and response may contain partial data:

{
"status": "error",
"response": {
"org.iso.18013.5.1": {
"family_name": "Doe"
}
},
"errors": {
"parsing_errors": "..."
},
"warnings": {}
}

Always check status before using response data:

const results = await fetchSessionResults(id, apiKey);
if (results.status === 'success') {
const mdl = results.response['org.iso.18013.5.1'];
// Use verified data
} else {
console.error('Verification errors:', results.errors);
// Show a user-friendly message — prompt them to try again
}

When retrying after a verification error, always create a new session with fetchSessionData(). Do not reuse the existing session.

fetchSessionResults() throws an Error for issues that prevent returning a structured result:

ScenarioError message containsWhat to do
Session expired or already consumed"Not Found"Sessions expire after 10 minutes and are single-read. Create a new session.
Session still in progress"Conflict"The user hasn’t completed verification yet. Wait and retry, or poll with a delay.
Invalid API key"Unauthorized"Check that your API key is correct and matches your environment.
Network failure"Error making request"Check network connectivity and the verifier URL.
try {
const results = await fetchSessionResults(id, apiKey);
// Handle results...
} catch (error) {
if (error.message.includes('Not Found')) {
// Session expired — create a new one
} else if (error.message.includes('Conflict')) {
// Still in progress — retry after a delay
} else {
console.error('Unexpected error:', error.message);
}
}
  • status, response, errors, warnings — these top-level keys are stable across SDK versions.
  • Namespace keys (e.g., org.iso.18013.5.1) are defined by ISO 18013-5 and stable.
  • Element names within namespaces (e.g., family_name, birth_date) are defined by ISO and AAMVA standards and stable.
  • Error key strings inside errors (e.g., parsing_errors) are internal and may change. Don’t match on specific error keys for control flow — treat a non-empty errors object as “something went wrong.”
  • Breaking changes to the SDK are communicated through semver.