For the complete documentation index, see llms.txt. This page is also available as Markdown.

Transition from PEX to DCQL

Transition from PEX to DCQL

Backward Compatibility & Presentation Definition to DCQL Migration Guide (v1.0.0-alpha.1)

Part 1 — Backward Compatibility: DCQL vs. PEX

Overview

As Inji Verify evolves to adopt DCQL (Digital Credentials Query Language) as its primary query protocol, older wallet implementations that only support PEX (Presentation Exchange) are no longer compatible with newer verifier versions.

This section defines the compatibility behavior, versioning strategy, and guidance for System Integrators (SIs) and end users — so there is no confusion about what works, what doesn't, and what to do about it.

Important: There is no backward compatibility layer. No fallback from DCQL to PEX will be implemented in any verifier version.

Background

Protocol

Description

PEX (Presentation Exchange)

Legacy query protocol (presentation_definition) used in older wallets and in Inji Verify releases up to 0.18.x

DCQL (Digital Credentials Query Language)

Modern credential query language defined by OpenID4VP 1.0 (final), adopted by Inji Verify from version 1.0.0-alpha.1 onwards

These two protocols are not interoperable. A verifier built on DCQL cannot process a presentation from a wallet that only speaks PEX, and vice versa.

Versioning Strategy

Inji Verify Version

Supported Protocol

Compatible Wallets

Up to 0.18.x (Legacy)

PEX (presentation_definition)

Wallets supporting PEX

1.0.0-alpha.1 and later (Current)

DCQL (dcql_query)

Wallets supporting DCQL / OpenID4VP 1.0

  • Newer verifier versions exclusively use DCQL for authorization requests and VP token validation.

  • Older verifier versions support PEX and remain available for integrators who need legacy wallet support.

  • There is no verifier version that supports both query protocols for new verification requests.

  • Result-fetch endpoints in the current version can still return results for both DCQL-based and legacy Presentation Definition submissions, so previously completed verifications remain readable.

Compatibility Matrix

Wallet Type

Inji Verify ≤ 0.18.x (PEX)

Inji Verify 1.0.0-alpha.1+ (DCQL)

Wallet supporting DCQL only

❌ Does not work

✅ Works

Wallet supporting PEX only

✅ Works

❌ Does not work

Wallet supporting both

✅ Works

✅ Works

System Integrator (SI) Guidance

SIs must choose the verifier version based on the wallet ecosystem they intend to support:

Scenario A — Supporting Legacy Wallets

  • Use: Inji Verify version ≤ 0.18.x (PEX-based)

  • When: Your end users are on older wallets that have not yet migrated to DCQL

  • Trade-off: You will not benefit from DCQL capabilities, OpenID4VP 1.0 alignment, or other features of newer verifier releases

Scenario B — Supporting Modern Wallets

  • Use: Inji Verify 1.0.0-alpha.1 or later (DCQL-based)

  • When: Your ecosystem is on modern wallets with DCQL / OpenID4VP 1.0 support

  • Trade-off: End users on older PEX-only wallets will be unable to complete verification

Scenario C — Mixed Ecosystem (Transition Period)

Recommended approach: Run two separate verifier deployments — one PEX (legacy version), one DCQL (current version) — and route users based on wallet capability detection at the application layer.

Inji Verify itself does not perform this routing; the SI is responsible for the routing logic.

End-User Messaging

When a user with an incompatible (PEX-only) wallet attempts verification against a DCQL verifier, the flow will fail. SIs should surface a clear, actionable message to the end user.

Recommended message template:

Additional guidance for SIs:

  • Display this message as early as possible in the verification flow, ideally before the user attempts to share a presentation.

  • Provide a link to wallet upgrade/download instructions where applicable.

  • Do not surface raw protocol error codes to end users.

Migration Roadmap

Phase
Action

Short-term

Integrators on PEX continue using legacy Inji Verify versions (≤ 0.18.x)

Mid-term

Wallet providers upgrade their wallets to support DCQL / OpenID4VP 1.0

Long-term

All integrators migrate to DCQL-based verifiers (1.0.0-alpha.1+); PEX-based versions reach end-of-life

SIs are encouraged to plan wallet upgrade timelines in coordination with their wallet provider to minimize disruption to end users.


Part 2 — Migrating Presentation Definition to DCQL Query

Overview

As Inji Verify adopts DCQL as its primary query protocol, developers who have built integrations using Presentation Definitions (PD/PEX) need a clear, practical guide to migrate their existing queries to the DCQL format.

This section explains how each component of a Presentation Definition maps to its DCQL equivalent, with step-by-step guidance and real-world examples aligned to OpenID4VP 1.0 (final) and the structures accepted by the current Inji Verify verify-service.

Understanding the Two Formats

Presentation Definition (PD / PEX)

Presentation Definitions are part of the DIF Presentation Exchange (PEX) specification. They describe what credentials a verifier requires using input_descriptors, constraints, and fields.

Core PD structure:

DCQL Query

DCQL is the credential query language defined in OpenID4VP 1.0. It uses a credentials array with claims entries to express the same requirements more concisely, plus optional claim_sets and credential_sets for alternatives.

Core DCQL structure:

Note: in the Inji Verify create-verification-request API the query is passed as the dcqlQuery field of the request body; the wire-level authorization request carries it as dcql_query per OpenID4VP.

Component Mapping Reference

PD Component
DCQL Equivalent
Notes

presentation_definition.id

dcql_query (root object)

No direct ID at query level

input_descriptors[]

credentials[]

One-to-one mapping

input_descriptor.id

credential.id

Same purpose; referenced by credential_sets

input_descriptor.name

Not required

Informational only in PD

input_descriptor.purpose

Not required

Use in UI/UX layer instead

format (PD level)

credential.format

Per-credential; e.g. dc+sd-jwt, ldp_vc, mso_mdoc

Credential type filter ($.type / $.vct field constraint)

meta.type_values (ldp_vc) / meta.vct_values (sd-jwt)

Type matching moves out of claims into meta

constraints.fields[].path

claims[].path

JSONPath string → path array

constraints.fields[].filter

claims[].values

Value-matching logic moves to values

constraints.fields[].optional

claim_sets

Alternative claim combinations, in order of preference

submission_requirements

credential_sets with options

Alternatives across credentials; required: false for optional sets

constraints.limit_disclosure

Implied by format

Selective disclosure handled by dc+sd-jwt

Holder binding checks

require_cryptographic_holder_binding

Replaces the earlier acceptVPWithoutHolderProof configuration

Step-by-Step Migration Process

Step 1 — Inventory Your Presentation Definition

  • List all input_descriptors in your existing PD

  • Note each descriptor's id, name, purpose, and constraints

  • Identify the credential format (e.g., ldp_vc, jwt_vc_json, SD-JWT VC)

Step 2 — Map Each Input Descriptor to a DCQL Credential

  • Each input_descriptor becomes one entry in the credentials[] array

  • Carry over the id

  • Set the format at the credential level — use dc+sd-jwt for SD-JWT VCs (the OpenID4VP 1.0 identifier; older drafts used vc+sd-jwt)

Step 3 — Move Credential Type Matching into meta

  • PD constraints on $.type (W3C VC) become meta.type_values — an array of arrays of type IRIs (full URIs after JSON-LD expansion; types not defined in any @context remain as-is and are accepted as relative IRIs)

  • PD constraints on $.vct (SD-JWT VC) become meta.vct_values — matched exactly against the credential's vct claim (type inheritance is not currently supported)

  • The meta/format pairing is enforced by the verifier: vct_values is only valid with SD-JWT formats and type_values only with ldp_vc; the wrong combination is rejected at request creation (DCQL_META_NOT_MATCHING_FORMAT)

Step 4 — Convert Field Paths

  • PD uses JSONPath syntax: $.credentialSubject.dateOfBirth

  • DCQL uses a path array of components: ["dateOfBirth"] (relative to the claims of the credential)

  • Remove the $.credentialSubject. prefix; each nesting level becomes its own array element

  • Array selectors: use an integer index for one element (["fullName", 0, "value"]) or null for all elements (["gender", null, "value"])

Step 5 — Convert Field Filters

  • PD filter objects (JSON Schema) → DCQL values array (allowed values list)

  • If the PD filter only checks type ("type": "string"), the DCQL claims entry needs only a path — no values required

  • filter.const: "x" → values: ["x"]; filter.enum: [...] → values: [...]

Step 6 — Handle Optionality and Alternatives

  • Optional fields within one credential → give claims an id and express alternatives with claim_sets (listed in order of preference)

  • submission_requirements across credentials → credential_sets with options (each option is a list of credential ids that together satisfy the request)

  • Purely optional credential sets → required: false on the credential set

Step 7 — Validate

  • Create a verification request with the DCQL query against a DCQL-compatible verifier (Inji Verify 1.0.0-alpha.1+)

  • Confirm the wallet returns the expected claims in the vp_token

  • Verify semantic equivalence with the original PD before deprecating the PD-based flow

Migration Examples

Example 1 — Simple Age Verification (Single Field)

Before (PD):

After (DCQL):

Example 2 — Identity Verification (Multiple Fields, W3C VC)

Before (PD):

After (DCQL):

Note: type_values uses full type URIs (each inner array is one acceptable combination of types). The Verify UI also uses type_values to match submitted credentials when multiple verifier configurations share the same credential type.

Example 3 — Multi-Credential Request with Value Filter and Alternatives (Complex)

Before (PD):

After (DCQL):

Here claim_sets lists acceptable claim combinations in order of preference, and credential_sets.options expresses that presenting either credential satisfies the request — the DCQL equivalent of a PEX pick submission requirement.

Edge Cases & Handling

Scenario
PD Behavior
DCQL Handling

Optional fields

optional: true on field constraint

Give claims an id and use claim_sets to list acceptable combinations; or omit the claim entirely

Nested claims

$.credentialSubject.address.city

["address", "city"] — each level is a separate array element

Array element (specific)

$.credentialSubject.fullName[0].value

["fullName", 0, "value"] — integer index selects one element

Array element (any/all)

JSONPath wildcard [*]

["gender", null, "value"] — null selects all elements

Enum / allowed values

filter.enum: ["active", "valid"]

values: ["active", "valid"]

Constant value match

filter.const: "active"

values: ["active"]

Credential type matching

Field constraint on $.type or $.vct

meta.type_values (ldp_vc) or meta.vct_values (dc+sd-jwt)

Multiple credential formats

format at PD level

format per credential in credentials[]

Selective disclosure

limit_disclosure: "required"

Use dc+sd-jwt format — disclosure handled by the format itself

Holder binding

Verifier-side configuration (acceptVPWithoutHolderProof)

require_cryptographic_holder_binding parameter, supported for SD-JWT VC and LDP_VC

Best Practices

  • Maintain semantic equivalence — always verify the DCQL query returns the same claims as the original PD before deprecating PD-based flows

  • Use the correct format identifiers — dc+sd-jwt is the OpenID4VP 1.0 identifier for SD-JWT VCs; vc+sd-jwt appears only in older draft-based integrations

  • Always constrain credential type via meta — set vct_values or type_values so wallets match the intended credential, not just any credential with similar claims

  • Keep claim paths minimal — only request claims strictly required for the verification use case; over-requesting reduces user trust

  • Test with real wallets — validate DCQL queries against actual wallet implementations, not just spec compliance

  • Version your queries — tag DCQL queries with a version identifier for traceability across deployments

  • Document the migration — record the original PD and its DCQL equivalent in your integration documentation for audit purposes

Points to Note

  • No fallback implementation from DCQL to PEX

  • No dual-protocol support for new verification requests within a single verifier version

  • No automatic wallet version detection within Inji Verify

  • No Automated PD-to-DCQL conversion tooling

Last updated

Was this helpful?