Modeling Your World
The overview introduced the four layers (L1 catalog, L2 profile, L3 set, L4 channel). This page explains how the model describes an organization's world, how governance flows through every layer, and how wire forms are derived from it. The model is the authoritative source that drives wire forms; the issuer design and the verifier DCQL are both derived from it, not authored beside it.
Modeling Your World
Before any credential is designed, the catalog lets an organization describe its world: the kinds of party it deals with, the attributes those parties carry, and the relationships between them. Everything downstream derives from this, so it is worth modeling deliberately rather than per credential.
The catalog is bound to a Party. Every catalog is owned by a Party through ownerPartyRef. In most organizations that owner is the tenant or the organization itself, though it can just as well be a local subsidiary that keeps its own catalog. Whoever owns it, a catalog is typically used as the organization's single source of truth for its world: one governed place where the meaning, classification, and structure of every attribute is defined once and reused everywhere.
Entities are party types. Each entity in the catalog is a kind of party. The platform ships a rich set of built-in party types, including natural_person, organization, address, and group, alongside platform roles such as identity, credential_template, resource, and user; the partyType token is extensible for anything else your world needs. A PREDEFINED entity names one of these party types and is modelled up front as first-class data.
Specializations are use-case subtypes you do not model up front. In a given use case a natural person may be an employee, a student, or a customer; an organization may be an employer or a supplier. These are SPECIALIZATION entities: each extends a predefined entity with extra attributes for the use case, without the platform having to predefine "student" or "customer" as their own party types. A specialization inherits the attributes of what it specializes and adds its own.
Relationships connect entities. Relationships are first-class: a Person has an Address, an Employee is employed by an Employer. Each relationship has a type and two ends, and each end carries its own cardinality, so the model captures how many addresses a person may have and that the address in that relationship belongs to exactly one resident.
The Four Layers
The model is structured into four layers that build on each other: the Catalog (L1) defines the canonical party types, attributes, and relationships; the Attribute Profile (L2) assembles catalog entities into named use-case roles; the Attribute Set (L3) is a role-scoped traversal subselection of one profile; and Channels (L4) are the set-bound artifacts that both the issuer design and the verifier DCQL derive from. Each layer is versioned and uses the same DRAFT | PUBLISHED lifecycle.
Governance overlays flow through every layer. The four governance overlays on an attribute (classification, processing, residency, assurance) are authored once on the catalog attribute and flow down every layer into the wire form, never retyped per credential. They are grounded in W3C DPV, GDPR, NIST FIPS 199, ISO 27001, and eIDAS2. Personal-data classification is overlays.classification.pii (with specialCategory for Article 9 data); like all governance, it lives in the overlays bag. Each layer may narrow what the layer above admits but never widen it.
What the governance overlays drive
Rendering a set to different output formats is only half of what the rich model does. The governance overlays on each attribute are operational, not decorative: they determine how the platform protects, uses, keeps, and erases the data, and they travel with the value wherever it flows.
classificationsets the protection posture. Thepiiflag andspecialCategorymarker, the ISO 27001 label, and the NIST FIPS 199 impact triad decide how strictly a value is guarded, masked, and access-controlled, and which attributes count as personal or special-category data for audit.processinggoverns lawful use and lifecycle. Each purpose carries its GDPR Article 6 legal basis and its own retention rule, so the model knows why a value may be used and, through the retentionduration,trigger, andaction, when it must be cleaned up or erased.residencygoverns where a value may live: the allowed and denied regions, whether it must stay in-region, and the Chapter V transfer mechanism for any permitted cross-border movement.assurancegoverns the trust level: the eIDAS level of assurance, the attestation type, and the authentic source the value is asserted against.
Because these travel with the attribute down every layer, the same protection, retention, residency, and assurance rules apply consistently to a form, a PDF, an API payload, and a credential, without being restated per artifact. The model is not just a rendering source; it is where data-handling policy is declared once and enforced everywhere the attribute appears.
How the Wire Forms Are Derived
Wire forms are derivations from VC channels, not a separate authoring tier.
Issuer credential design = a VC channel + issuance-only overlays the channel does not carry (displays, optional alias, hostingMode). Created at POST /api/v1/designs/credentials/fromchannel with channelRef: { channelId, channelVersion }. The claim list, selective-disclosure posture, ordering, and credential-type identity are all derived from the VC channel and its set, profile, and catalog chain. No claims[] or bindings[] are authored on the design itself. Each consumed traversal path writes one ISSUE-role lineage row. See Issuing.
Verifier DCQL query = one or more VC channels. DCQL spans multiple credentials, one credential query per channel, so a single DCQL can request both the Employee SD-JWT and the Business Card mdoc simultaneously. Created at POST /api/v1/oid4vp/dcql/authored with channelRefs: [ { channelId, channelVersion } ]. Each consumed traversal path writes one REQUEST-role lineage row. See Verifying.
The through-line from semantic model to wire form: a set traversal entry { roleRef: "employee", path: ["residentialAddress", "country"] } maps in the SD-JWT VC channel to claimPath: ["address", "country"], surfaces as a selectively-disclosable verified claim in the issued credential, and is recorded in lineage with its traversal_path value. The verifier's DCQL query carries the same claimPath, so issuer and verifier agree on field identity without any out-of-band coordination.
Override and Version-Pinning Precedence
When a value is resolved for a wire form, these layers apply in order. Each layer narrows what the layer above admits; no layer widens it:
- Catalog entity attribute (L1) is canonical:
valueType,overlays.i18nlabels,sdPolicy, governance metadata. - Profile override (L2) is the profile's narrow-only effective value for the override allow-list (
conformance,sdPolicy,entryCodesSubset,sensitive, ...). The profile also pins the catalog version viacatalogRefs. Anything outside the allow-list reads through to the catalog. - Set override (L3) tightens further per selected (role, path) entry (
conformance,cardinality,entryCodesSubset,sensitive). The set pins the profile version viaprofileRef. - VC channel is selection and mapping only (which traversal entries, which
claimPath, whichdisclosurevalue). It does not override governance. - Issuer design overlay is issuance-only (
displays,alias,hostingMode).
Each layer's version pin is what keeps derivation deterministic: a channel authored against set v2 keeps rendering the v2 shape even after the set is revised to v3.
Usage Lineage
Every render that consumes a traversal path records a usage-lineage row. One row has this shape:
| Column | Meaning / values |
|---|---|
role_ref | The role that contributed the path (e.g. employee, employer). |
source_entity | The entity the path originates from (e.g. Person, Employee). |
traversal_path | The full traversal path as consumed from the set (e.g. ["residentialAddress","country"]). |
role | ISSUE (written by a design-from-channel render) or REQUEST (written by a DCQL author call). |
artifact_kind | CREDENTIAL_DESIGN or DCQL_QUERY. |
artifact_id, artifact_version | The rendered artifact and the version it was captured at. |
channel_id, channel_version | The VC channel the render derived from. |
The lineage row carries enough identity in role_ref, source_entity, traversal_path, and the channel reference to answer cross-role questions directly, and the path back to the profile and catalog runs through that channel reference.
The issuer's design-from-channel render writes role = ISSUE rows; the verifier's DCQL author call writes role = REQUEST rows. For relationship-traversal paths, the row captures the full traversal, so ["residentialAddress","country"] is one traceable entry.
Because the rows carry the channel identity, the role, and the traversal path together, the platform can answer questions the opaque per-service stores cannot:
- Which credentials issue, and which verifier requests touch, a given attribute or traversal path?
- Under which VC channel and at which versions?
- Which
source_entitycontributes a given traversal path, and does any verifier request it?
That cross-role reasoning over meaning, classification, and provenance is the deliverable of the enterprise tier. See Provenance & Operations.
The License Gate
Every WRITE in the enterprise tier is gated behind a single license feature, semantic-attribute-binding:
- Gated: catalog, profile, set, branding, and channel authoring; the issuer design-from-channel render; the verifier DCQL
authoredcall. - Never gated: reads (get, list, resolve) and the DCQL
previewderivation, which derives a query but persists nothing and records no lineage. - Never gated: the free-form / lite channel path in the IDK.
The gate is fail-open by design. Behaviour depends on the deployment's license:
| License features | Behaviour |
|---|---|
| empty set (unbounded default) | no gating applies; every gated write passes |
non-empty, contains semantic-attribute-binding | gated writes pass |
non-empty, missing semantic-attribute-binding | gated writes return FORBIDDEN |
With no license features set (the unbounded default), no gating applies and the FORBIDDEN response does not occur. In VDX, semantic-binding REST operations declare their operation-level license metadata with x-license-protection, and the service command contracts expose matching licenseProtection descriptors. This makes the OpenAPI reference, command registry, and runtime license checks use the same entitlement keys.
Pagination
Every list endpoint under /api/attributes/v1/{catalogs,profiles,sets,channels,branding} is paginated and filterable uniformly. A list call accepts these query parameters:
| Parameter | Meaning |
|---|---|
limit | Page size, clamped to [1, 100], default 20. |
offset | Number of items to skip. |
page | Zero-based page index (alternative to offset). |
size | Page size (alias of limit). |
sort | Field to sort by, default createdAt. |
sortDirection | ASC or DESC, default DESC. |
| per-entity filters | nameContains (case-insensitive substring), status on catalogs/profiles/sets/branding, and channel / setId on channels. |
Every list response uses the same paginated envelope:
{
"data": [ /* the page of entities (never a bare top-level array) */ ],
"pagination": {
"limit": 20,
"offset": 0,
"page": 0,
"size": 20,
"total": 7,
"totalPages": 1,
"hasMore": false
}
}
Read the page from .data (always an array, never the top-level object) and the counts from .pagination. The channel list returns .data as an array of ChannelEnvelope items; read .data[].channel for each concrete channel. See Channels for paged list, filter, and sort parameters in action.
Next Steps
- Catalog (L1): define your catalog shell, add entities and relationships, and publish
- Issuing: render issuer designs from the VC channels and create the offer
- Verifying: author the multi-credential DCQL and verify a presentation