DCQL: mandatory + optional groups (student transport pass)
Scenario
A transport authority sells a discounted student pass. Mandatory: PID
(identity) AND student status (Student ID card OR Enrolment Letter).
Optional (required: false): local-residency proof (Utility Bill OR
Rental Agreement) for an additional discount - the wallet presents it only
if the holder has and consents to it.
Before you build: run the integrator intake in igrantio-ows-overview - environment, API key, tenancy, backend host, webhooks, frontend - one question at a time, a recommended default with each.
The DCQL query
{
"credentials": [
{
"id": "pid",
"format": "mso_mdoc",
"meta": {
"doctype_value": "urn:eu.europa.ec.eudi:pid:1"
},
"claims": [
{ "id": "full_name", "path": ["full_name"] },
{ "id": "dob", "path": ["date_of_birth"] }
],
"claim_sets": [["full_name"], ["dob"]]
},
{
"id": "student_id_card",
"format": "dc+sd-jwt",
"meta": { "vct_values": ["student_id"] },
"claims": [
{ "id": "student_id", "path": ["student_id"] },
{ "id": "university_name", "path": ["university_name"] }
],
"claim_sets": [["university_name", "student_id"]]
},
{
"id": "enrolment_letter",
"format": "dc+sd-jwt",
"meta": { "vct_values": ["employment_letter"] },
"claims": [
{ "id": "status", "path": ["status"] },
{ "id": "university_name", "path": ["university_name"] }
],
"claim_sets": [["university_name", "status"]]
},
{
"id": "utility_bill_doc",
"format": "dc+sd-jwt",
"meta": { "vct_values": ["utility_bill_doc"] },
"claims": [{ "id": "address", "path": ["address"] }]
},
{
"id": "rental_agreement_doc",
"format": "dc+sd-jwt",
"meta": { "vct_values": ["rental_agreement_doc"] },
"claims": [{ "id": "address", "path": ["address"] }]
}
],
"credential_sets": [
{ "options": ["pid"], "required": true },
{ "options": [["student_id_card"], ["enrolment_letter"]], "required": true },
{ "options": [["utility_bill_doc"], ["rental_agreement_doc"]], "required": false }
]
}
Run it on OWS
- Store as a presentation definition; send the verification request (v3).
- On
presentation_acked+verified === true, the presentation holds 2 OR 3 credentials. Branch on whether the optional residency group came back (checkpresentationSubmission) and price the pass accordingly.
Adjust for your deployment
- The example
vct_valuesare pilot values (noteemployment_letterfor the enrolment letter) - pin them to your issuers' real VCTs. - Optional groups must change an OUTCOME (discount tier), never gate the flow; treat absence as the normal path.
- Trim claims to what pricing actually needs.
Cross-references
igrantio-dcql-kyc- the all-mandatory version of this pattern.igrantio-dcql-claim-sets- fallbacks within one credential.
Source of truth
This workflow mirrors https://docs.igrant.io/docs/dcql-2-4-5-student-transport-pass/ (query detailed in https://docs.igrant.io/concepts/eudi-wallet-dcql-openid4vp-business-wallet-payments/, §2.4.5). Before implementing, fetch the doc page; if it disagrees with this skill, the documentation wins - follow it and report the drift so the skill can be updated.