Proven and the Holdr SDK provide the capability to issue, hold, and verify credentials in the mdoc/mDL format over a variety of protocols. The following documentation describes how to use Proven for the server portions of mdoc/mDL workflows.
There are currently four categories of APIs for working with mdoc/mDL credentials over OID4VC: Keys, Schemas, Issuance, and Verification. These categories of APIs should be approached sequentially, e.g. it doesn't work to use the verification APIs if you haven't configured keys.
Provision mDoc issuer key material so that you can securely issue mdoc and mDL credentials.
curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vci/setup/mdoc' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4=' \
--header 'Content-Type: application/json' \
--header 'Cookie: sessionId=s%3AIxantPaS5ZGMmrHZDetRQHQIVTRBiNBL.DAjBpQO8pxrjJdM4jQUYJU%2FlxzGAGIJcUzM%2FM7zltk0' \
--data '{
"force": false
}'force {boolean}: Whether to force the creation of a new key or not. Use false for first-time initialization or in case you don't want to overwrite the key (if one exists). Use true to rotate the key.
key_id {string}: This string will allow you to identify the key that the system is using for mdoc, allowing you assess the state of the system (e.g., are we still using the same key as 6 months ago?). Useful to save. Sample: 8d3e8f18-5e7d-4f1a-a72b-1db2f1d0c001
cert_id {string}: This string will allow you to identify the certificate that the system is using to identify itself to other entities, allowing you to assess the state of the system (e.g. is this the endpoint or agent I think it is?). Useful to save. Sample: 6af84a3c-b6e9-4b1c-844a-6ce6a1f2d002
message {string}: Human readable text that describes the result of the operation (e.g., mDoc issuer keys provisioned successfully). Sample: mDoc issuer keys provisioned successfully.
Use this API to check whether the agent has been initialized with mdoc issuer key material and is ready to issue credentials.
No request body or parameters.
keys {array of objects}: The key(s) currently provisioned for mdoc issuance. Each object contains:
key_id {string}: The identifier of the provisioned key. Sample: 8d3e8f18-5e7d-4f1a-a72b-1db2f1d0c001
cert_id
Use this API to configure the system to issue credentials of a particular schema, i.e. set things up so you can issue mDLs, passports, national IDs, etc.
doctype {string} Required: The mdoc document type identifier (e.g., org.iso.18013.5.1.mDL).
label {string}: A human-readable name for this credential type (e.g., Mobile Driver's License).
description
agentRecord {object}: The record created in the agent.
supported_cred_id {string}: Unique identifier for this credential type in the agent. Sample: 9fd5ef9d-b8b8-4f52-b6a9-95b9ce4f6f8a
identifier
Optional query parameters:
doctype {string}: Filter results to a specific document type.
config_id {string}: Filter results to a specific configuration record.
Returns an array of configuration objects, each with the same fields as the dbConfig object in the POST response above.
Use this API to create a credential exchange and generate an offer that can be delivered to a holder's wallet.
supported_cred_id {string}: The ID of the registered credential type to issue, obtained from the Schema Setup step. Sample: 9fd5ef9d-b8b8-4f52-b6a9-95b9ce4f6f8a
credential_subject {object}: The claims to include in the credential. Keys should match the claims defined when the credential type was registered. For an mDL, common fields include family_name, given_name, birth_date, issue_date
offer {object}: The credential offer object, suitable for delivery to a holder's wallet.
credential_issuer {string}: The URL of the credential issuer. Sample: https://example/oid4vc/tenant/c286d1c7-c548-48d1-8580-76d3fe317bff
credentials
Verification is a multi-step process. First, you create a presentation definition that describes what claims you want to verify. Then, you use that definition to create a presentation request, which generates a URI that can be delivered to a holder's wallet (e.g., as a QR code). Finally, after the holder responds, you retrieve the presentation results.
Use this API to define what credentials and claims you want to request from a holder.
pres_def {object}: The presentation definition object, following the DIF Presentation Exchange specification.
id {string}: An optional identifier for the presentation definition. If omitted, the system will generate one.
purpose {string}: A human-readable string describing the purpose of the verification request.
input_descriptors {array of objects}: One or more descriptors specifying what credentials and claims are required.
pres_def_id {string}: The system-generated identifier for this presentation definition. Save this — you will need it to create a presentation request. Sample: 42c870ae-b605-4121-b5e3-1e6bb3a00c6f
pres_def {object}: The presentation definition as stored, including any system-generated fields such as id.
Retrieve all presentation definitions registered for your wallet.
No request body or parameters.
Returns an array of presentation definition objects, each with the same fields as the POST response for creating a presentation definition above.
pres_def_id {string} (path parameter, required): The identifier of the presentation definition to retrieve.
Returns a single presentation definition object with the same fields as the POST response for creating a presentation definition above.
pres_def_id {string} (path parameter, required): The identifier of the presentation definition to delete.
Only an HTTP status response code is returned.
Use this API to generate a presentation request from a previously created presentation definition. The response includes a URI that can be rendered as a QR code or delivered as a deep link for the holder's wallet to scan.
pres_def_id {string}: The identifier of the presentation definition to use, obtained from Step 1. Sample: 42c870ae-b605-4121-b5e3-1e6bb3a00c6f
vp_formats {object}: The verifiable presentation formats to accept. For mdoc verification, use "mso_mdoc": { "alg": ["ES256"] }.
request_uri {string}: A URL-encoded openid4vp:// URI. This is typically rendered as a QR code or deep link for the holder's wallet to scan or tap. Sample: openid4vp://?client_id=did%3Ajwk%3A...&request_uri=https%3A//example/oid4vc/tenant/.../oid4vp/request/43050ce4-bfb4-4454-b5de-9bbd1c564a85
request {object}: The presentation request record.
After the holder's wallet responds to the presentation request, use this API to retrieve all of the results.
Optional query parameters:
sort-field {string}: The field to sort by (default updated_at).
sort-direction {string}: Sort direction, ASC or DESC (default DESC).
params {object}: The pagination and filter parameters applied to the query.
rows {array of objects}: The presentation records. Key fields on each record include:
presentation_exchange_id {string}: Unique identifier for the presentation exchange.
After the holder's wallet responds to the presentation request, use this API to retrieve a specific result.
presentation_exchange_id {string} (path parameter, required): The identifier of the presentation exchange to retrieve.
Returns a single presentation record with the same fields as described in the list response above.
6af84a3c-b6e9-4b1c-844a-6ce6a1f2d002defaultCertificate {object}: The certificate currently designated as the default for mdoc issuance.
cert_id {string}: The identifier of the default certificate. Sample: 6af84a3c-b6e9-4b1c-844a-6ce6a1f2d002
key_id {string}: The identifier of the key associated with this certificate. Sample: 8d3e8f18-5e7d-4f1a-a72b-1db2f1d0c001
subject_dn {string}: The subject distinguished name of the certificate. Sample: CN=Proven mDoc Issuer
issuer_dn {string}: The issuer distinguished name of the certificate. Sample: CN=Proven mDoc Issuer
trustAnchors {array}: The trust anchors configured for this issuer. Empty if none have been configured.
ISO 18013-5 Mobile Driver's Licensedisplay {array of objects}: Display metadata for the credential type, used for rendering in wallets and verifier UIs.
verification_method {string}: The verification method to use when signing credentials of this type.
issuer_id {string}: The DID or identifier of the issuer for this credential type.
claims_schema {object}: An object defining the namespaces and claims this credential type supports.
vc_additional_data {object}: Additional data to include in the credential.
cryptographic_binding_methods_supported {array of strings}: Cryptographic binding methods supported for this credential type.
cryptographic_suites_supported {array of strings}: Cryptographic suites supported for this credential type.
proof_types_supported {object}: Proof types supported for this credential type.
org.iso.18013.5.1.mDLformat {string}: The credential format. Always mso_mdoc for mdoc credentials.
display {array of objects}: Display metadata as stored in the agent.
format_data {object}: The doctype and claims as stored in the agent.
dbConfig {object}: The configuration record stored in the Proven database.
config_id {string}: Unique identifier for this configuration record. Sample: c4d8f7f2-f8d0-4d0b-93d0-9f9f31a5c003
wallet_id {string}: The wallet this configuration is associated with. Sample: wallet-123
doctype {string}: The document type identifier as provided in the request.
supported_cred_id {string}: Matches the supported_cred_id in agentRecord.
format {string}: The credential format. Always mso_mdoc.
label {string}: The human-readable label as provided in the request.
description {string}: The human-readable description as provided in the request.
created_at {string}: ISO 8601 timestamp of when the record was created.
updated_at {string}: ISO 8601 timestamp of when the record was last updated.
expiry_dateissuing_countryissuing_authoritydocument_numberdriving_privilegesun_distinguishing_signportraitdid {string}: The DID to associate with the credential subject.
verification_method {string}: The verification method to use for signing this credential. If omitted, the system uses the verification method configured for the credential type.
pin {string}: An optional user PIN for the credential offer, adding an extra layer of security to the issuance flow.
label {string}: A human-readable label for this credential exchange.
connection_id {string}: The connection ID to associate with this credential exchange.
["org.iso.18013.5.1.mDL"]grants {object}: The grant types available for this offer. For mdoc/mDL issuance, this will contain a pre-authorized code grant.
urn:ietf:params:oauth:grant-type:pre-authorized_code {object}: The pre-authorized code grant.
pre-authorized_code {string}: The pre-authorized code the holder's wallet uses to retrieve the credential. Sample: iQ7DWmf2vjogMtQ_bdrDQg
user_pin_required {boolean}: Whether the holder is required to supply a PIN to redeem the offer.
credential_offer {string}: A URL-encoded openid-credential-offer:// URI. This is typically rendered as a QR code or deep link for the holder's wallet to scan or tap.
exchange {object}: The credential exchange record created by this request.
exchange_id {string}: Unique identifier for this exchange. Sample: 921786c9-dd65-473a-bebf-e5283d689c96
supported_cred_id {string}: The credential type ID used for this exchange, matching the value from the request.
credential_subject {object}: The claims as provided in the request.
verification_method {string}: The verification method that will be used to sign the credential. Sample: did:key:zDnaevgeiLuxFHYTHCHb1eAr489xPuCy3pDamtiGe5pWPvU41#zDnaevgeiLuxFHYTHCHb1eAr489xPuCy3pDamtiGe5pWPvU41
issuer_id {string}: The DID of the issuer. Sample: did:key:zDnaevgeiLuxFHYTHCHb1eAr489xPuCy3pDamtiGe5pWPvU41
state {string}: The current state of the exchange. Will be created immediately after issuance is initiated.
created_at {string}: ISO 8601 timestamp of when the exchange was created.
updated_at {string}: ISO 8601 timestamp of when the exchange was last updated.
id {string}: An identifier for this input descriptor. For mdoc, typically the doctype (e.g., org.iso.18013.5.1.mDL).
format {object}: Specifies the credential format. For mdoc verification, use "mso_mdoc": { "alg": ["ES256"] }.
constraints {object}: Defines the constraints on the requested claims.
limit_disclosure {string}: Set to "required" to ensure only the requested claims are disclosed.
fields {array of objects}: The specific claims to request. Each field has a path array using JSONPath notation. For mdoc claims, use the namespace-qualified syntax: $['org.iso.18013.5.1']['claim_name'].
wallet_idc286d1c7-c548-48d1-8580-76d3fe317bffcreated_at {string}: ISO 8601 timestamp of when the record was created.
updated_at {string}: ISO 8601 timestamp of when the record was last updated.
request_id {string}: Unique identifier for this request. Sample: 43050ce4-bfb4-4454-b5de-9bbd1c564a85pres_def_id {string}: The presentation definition used for this request.
vp_formats {object}: The verifiable presentation formats as provided in the request.
created_at {string}: ISO 8601 timestamp of when the request was created.
updated_at {string}: ISO 8601 timestamp of when the request was last updated.
presentation {object}: The presentation exchange record created by this request.
presentation_id {string}: Unique identifier for this presentation exchange. Use this to poll for results. Sample: 5e871b45-3821-4a94-8695-303517939afb
pres_def_id {string}: The presentation definition used.
request_id {string}: The request that initiated this presentation exchange.
state {string}: The current state of the presentation. Will be request-created immediately after the request is made.
created_at {string}: ISO 8601 timestamp of when the presentation exchange was created.
updated_at {string}: ISO 8601 timestamp of when the presentation exchange was last updated.
page-size {integer}: Number of results per page (default 20).
current-page {integer}: The page number to retrieve (default 1).
item-count {integer}: The total number of items.
state-filter {string}: Filter results to a specific state (e.g., done, request-created).
contact-id {string}: Filter results to a specific contact.
state {string}: The current state (e.g., request-created, done).
verified {boolean}: Whether the presented credentials were successfully verified.
role {string}: The role in the exchange (e.g., verifier).
presentation {object}: The presented credentials, if available.
created_at {string}: ISO 8601 timestamp of when the record was created.
updated_at {string}: ISO 8601 timestamp of when the record was last updated.
count {integer}: The total number of presentation records.
curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vci/status/mdoc' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4='curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vci/credentials-supported/mdoc' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4=' \
--header 'Content-Type: application/json' \
--header 'Cookie: sessionId=s%3AIxantPaS5ZGMmrHZDetRQHQIVTRBiNBL.DAjBpQO8pxrjJdM4jQUYJU%2FlxzGAGIJcUzM%2FM7zltk0' \
--data '{
"doctype": "org.iso.18013.5.1.mDL",
"label": "Mobile Driver'\''s License",
"description": "ISO 18013-5 Mobile Driver'\''s License"
}'
curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vci/credentials-supported/mdoc' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4='curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vci/issue' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4=' \
--header 'Content-Type: application/json' \
--header 'Cookie: sessionId=s%3AIxantPaS5ZGMmrHZDetRQHQIVTRBiNBL.DAjBpQO8pxrjJdM4jQUYJU%2FlxzGAGIJcUzM%2FM7zltk0' \
--data '{
"supported_cred_id": "9fd5ef9d-b8b8-4f52-b6a9-95b9ce4f6f8a",
"credential_subject": {
"family_name": "Doe",
"given_name": "Jane",
"birth_date": "1990-01-15",
"issue_date": "2026-03-10",
"expiry_date": "2031-03-10",
"issuing_country": "US",
"issuing_authority": "State DMV",
"document_number": "DL123456",
"driving_privileges": "A,B,C",
"un_distinguishing_sign": "USA",
"sex": "2",
"height": "170",
"eye_colour": "BLU",
"birth_place": "New York",
"resident_city": "Springfield",
"resident_state": "IL",
"resident_postal_code": "62701",
"resident_country": "US",
"nationality": "US",
"age_over_18": "true",
"portrait": ""
}
}'curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vp/presentation-definitions' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4=' \
--header 'Content-Type: application/json' \
--header 'Cookie: sessionId=s%3AIxantPaS5ZGMmrHZDetRQHQIVTRBiNBL.DAjBpQO8pxrjJdM4jQUYJU%2FlxzGAGIJcUzM%2FM7zltk0' \
--data '{
"pres_def": {
"input_descriptors": [
{
"id": "org.iso.18013.5.1.mDL",
"format": {
"mso_mdoc": {
"alg": ["ES256"]
}
},
"constraints": {
"limit_disclosure": "required",
"fields": [
{
"path": ["$['\''org.iso.18013.5.1'\'']['\''given_name'\'']"]
},
{
"path": ["$['\''org.iso.18013.5.1'\'']['\''family_name'\'']"]
}
]
}
}
]
}
}'curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vp/presentation-definitions' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4='curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vp/presentation-definitions/{pres_def_id}' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4='curl --location --request DELETE 'https://buckets4life.share.zrok.io/api/v1/oid4vp/presentation-definitions/{pres_def_id}' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4='curl --location 'https://buckets4life.share.zrok.io/api/v1/oid4vp/request' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4=' \
--header 'Content-Type: application/json' \
--header 'Cookie: sessionId=s%3AIxantPaS5ZGMmrHZDetRQHQIVTRBiNBL.DAjBpQO8pxrjJdM4jQUYJU%2FlxzGAGIJcUzM%2FM7zltk0' \
--data '{
"pres_def_id": "42c870ae-b605-4121-b5e3-1e6bb3a00c6f",
"vp_formats": {
"mso_mdoc": {
"alg": ["ES256"]
}
}
}'curl --location 'https://buckets4life.share.zrok.io/api/v1/presentations' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4='curl --location 'https://buckets4life.share.zrok.io/api/v1/presentations/{presentation_exchange_id}' \
--header 'x-api-key: HuNsaIP9w0LsM5vqRhWprqLShgWLvb2yMAyuYUjWqd4='