OCA Bundles
OCA (Overlays Capture Architecture, oca.colossi.network) is a specification for describing credential metadata through a layered approach. A capture base names the attributes and their data types; a stack of overlays adds labels, formats, units, entry codes, sensitivity, descriptions, and per-locale display on top. The structure can be defined once and re-layered with different language packs, validation rules, or branding without touching the original schema.
The EDK ships OCA as a first-class metadata source. The lib-data-oca-* modules provide the OCA primitives (parser, overlay processor, SAID verifier, native records), and the lib-data-store-credential-design-impl module integrates them into the credential design system as a layer provider and a mapper so OCA bundles can drive credential display directly, without manual claim-by-claim translation. The same OCA records can be persisted natively alongside the canonical credential design, so the original bundle remains round-trippable for export or republication.
Why OCA in the EDK?
A credential issuer who publishes an OCA bundle alongside their credential type gives every wallet and verifier in the ecosystem a standardised, ecosystem-neutral way to learn:
- Which attributes the credential carries and what shape each attribute's value has
- How to label each attribute in the user's language
- Which attributes are mandatory and which are optional
- Which values are valid for enumerated attributes, and how to display each enum code
- Which attributes contain sensitive data and should be treated accordingly
- The credential's own display name and description, per locale
Without OCA, every consumer of the credential has to manually map raw claim names (given_name, family_name, org.iso.18013.5.1.birth_date) into human-readable labels, figure out which are sensitive, and decide how to render enumerations. With OCA, that work is done once at the issuer and consumed automatically by any client that understands the spec. The EDK plugs OCA into the credential design system, so the same CredentialDesignService calls that resolve display metadata from OID4VCI or SD-JWT VCT can also resolve from OCA.
Architecture
The OCA pipeline has three stages. The parser takes the raw bundle JSON and produces a ParsedOcaBundle (capture base SAID, bundle SAID, OCA version, attribute map, list of ParsedOcaOverlay entries with type, language, SAID, and the original payload). The overlay processor walks the parsed overlays and flattens them into an OcaProcessedBundle, a single typed structure that holds every piece of metadata in convenient maps (labels, descriptions, mandatory attributes, entry codes per attribute and locale, units, format patterns, and so on). Optional SAID verification operates on the parsed form at one of three levels (format, structural, cryptographic) depending on how strictly you need to check integrity.
The processed bundle is generic. Anything that wants to consume OCA data, the credential design system, a PDF renderer, a form builder, an admin UI that previews a bundle before importing it, reads from OcaProcessedBundle without re-parsing the raw JSON.
OCA Bundle Structure
An OCA bundle is a JSON document containing a capture base and a list of overlays. Each object carries a SAID (Self-Addressing Identifier) under the d field for integrity.
Capture Base
The capture base defines the attribute names and their OCA types. It is the stable structural layer:
{
"d": "ECaptureBaseSaid...",
"type": "spec/capture_base/2.0.0",
"attributes": {
"given_name": "Text",
"family_name": "Text",
"birth_date": "DateTime",
"portrait": "Binary",
"age_over_18": "Boolean",
"nationality": "Text",
"document_number": "Numeric"
}
}
Attribute Types
OCA defines a small set of scalar types and array variants. The EDK maps each one to a canonical value-kind and a default widget hint that downstream consumers can use directly:
| OCA Type | Canonical Value Kind | Default Widget Hint |
|---|---|---|
Text | STRING | TEXT |
Numeric | NUMBER | TEXT |
Boolean | BOOLEAN | CHECKBOX |
Binary | BINARY | FILE |
DateTime | DATE_TIME | DATE_TIME |
Reference | REFERENCE | GROUP |
[Text], [Numeric], [Boolean] | ARRAY | LIST |
The mapping lives in OcaTypeMapping and is intentionally string-based so it can be reused by consumers (credential design, PDF rendering, form builders) without forcing them onto a single enum. When entry codes are present for an attribute, the widget hint is promoted to PICKLIST regardless of the underlying type, and the localized entry display values become the picklist options.
Overlays
Overlays are divided into language-independent and language-specific kinds. Language-independent overlays apply globally:
| Overlay | What It Carries |
|---|---|
character_encoding | Encoding per attribute (e.g. utf-8) |
format | Format patterns and regular expressions (e.g. YYYY-MM-DD, ^[A-Z]{2}$) |
standard | References to external standards (e.g. ISO 3166-1) |
conformance | Mandatory / optional flags per attribute |
cardinality | Value-count constraints (1, 1-5, 0-*) |
entry_code | Valid enumeration codes per attribute |
unit | Units of measurement |
sensitive | Marks attributes containing sensitive data |
Language-specific overlays carry a language field (BCP-47) and produce per-locale data:
| Overlay | What It Carries |
|---|---|
meta | Credential-level display name and description |
label | Per-attribute human-readable labels |
information | Per-attribute extended descriptions |
entry | Display values for entry codes (e.g. "M" to "Male") |
The EDK's OcaOverlayProcessor handles both v1 (array-based) and v2 (object-based) overlay layouts, falls back gracefully when fields are missing or shaped unexpectedly, and produces a single OcaProcessedBundle with all this data flattened into maps keyed by attribute name and locale.
OCA Bundle Example
A complete bundle for a driving license credential with English and Polish labels:
{
"d": "EBundleSaid...",
"capture_base": {
"d": "ECaptureBase...",
"type": "spec/capture_base/2.0.0",
"attributes": {
"given_name": "Text",
"family_name": "Text",
"birth_date": "DateTime",
"issuing_country": "Text"
}
},
"overlays": [
{
"d": "EConformance...",
"type": "spec/overlays/conformance/1.0",
"capture_base": "ECaptureBase...",
"attribute_conformance": {
"given_name": "M",
"family_name": "M",
"birth_date": "M",
"issuing_country": "M"
}
},
{
"d": "ELabelEn...",
"type": "spec/overlays/label/1.0",
"capture_base": "ECaptureBase...",
"language": "en",
"attribute_labels": {
"given_name": "First Name",
"family_name": "Last Name",
"birth_date": "Date of Birth",
"issuing_country": "Issuing Country"
}
},
{
"d": "ELabelPl...",
"type": "spec/overlays/label/1.0",
"capture_base": "ECaptureBase...",
"language": "pl",
"attribute_labels": {
"given_name": "Imie",
"family_name": "Nazwisko",
"birth_date": "Data urodzenia",
"issuing_country": "Kraj wydania"
}
},
{
"d": "EMetaEn...",
"type": "spec/overlays/meta/1.0",
"capture_base": "ECaptureBase...",
"language": "en",
"name": "Driving License",
"description": "EU-compliant digital driving license"
},
{
"d": "EFormat...",
"type": "spec/overlays/format/1.0",
"capture_base": "ECaptureBase...",
"attribute_formats": {
"birth_date": "YYYY-MM-DD",
"issuing_country": "^[A-Z]{2}$"
}
}
]
}
Once processed, the resulting OcaProcessedBundle contains:
- Four attributes typed as Text, Text, DateTime, Text
- All four marked mandatory
- English labels: First Name, Last Name, Date of Birth, Issuing Country
- Polish labels: Imie, Nazwisko, Data urodzenia, Kraj wydania
- Meta display for English: name "Driving License", description "EU-compliant digital driving license"
- Format patterns:
birth_datematchesYYYY-MM-DD,issuing_countrymatches^[A-Z]{2}$
The same data feeds the credential design system through the layer provider described in Credential Design Integration, and is persisted natively for round-tripping as described there as well.
Next Steps
- Bundle Service: parsing, processing, and the OCA service interface
- SAID Verification: the three integrity-check levels for bundles and overlays
- Credential Design Integration: the mapper, the layer provider, and native persistence