mDL Exchange API

❗️

Alpha API

The mDL Exchange API is in a private alpha state; access is restricted, and the API may drastically change with no warning.

We are actively looking for feedback and testing of this API; please contact Trinsic to learn more.

Overview

The mDL Wallet landscape is significantly fragmented, with major differences in the transport mechanisms, data formats, and security features across the major vendors. The verification process changes significantly depending both on where an mDL is stored (Apple/Google/Samsung Wallet, CA DMV, etc.) and on what client the user is verifying from (web, native app).

The mDL Exchange API simplifies all of this complexity behind two intuitive API endpoints, a lightweight client SDK, and a few string values.

Supported Wallets and Platforms

The mDL Exchange API is designed to support all mDL wallets which support a native on-device exchange mechanism, such as Digital Credentials API or similar Android / iOS native APIs.

WalletVerify on WebVerify in AppSessions API
Google Wallet✅ Supported✅ Supported✅ Supported
Apple Wallet🟢 Available Soon🟢 Available Soon🟢 Available Soon
Samsung Wallet⏱️ Not yet supported by wallet⏱️ Not yet supported by wallet✅ Supported
CA DMV⏱️ Not yet supported by wallet⏱️ Not yet supported by wallet✅ Supported
LA Wallet⏱️ Not yet supported by wallet⏱️ Not yet supported by wallet✅ Supported

Note: "Web" here refers to a Digital Credentials API verification, whereas "Native" refers to an mDL Verification in a native Android or iOS app, using a native SDK.

The "Sessions API" column describes the support for this provider in the Sessions API, which is designed to support every digital ID provider and wallet.


How to Verify Credentials in Unsupported mDL Wallets

A number of mDL Wallets within Trinsic's network (such as Samsung Wallet, CA DMV, LA Wallet) do not yet support a native on-device exchange API, and therefore do not fit into the mDL Exchange API paradigm.

Use the Trinsic Sessions API to verify an mDL stored in any of the wallets not supported by the mDL Exchange API.



Exchange Flow

1. Create an mDL Exchange

Call the Create mDL Exchange API endpoint, passing in the following information:

  • verificationProfileId
    • Trinsic will provide this to you
  • provider
    • Which wallet you are attempting to verify an mDL within
    • Can be apple-wallet or google-wallet
  • exchangeMechanism
    • Which native API to create an mDL request for
    • Can be DigitalCredentialsApi (to verify on web) or NativeApp (to verify in an app)
  • documentType
    • The document type identifier to request from the user's wallet (e.g., org.iso.18013.5.1.mDL)
  • nameSpaces
    • The mdoc namespaces and fields to request from the credential
  • Provider-specific configuration
    • This is described in greater detail in later sections

The response to this API call contains three strings: exchangeId, exchangeContext, and requestObjectBase64Url.

exchangeId is a unique identifier for the exchange; save it in your backend.

exchangeContext is an opaque, encrypted string which must be sent back to Trinsic during the Finalization step; save it in your backend.

requestObjectBase64Url should be sent to your frontend (website or app) and passed into the Trinsic mDL SDK, exactly as received from the Trinsic API.


{
    "verificationProfileId": "4d9beada-c60b-4585-8214-9441edcf9e52",
    "exchangeMechanism": "NativeApp",
    "provider": "google-wallet",
    "documentType": "org.iso.18013.5.1.mDL",
    "nameSpaces": {
        "org.iso.18013.5.1": {
            "given_name": true,
            "family_name": true,
            "birth_date": true,
            "age_over_21": true
        }
    },

    // Relevant only to Digital Credentials API (web)
    "digitalCredentialsApiHost": "example.com",

    // Relevant only to Native Android
    "androidNativeAppPackageName": "id.example.app",
    "androidNativeAppSigningCertificateFingerprint": "96:77:82:71:A3:FC:26:54:4C:8E:06:70:B7:BA:5D:E2:A5:36:F1:ED:8F:8A:70:81:26:98:EC:87:86:0F:D4:42"
}
{
    "exchangeId": "664d0542-8183-8027-ae9f-9bb849c70e1b",
    "requestObjectBase64Url": "ey[...]3sW5nZUlkIjoiNjY0ZDYXRpb0ifQ",
    "exchangeContext": "BgpTNTNct[...]0M2oImikCSWmszx_WgEMqrEYgk-M"
}


2. Invoke Client mDL SDK

Call the Trinsic mDL SDK for your environment (Web, Android, iOS), passing in the requestObjectBase64Url you received in the Creation step.

If successful, the response from the Trinsic SDK will contain a token with a string value.

Send this token to your backend.


3. Finalize the Exchange

Once your backend has received the final token from your web frontend or native app, call the Finalize mDL Exchange endpoint, passing in the following information:

  • verificationProfileId
    • Same value as provided during Creation
  • exchangeId
    • Provided to you when you created the mDL Exchange.
  • exchangeContext
    • Pass back the exchangeContext which was returned to you when you created the mDL Exchange.
  • responseToken
    • The token you got from your frontend or app

As part of this API call, Trinsic will process the mDL exchange; verify all cryptographic signatures, check against trusted issuer root certificates, and verify revocation status; and process and normalize the output mDL data into an easy-to-use data model.


{
    "verificationProfileId": "4d9beada-c60b-4585-8214-9441edcf9e52",
    "exchangeId": "664d0542-8183-8027-ae9f-9bb849c70e1b",
    "exchangeContext": "BgpTNTNct[...]0M2oImikCSWmszx_WgEMqrEYgk-M",
    "responseToken": "eyJw[...]cm90b2Nvb"
}
{
    "exchangeId": "664d0542-8183-8027-ae9f-9bb849c70e1b",
    "createdSession": {
        "id": "664d0542-8181-8027-ae9f-9bb849c70e1b",
        "done": true,
        "success": true,
        "errorCode": null
    },
    "mdlData": {
        "iacaRootCertificate": {
            "serialNumber": "576294104512703411441843988502590645787600357",
            "commonName": "TEST USE ONLY GICI Staging Root",
            "stateOrProvinceName": "", // Empty for Google Wallet ID Pass  
            "notBefore": "2025-04-03T19:16:25Z",
            "notAfter": "2035-04-04T05:13:50Z"
        },
        "documentSignerCertificate": {
            "serialNumber": "5659316260372263940760166162443504011989628991",
            "commonName": "TEST USE ONLY GICI Staging DS",
            "stateOrProvinceName": "", // Empty for Google Wallet ID Pass
            "notBefore": "2025-04-03T19:20:42Z",
            "notAfter": "2026-04-03T19:20:41Z"
        },
        "nameSpaces": {
            "org.iso.18013.5.1": {
                "family_name": {
                    "type": "String",
                    "value": "DOE"
                },
                "given_name": {
                    "type": "String",
                    "value": "JOHN"
                },
                "birth_date": {
                    "type": "String",
                    "value": "2000-03-01"
                },
                "age_over_21": {
                    "type": "Boolean",
                    "value": "true"
                }
            }
        }
    },
    "normalizedIdentityData": {
        "originatingProviderId": "google-wallet",
        "person": {
            "givenName": "JOHN",
            "familyName": "DOE",
            "dateOfBirth": "2000-03-01"
        },
        "document": {
            "type": "Passport"
        }
    }
}




Client mDL SDKs

Web

CreateMdlExchange Input

For mDL verifications on the web, Trinsic needs to know the hostname of the page on which the Digital Credentials API will be called -- that is, the hostname in the browser bar of the page the user is interacting with.

This can be provided via the digitalCredentialsApiHost field when creating an mDL Exchange.

For example, if the user is on the page https://verify.exampleshop.com/verify-mdl, use the value verify.exampleshop.com.

SDK Usage

Use the Trinsic Web UI SDK, version 2.3.0-alpha2.

Once you have a requestObjectBase64Url from your backend, invoke the Trinsic SDK like so:

import { performMdlExchange } from "@trinsic/web-ui";

const mdlResult = await performMdlExchange(requestObjectBase64Url); // Throws on failure
const resultExchangeId = mdlResult.exchangeId;
const resultToken = mdlResult.token;

// Send resultToken to your backend


Android App

CreateMdlExchange Input

For mDL verifications in an Android app, Trinsic needs to know two pieces of information about the app which will be requesting the user's credential:

  1. The package name of the app (eg com.example.app)
  2. The SHA-256 fingerprint of the app's signing certificate
    1. This should be passed to Trinsic's API in hex form (eg 01:02:03:...), with or without colons.
    2. For debug / local builds, this is likely contained in your local debug keystore.
      1. Use the command keytool -list -keystore <path-to-debug-keystore> to find your debug certificate's fingerprint.
      2. The default password for Android debug keystores is android.

These should be passed in the androidNativeAppPackageName and androidNativeAppSigningCertificateFingerprint fields, respectively.


SDK Usage

Use the Trinsic Android UI SDK , version 2.1.0-alpha1.

Once you have a requestObjectBase64Url from your backend, invoke the Trinsic Android SDK:

TrinsicMdl.performMdlExchange(this, requestObjectBase64Url, (result) -> {
    if (result.getSuccess()) {
      // On success, extract token and send it to your backend
      String exchangeId = result.getExchangeId();
      String token = result.getToken();
      sendToBackend(token);
    } else {
      // On fail, result contains an exception
      Exception thrownException = result.getException();
    }
});

iOS App

CreateMdlExchange Input

For mDL verifications in an iOS app, no extra fields must be provided in the CreateMdlExchangeRequest object.

Trinsic will need to configure your VerificationProfile with your signing certificate and metadata before any verifications can be processed.

Handling of nameSpaces

Apple's iOS SDK uses a custom format to determine which fields to request from the mDL. It is not possible to request arbitrary fields by name; instead, a small set of pre-determined fields may be requested. Some fields, such as address, cause multiple underlying data fields to be returned from the mDL.

Trinsic's API, combined with our iOS SDK, fully handles this for you. We translate the nameSpaces you send to our API, creating a request object which our SDK interprets to construct the native request.

SDK Usage

Use the Trinsic iOS UI SDK , version 2.1.0-alpha1.

Once you have a requestObjectBase64Url from your backend, invoke the Trinsic iOS SDK:

let trinsicMdl = TrinsicMdl()

do {
    let result = try await trinsicMdl.performMdlExchange(requestObjectBase64Url)
    let exchangeId = result.exchangeId
    let token = result.token
    
    // Send `token` to your backend

} catch TrinsicMdlError.documentRequestFailed(let error){
    print("Error: \(error)")
}