diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..464c0ed --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing + +Thanks for helping improve OpenCred's credential schemas. This repo is small and conservative on purpose: schemas published here are referenced by credentials in the wild, so the bar for changes is high. + +## Adding a new schema + +1. **Pick a name.** Lowercase, hyphenated (`salary-slip`, not `SalarySlip`). Singular noun. Match the credential's primary subject. +2. **Create the directory:** `schemas//v1/`. +3. **Write the JSON Schema** at `schemas//v1/schema.json`: + - Use JSON Schema draft-07 or draft 2020-12 (be consistent within a schema). + - Set `$id` to the raw URL: `https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas//v1/schema.json`. + - Include `title` and `description`. + - Mark required fields explicitly under `required`. + - Document each property with `description`. + - Default `additionalProperties` to `true` unless you have a reason to lock it down. +4. **Write a README** at `schemas//v1/README.md` that includes: + - The schema URL + - A required-fields table and an optional-fields table + - At least one realistic example +5. **Optional**: add a `context.jsonld` if the credential needs JSON-LD term mappings, and an `example.json` with a full example credential. + +## Revising an existing schema + +Schemas published here are **immutable**. Once a `v/schema.json` URL is referenced by a credential in the wild, the file at that URL must keep working forever. + +| Change | Action | +|---|---| +| Typo in `description`, README clarification, comment | Edit in place — does not change validation behavior | +| Tightening validation (new required field, narrower constraint) | **Breaking** — publish as `v` | +| Loosening validation (new optional field, wider constraint) | **Non-breaking** — still publish as `v`, do **not** mutate `v` | +| Renaming or removing a field | **Breaking** — publish as `v` | + +In all cases of structural change, create a new version directory and leave the previous one untouched. + +## Pull request checklist + +- [ ] Schema validates against its declared `$schema` meta-schema +- [ ] Example in the README validates against the schema +- [ ] `$id` matches the file's raw URL exactly +- [ ] README documents required + optional fields and includes an example +- [ ] If revising, the change respects the immutability policy above +- [ ] PR description explains the use case for the schema or change + +## Where this gets used + +These schemas are consumed by: + +- **OpenCred Desktop & Docker** — `credentialSchema` references in issued credentials +- **Verifiers** — schema validation during VC verification +- **Issuers using OpenCred templates** — built-in template forms map to these schemas diff --git a/README.md b/README.md index bde6e5a..6cf68a8 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,94 @@ -# Verifiable Credential Schemas +# OpenCred Verifiable Credential Schemas -A collection of schemas for Verifiable Credentials (VCs), aligned with [Schema.org](https://schema.org) vocabulary wherever applicable. +JSON Schemas for Verifiable Credentials (VCs) used by [OpenCred](https://github.com/nfh-trust-labs/opencred) and the broader trust-services ecosystem. Each schema is interoperable, versioned, and immutable once published. -## Overview +## Available schemas -This repository maintains JSON-LD schemas for various types of verifiable credentials. Each schema is designed to be: +| Credential | Latest | Schema URL | +|---|---|---| +| Education | v1 | [schemas/education/v1/schema.json](schemas/education/v1/schema.json) | +| Employment | v1 | [schemas/employment/v1/schema.json](schemas/employment/v1/schema.json) | +| Identity | v1 | [schemas/identity/v1/schema.json](schemas/identity/v1/schema.json) | +| Health | v1 | [schemas/health/v1/schema.json](schemas/health/v1/schema.json) | +| Business | v1 | [schemas/business/v1/schema.json](schemas/business/v1/schema.json) | +| Salary Slip | v1 | [schemas/salary-slip/v1/schema.json](schemas/salary-slip/v1/schema.json) | +| Electricity (Customer) | v1 | [schemas/electricity/v1/schema.json](schemas/electricity/v1/schema.json) | -- **Interoperable**: Based on Schema.org vocabulary standards -- **Extensible**: Custom properties for domain-specific needs -- **Semantic**: Rich, machine-readable metadata using JSON-LD -- **Verifiable**: Compatible with W3C Verifiable Credentials standards| +## URL pattern -All schemas in this repository prioritize alignment with Schema.org vocabulary: +Every schema is reachable at a stable raw URL: + +``` +https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas//v/schema.json +``` + +This URL is also the schema's `$id`, so JSON Schema processors can resolve it directly. OpenCred references these URLs in the W3C VC `credentialSchema` field. + +## Repository layout + +``` +schemas/ +└── / + └── v/ + ├── schema.json # JSON Schema (draft-07 or 2020-12) + ├── README.md # field reference + example + ├── context.jsonld # JSON-LD context (optional) + └── example.json # example credential subject (optional) +``` + +## Versioning policy + +- Each schema version is **immutable** once merged. Bug fixes that don't change the data shape are allowed; anything else requires a new version. +- **Breaking changes** → publish under a new version directory (`v2`, `v3`, …) and keep older versions in place. +- **Non-breaking additions** (new optional properties, looser constraints) — bump the directory version. Don't mutate existing files. +- Once a credential is in the wild referencing `…/v1/schema.json`, that URL must keep working forever. + +## Using a schema + +### From the command line + +```bash +curl https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/education/v1/schema.json +``` + +### From a W3C Verifiable Credential + +```json +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": ["VerifiableCredential", "EducationCredential"], + "credentialSchema": { + "id": "https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/education/v1/schema.json", + "type": "JsonSchemaValidator2018" + }, + "issuer": "did:web:example.org", + "issuanceDate": "2026-04-07T00:00:00Z", + "credentialSubject": { + "id": "did:example:subject", + "name": "Jane Doe", + "degree": "Bachelor of Science in Computer Science", + "institution": "University of Example", + "dateConferred": "2024-06-15" + } +} +``` + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for how to add or revise a schema. ## Resources -- [Schema.org Documentation](https://schema.org) -- [W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model/) +- [W3C Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/) +- [JSON Schema](https://json-schema.org/) - [JSON-LD 1.1](https://www.w3.org/TR/json-ld11/) +- [Schema.org](https://schema.org) ## License -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. +MIT — see [LICENSE](LICENSE). ## Maintainer diff --git a/energy credentials/readme.md b/energy credentials/readme.md deleted file mode 100644 index 54f69e6..0000000 --- a/energy credentials/readme.md +++ /dev/null @@ -1 +0,0 @@ -These are schemas for credentials in the energy sector. diff --git a/schemas/business/v1/README.md b/schemas/business/v1/README.md new file mode 100644 index 0000000..b0be561 --- /dev/null +++ b/schemas/business/v1/README.md @@ -0,0 +1,29 @@ +# Business Credential — v1 + +JSON Schema for an organization incorporation credential. + +## URL + +``` +https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/business/v1/schema.json +``` + +## Required fields + +| Field | Type | Format | Notes | +|---|---|---|---| +| `name` | string | — | Legal name of the organization | +| `registrationNumber` | string | — | Registration number assigned by the authority | +| `jurisdiction` | string | — | ISO 3166-1 / ISO 3166-2 code recommended | +| `incorporationDate` | string | `date` | ISO 8601 | + +## Example credential subject + +```json +{ + "name": "Acme Corp Pvt Ltd", + "registrationNumber": "U12345KA2020PTC123456", + "jurisdiction": "IN-KA", + "incorporationDate": "2020-03-15" +} +``` diff --git a/schemas/business/v1/schema.json b/schemas/business/v1/schema.json new file mode 100644 index 0000000..55bf9ad --- /dev/null +++ b/schemas/business/v1/schema.json @@ -0,0 +1,31 @@ +{ + "$id": "https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/business/v1/schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Business Credential", + "description": "Verifiable credential attesting that an organization is incorporated in a particular jurisdiction under a specific registration number.", + "type": "object", + "required": ["name", "registrationNumber", "jurisdiction", "incorporationDate"], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Legal name of the organization." + }, + "registrationNumber": { + "type": "string", + "minLength": 1, + "description": "Registration number assigned by the registering authority." + }, + "jurisdiction": { + "type": "string", + "minLength": 1, + "description": "Jurisdiction of incorporation, recommended as an ISO 3166-1 / ISO 3166-2 code (e.g. \"IN\", \"US-DE\")." + }, + "incorporationDate": { + "type": "string", + "format": "date", + "description": "ISO 8601 date (YYYY-MM-DD) on which the organization was incorporated." + } + }, + "additionalProperties": true +} diff --git a/schemas/education/v1/README.md b/schemas/education/v1/README.md new file mode 100644 index 0000000..910b61f --- /dev/null +++ b/schemas/education/v1/README.md @@ -0,0 +1,32 @@ +# Education Credential — v1 + +JSON Schema for an academic qualification credential. + +## URL + +``` +https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/education/v1/schema.json +``` + +## Required fields + +| Field | Type | Format | Notes | +|---|---|---|---| +| `name` | string | — | Full name of the credential subject | +| `degree` | string | — | The academic qualification conferred | +| `institution` | string | — | Conferring institution's legal name | +| `dateConferred` | string | `date` (ISO 8601) | Date the qualification was conferred | + +`additionalProperties: true` — issuers may include extra fields (transcript URLs, GPA, honors, etc.) without breaking conformance. + +## Example credential subject + +```json +{ + "name": "Jane Doe", + "degree": "Bachelor of Science in Computer Science", + "institution": "University of Example", + "dateConferred": "2024-06-15", + "honors": "magna cum laude" +} +``` diff --git a/schemas/education/v1/schema.json b/schemas/education/v1/schema.json new file mode 100644 index 0000000..4b8f75d --- /dev/null +++ b/schemas/education/v1/schema.json @@ -0,0 +1,31 @@ +{ + "$id": "https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/education/v1/schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Education Credential", + "description": "Verifiable credential attesting that a person has been conferred an academic qualification by an institution.", + "type": "object", + "required": ["name", "degree", "institution", "dateConferred"], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Full name of the person to whom the credential is issued." + }, + "degree": { + "type": "string", + "minLength": 1, + "description": "The academic qualification conferred (e.g. \"Bachelor of Science in Computer Science\")." + }, + "institution": { + "type": "string", + "minLength": 1, + "description": "Legal name of the institution that conferred the qualification." + }, + "dateConferred": { + "type": "string", + "format": "date", + "description": "ISO 8601 date (YYYY-MM-DD) on which the qualification was conferred." + } + }, + "additionalProperties": true +} diff --git a/schemas/electricity/v1/README.md b/schemas/electricity/v1/README.md new file mode 100644 index 0000000..88a846d --- /dev/null +++ b/schemas/electricity/v1/README.md @@ -0,0 +1,189 @@ +# Electricity (Customer) Credential — v1 + +> **Source**: This schema is derived from the unified Customer Credential proposed in [beckn/DEG#208](https://github.com/beckn/DEG/pull/208). beckn/DEG remains the upstream — changes there should be reflected here. + +## Schema URL + +``` +https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/electricity/v1/schema.json +``` + +## Overview + +The **Customer Credential** is a unified W3C Verifiable Credential (VC Data Model 2.0) that combines five equal-level profile sections into a single `credentialSubject` object. The customer's DID (`id`) is optional per the W3C VC Data Model, and the five profiles sit as equal-level sibling properties. + +This credential is issued per meter — each meter will have its own credential. + +## Credential Structure + +``` +credentialSubject +├── id (optional customer DID) +├── customerProfile (required — identity: meter, customer number, idRef) +├── customerDetails (required — name, address, connection date) +├── consumptionProfile (optional — premises, connection type, load, tariff) +├── generationProfile (optional — DER type, capacity, commissioning) +└── storageProfile (optional — battery capacity, power rating, type) +``` + +## Issuer + +The credential is issued by energy providers. The issuer object contains: + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | URI | Yes | DID or URL of the issuing provider | +| `name` | string | Yes | Name of the provider | +| `idRef` | object | No | (Any) Identity reference — see [idRef](#idref) | + +Example: +```json +"issuer": { + "id": "did:web:bescom.karnataka.gov.in", + "name": "BESCOM - Bangalore Electricity Supply Company", + "idRef": { + "issuedBy": "did:web:kerc.karnataka.gov.in", + "subjectId": "kerc.karnataka.gov.in:AABPC12345" + } +} +``` + +## Validity Period + +Per the [W3C VC Data Model 2.0 validity period](https://www.w3.org/TR/2025/REC-vc-data-model-2.0-20250515/#validity-period), this credential uses: + +- **`validFrom`** (required) — date-time from which the credential is valid +- **`validUntil`** (optional) — date-time until which the credential is valid + +All date-time values include an explicit timezone offset (e.g., `2025-01-13T10:30:00-05:00`). + +## Revocation + +Credential revocation is managed via DeDi. See [credentialStatus](../readme.md#credentialstatus) in the top-level readme. + +## Profile Sections + +### customerProfile + +Core customer identity fields: + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `customerNumber` | string | Yes | Full customer account number assigned by the utility | +| `meterNumber` | string | Yes | Unique meter serial number | +| `meterType` | enum | Yes | Type of meter — see [meterType enum](#metertype-enum) | +| `idRef` | object | No | External identity reference (e.g., government ID) — see [idRef](#idref) | + +#### meterType enum + +Values derived from Green Button / ESPI meter kind classifications: + +| Value | Description | +|-------|-------------| +| `AMR` | Automated Meter Reading | +| `AMI` | Advanced Metering Infrastructure (smart meter) | +| `Electromechanical` | Traditional electromechanical meter | +| `Forward` | Forward-only (import) meter | +| `Reverse` | Reverse-only (export) meter | +| `Bidirectional` | Bidirectional meter (import + export) | +| `Prepaid` | Prepaid/token-based meter | +| `NetMeter` | Net metering meter | +| `Other` | Other meter type | + +### customerDetails + +Personal and address information: + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `fullName` | string | Yes | Full name of the customer as per ID proof | +| `installationAddress` | object | Yes | Address of the installation (see below) | +| `serviceConnectionDate` | date-time | Yes | Date and time when the electricity connection was activated | + +#### installationAddress + +Follows the [beckn Location schema](https://github.com/beckn/protocol-specifications/blob/master/schema/Location.yaml) with an additional `openLocationCode` field. + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | string | No | Unique identifier for the location | +| `descriptor` | object | No | Physical description of the location (`name`, `code`, `short_desc`, `long_desc`) | +| `map_url` | string (uri) | No | URL to the map of the location | +| `gps` | string | No | GPS coordinates as `"lat,lng"` string (e.g., `"12.9716,77.5946"`) | +| `address` | string | Yes | Complete postal address of the installation | +| `city` | object | No | City — `{ name: string, code: string }` | +| `district` | string | No | District or county name | +| `state` | object | No | State — `{ name: string, code: string }` | +| `country` | object | Yes | Country — `{ name: string, code: string }` (ISO 3166-1 alpha-2 code required) | +| `area_code` | string | Yes | Area code or postal/ZIP code | +| `circle` | object | No | Circular geo-fence — `{ gps: string, radius: Scalar }` | +| `polygon` | string | No | Boundary polygon of the location | +| `3dspace` | string | No | Three dimensional region describing the location | +| `rating` | string | No | Rating of the location | +| `openLocationCode` | string | No | Open Location Code (OLC) for the installation location | + +The address object aligns with the [beckn protocol Location schema](https://github.com/beckn/protocol-specifications/blob/master/schema/Location.yaml) and reuses [schema.org](https://schema.org/) vocabulary where applicable. + +### consumptionProfile + +Connection and consumption characteristics: + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `premisesType` | enum | Yes | `Residential`, `Commercial`, `Industrial`, or `Agricultural` | +| `connectionType` | enum | Yes | `Single-phase` or `Three-phase` | +| `sanctionedLoadKW` | number | Yes | Sanctioned electrical load in kW | +| `tariffCategoryCode` | string | Yes | Billing/tariff category code | + +### generationProfile + +DER generation capability: + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `assetId` | string | No | Unique identifier for the generation asset | +| `generationType` | enum | Yes | `Solar`, `Wind`, `MicroHydro`, or `Other` | +| `capacityKW` | number | Yes | Installed generation capacity in kW | +| `commissioningDate` | date-time | Yes | Date and time when the system was activated | +| `manufacturer` | string | No | Equipment manufacturer | +| `modelNumber` | string | No | Equipment model number | + +### storageProfile + +Battery/energy storage capability: + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `assetId` | string | No | Unique identifier for the storage asset | +| `storageCapacityKWh` | number | Yes | Storage capacity in kWh | +| `powerRatingKW` | number | Yes | Charge/discharge power rating in kW | +| `commissioningDate` | date-time | Yes | Date and time when the system was activated | +| `storageType` | enum | No | `LithiumIon`, `LeadAcid`, `FlowBattery`, or `Other` | + +## idRef + +A reusable identity reference pattern. In this credential it appears in: + +- **`issuer.idRef`** — the utility's regulatory registration +- **`customerProfile.idRef`** — the customer's external identity + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `issuedBy` | URI (DID) | Yes | DID of the authority that issued the identity | +| `subjectId` | string | Yes | Identifier in the format `authority-domain:id-value` | + +Example (customer's government ID): +```json +"idRef": { + "issuedBy": "did:web:ssa.gov", + "subjectId": "ssa.gov:XXX-XX-1234" +} +``` + +## Files + +| File | Description | +|------|-------------| +| `context.jsonld` | JSON-LD context defining semantic mappings for all five profile sections | +| `schema.json` | JSON Schema (draft 2020-12) for credential validation | +| `example.json` | Sample credential with all five profiles populated | diff --git a/schemas/electricity/v1/context.jsonld b/schemas/electricity/v1/context.jsonld new file mode 100644 index 0000000..58660e3 --- /dev/null +++ b/schemas/electricity/v1/context.jsonld @@ -0,0 +1,303 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "schema": "https://schema.org/", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "deg": "https://schema.beckn.io/deg#", + "CustomerCredential": { + "@id": "deg:CustomerCredential", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type" + } + }, + "customerProfile": { + "@id": "deg:customerProfile", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + "customerNumber": { + "@id": "deg:customerNumber", + "@type": "xsd:string" + }, + "meterNumber": { + "@id": "deg:meterNumber", + "@type": "xsd:string" + }, + "meterType": { + "@id": "deg:meterType", + "@type": "xsd:string" + }, + "idRef": { + "@id": "deg:idRef", + "@type": "@id", + "@context": { + "issuedBy": { + "@id": "deg:issuedBy", + "@type": "@id" + }, + "subjectId": { + "@id": "deg:subjectId", + "@type": "xsd:string" + } + } + } + } + }, + "customerDetails": { + "@id": "deg:customerDetails", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + "fullName": { + "@id": "schema:name", + "@type": "xsd:string" + }, + "serviceConnectionDate": { + "@id": "deg:serviceConnectionDate", + "@type": "xsd:dateTime" + }, + "installationAddress": { + "@id": "beckn:Location", + "@type": "@id", + "@context": { + "beckn": "https://schema.beckn.io/", + "descriptor": { + "@id": "beckn:descriptor", + "@type": "@id", + "@context": { + "name": { + "@id": "beckn:name", + "@type": "xsd:string" + }, + "code": { + "@id": "beckn:code", + "@type": "xsd:string" + }, + "short_desc": { + "@id": "beckn:short_desc", + "@type": "xsd:string" + }, + "long_desc": { + "@id": "beckn:long_desc", + "@type": "xsd:string" + } + } + }, + "map_url": { + "@id": "beckn:map_url", + "@type": "@id" + }, + "gps": { + "@id": "beckn:gps", + "@type": "xsd:string" + }, + "address": { + "@id": "beckn:address", + "@type": "xsd:string" + }, + "city": { + "@id": "beckn:city", + "@type": "@id", + "@context": { + "name": { + "@id": "beckn:name", + "@type": "xsd:string" + }, + "code": { + "@id": "beckn:code", + "@type": "xsd:string" + } + } + }, + "district": { + "@id": "beckn:district", + "@type": "xsd:string" + }, + "state": { + "@id": "beckn:state", + "@type": "@id", + "@context": { + "name": { + "@id": "beckn:name", + "@type": "xsd:string" + }, + "code": { + "@id": "beckn:code", + "@type": "xsd:string" + } + } + }, + "country": { + "@id": "beckn:country", + "@type": "@id", + "@context": { + "name": { + "@id": "beckn:name", + "@type": "xsd:string" + }, + "code": { + "@id": "beckn:code", + "@type": "xsd:string" + } + } + }, + "area_code": { + "@id": "beckn:area_code", + "@type": "xsd:string" + }, + "circle": { + "@id": "beckn:circle", + "@type": "@id", + "@context": { + "gps": { + "@id": "beckn:gps", + "@type": "xsd:string" + }, + "radius": { + "@id": "beckn:radius", + "@type": "@id" + } + } + }, + "polygon": { + "@id": "beckn:polygon", + "@type": "xsd:string" + }, + "3dspace": { + "@id": "beckn:3dspace", + "@type": "xsd:string" + }, + "rating": { + "@id": "beckn:rating", + "@type": "xsd:string" + }, + "openLocationCode": { + "@id": "deg:openLocationCode", + "@type": "xsd:string" + } + } + } + } + }, + "consumptionProfile": { + "@id": "deg:consumptionProfile", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + "premisesType": { + "@id": "deg:premisesType", + "@type": "xsd:string" + }, + "connectionType": { + "@id": "deg:connectionType", + "@type": "xsd:string" + }, + "sanctionedLoadKW": { + "@id": "deg:sanctionedLoadKW", + "@type": "xsd:decimal" + }, + "tariffCategoryCode": { + "@id": "deg:tariffCategoryCode", + "@type": "xsd:string" + } + } + }, + "generationProfile": { + "@id": "deg:generationProfile", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + "assetId": { + "@id": "deg:assetId", + "@type": "xsd:string" + }, + "generationType": { + "@id": "deg:generationType", + "@type": "xsd:string" + }, + "capacityKW": { + "@id": "deg:capacityKW", + "@type": "xsd:decimal" + }, + "commissioningDate": { + "@id": "deg:commissioningDate", + "@type": "xsd:dateTime" + }, + "manufacturer": { + "@id": "schema:manufacturer", + "@type": "xsd:string" + }, + "modelNumber": { + "@id": "deg:modelNumber", + "@type": "xsd:string" + } + } + }, + "storageProfile": { + "@id": "deg:storageProfile", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + "assetId": { + "@id": "deg:storageAssetId", + "@type": "xsd:string" + }, + "storageCapacityKWh": { + "@id": "deg:storageCapacityKWh", + "@type": "xsd:decimal" + }, + "powerRatingKW": { + "@id": "deg:powerRatingKW", + "@type": "xsd:decimal" + }, + "commissioningDate": { + "@id": "deg:storageCommissioningDate", + "@type": "xsd:dateTime" + }, + "storageType": { + "@id": "deg:storageType", + "@type": "xsd:string" + } + } + }, + "idRef": { + "@id": "deg:idRef", + "@type": "@id", + "@context": { + "issuedBy": { + "@id": "deg:issuedBy", + "@type": "@id" + }, + "subjectId": { + "@id": "deg:subjectId", + "@type": "xsd:string" + } + } + }, + "credentialStatus": { + "@id": "deg:credentialStatus", + "@type": "@id", + "@context": { + "statusPurpose": { + "@id": "deg:statusPurpose", + "@type": "xsd:string" + }, + "statusListCredential": { + "@id": "deg:statusListCredential", + "@type": "@id" + } + } + } + } +} diff --git a/schemas/electricity/v1/example.json b/schemas/electricity/v1/example.json new file mode 100644 index 0000000..c2968dc --- /dev/null +++ b/schemas/electricity/v1/example.json @@ -0,0 +1,102 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://schema.org/", + "https://schema.beckn.io/Location/2.0/context.jsonld", + "https://schema.beckn.io/deg/CustomerCredential/context.jsonld", + "https://schema.beckn.io/deg/CustomerProfile/context.jsonld", + "https://schema.beckn.io/deg/CustomerDetails/context.jsonld", + "https://schema.beckn.io/deg/ConsumptionProfile/context.jsonld", + "https://schema.beckn.io/deg/GenerationProfile/context.jsonld", + "https://schema.beckn.io/deg/StorageProfile/context.jsonld" + ], + "id": "urn:uuid:e5f6a7b8-9012-34ab-cdef-567890123456", + "type": [ + "VerifiableCredential", + "CustomerCredential" + ], + "issuer": { + "id": "https://example-utility.com/issuers/energy-dept", + "name": "Example Energy Utility", + "idRef": { + "issuedBy": "did:web:exreg.gov", + "subjectId": "exreg.gov:AABPC00001" + } + }, + "validFrom": "2025-01-13T10:30:00-05:00", + "validUntil": "2026-01-13T10:30:00-05:00", + "credentialStatus": { + "id": "https://dedi.global/dedi/lookup/example-utility.com/vc-revocation-registry/e5f6a7b8-9012-34ab-cdef-567890123456", + "type": "dedi", + "statusPurpose": "revocation", + "statusListCredential": "https://dedi.global/dedi/query/example-utility.com/vc-revocation-registry" + }, + "credentialSubject": { + "id": "did:example:customer:abc123", + "customerProfile": { + "customerNumber": "UTIL-2025-001234567", + "meterNumber": "MET2025789456123", + "meterType": "AMR", + "idRef": { + "issuedBy": "did:web:ssa.gov", + "subjectId": "ssa.gov:XXX-XX-1234" + } + }, + "customerDetails": { + "fullName": "Jane Doe", + "installationAddress": { + "id": "LOC-001", + "descriptor": { + "name": "Jane Doe Residence", + "short_desc": "Residential installation at 123 Energy Street" + }, + "gps": "37.7749,-122.4194", + "address": "123 Energy Street, Unit 4", + "city": { + "name": "Metro City", + "code": "METRO" + }, + "district": "Metro District", + "state": { + "name": "Example State", + "code": "EX" + }, + "country": { + "name": "United States", + "code": "US" + }, + "area_code": "12345", + "openLocationCode": "849VCWC8+R9" + }, + "serviceConnectionDate": "2025-01-10T00:00:00-05:00" + }, + "consumptionProfile": { + "premisesType": "Residential", + "connectionType": "Single-phase", + "sanctionedLoadKW": 5, + "tariffCategoryCode": "RES-01" + }, + "generationProfile": { + "assetId": "DER-SOLAR-001", + "generationType": "Solar", + "capacityKW": 3, + "commissioningDate": "2025-01-12T00:00:00-05:00", + "manufacturer": "SunPower Corporation", + "modelNumber": "SPR-X22-360" + }, + "storageProfile": { + "assetId": "BESS-001", + "storageCapacityKWh": 10, + "powerRatingKW": 5, + "commissioningDate": "2025-01-12T00:00:00-05:00", + "storageType": "LithiumIon" + } + }, + "proof": { + "type": "Ed25519Signature2020", + "created": "2025-01-13T10:30:00-05:00", + "verificationMethod": "https://example-utility.com/issuers/energy-dept#key-1", + "proofPurpose": "assertionMethod", + "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndTaXoT..." + } +} diff --git a/schemas/electricity/v1/schema.json b/schemas/electricity/v1/schema.json new file mode 100644 index 0000000..d817e4d --- /dev/null +++ b/schemas/electricity/v1/schema.json @@ -0,0 +1,576 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/electricity/v1/schema.json", + "title": "Customer Credential Schema", + "description": "JSON Schema for a unified customer credential that combines customer identity, customer details, consumption characteristics, generation capability, and storage capability as equal-level properties within a single W3C Verifiable Credential (VC Data Model 2.0). Issued by energy providers.", + "type": "object", + "required": [ + "@context", + "id", + "type", + "issuer", + "validFrom", + "credentialSubject" + ], + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "contains": { + "const": "https://www.w3.org/ns/credentials/v2" + }, + "minItems": 2 + }, + "id": { + "type": "string", + "format": "uri", + "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "description": "Unique identifier for the credential in URN UUID format" + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "contains": { + "const": "CustomerCredential" + }, + "minItems": 2 + }, + "issuer": { + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "string", + "format": "uri", + "description": "URL of the issuing provider" + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Name of the provider" + }, + "idRef": { + "type": "object", + "description": "Reference to an identity issued by an external authority", + "required": [ + "issuedBy", + "subjectId" + ], + "properties": { + "issuedBy": { + "type": "string", + "format": "uri", + "description": "DID of the authority that issued the identity (e.g., did:web:kerc.karnataka.gov.in)" + }, + "subjectId": { + "type": "string", + "pattern": "^[A-Za-z0-9._-]+:[A-Za-z0-9X_-]+$", + "description": "Subject identifier in the format authority-domain:id-value (e.g., kerc.karnataka.gov.in:AABPC12345)" + } + } + } + } + }, + "validFrom": { + "type": "string", + "format": "date-time", + "description": "Date and time from which the credential is valid (W3C VC Data Model 2.0)" + }, + "validUntil": { + "type": "string", + "format": "date-time", + "description": "Date and time until which the credential is valid (W3C VC Data Model 2.0)" + }, + "credentialStatus": { + "type": "object", + "required": [ + "id", + "type", + "statusPurpose", + "statusListCredential" + ], + "description": "Revocation status information for the credential", + "properties": { + "id": { + "type": "string", + "format": "uri", + "description": "URL to look up the revocation status of this specific credential via DeDi registry" + }, + "type": { + "type": "string", + "const": "dedi", + "description": "Type of status check mechanism (DeDi)" + }, + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ], + "description": "Purpose of the credential status entry" + }, + "statusListCredential": { + "type": "string", + "format": "uri", + "description": "URL to the issuer revocation registry on DeDi" + } + } + }, + "credentialSubject": { + "type": "object", + "description": "Single subject with five profile sections: customerProfile (required), customerDetails, consumptionProfile, generationProfile, storageProfile (all optional except customerProfile)", + "required": [ + "customerProfile" + ], + "properties": { + "id": { + "type": "string", + "format": "uri", + "description": "Optional DID of the customer/credential subject" + }, + "customerProfile": { + "$ref": "#/$defs/CustomerProfile" + }, + "customerDetails": { + "$ref": "#/$defs/CustomerDetails" + }, + "consumptionProfile": { + "$ref": "#/$defs/ConsumptionProfile" + }, + "generationProfile": { + "$ref": "#/$defs/GenerationProfile" + }, + "storageProfile": { + "$ref": "#/$defs/StorageProfile" + } + } + }, + "proof": { + "type": "object", + "required": [ + "type", + "created", + "verificationMethod", + "proofPurpose", + "proofValue" + ], + "properties": { + "type": { + "type": "string", + "description": "Cryptographic signature type (e.g., Ed25519Signature2020)" + }, + "created": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the proof was created" + }, + "verificationMethod": { + "type": "string", + "format": "uri", + "description": "URI of the verification method/public key" + }, + "proofPurpose": { + "type": "string", + "enum": [ + "assertionMethod", + "authentication" + ], + "description": "Purpose of the proof" + }, + "proofValue": { + "type": "string", + "minLength": 1, + "description": "The cryptographic signature value" + } + } + } + }, + "$defs": { + "CustomerProfile": { + "type": "object", + "description": "Core customer identity: customer number, meter number, external ID reference", + "required": [ + "customerNumber", + "meterNumber", + "meterType" + ], + "properties": { + "customerNumber": { + "type": "string", + "minLength": 1, + "description": "Full customer account number assigned by the utility" + }, + "meterNumber": { + "type": "string", + "minLength": 1, + "maxLength": 50, + "description": "Unique meter serial number" + }, + "meterType": { + "type": "string", + "description": "Type of electricity meter installed. Values derived from Green Button / ESPI meter kind classifications.", + "enum": [ + "AMR", + "AMI", + "Electromechanical", + "Forward", + "Reverse", + "Bidirectional", + "Prepaid", + "NetMeter", + "Other" + ] + }, + "idRef": { + "type": "object", + "description": "Reference to an identity issued by an external authority", + "required": [ + "issuedBy", + "subjectId" + ], + "properties": { + "issuedBy": { + "type": "string", + "format": "uri", + "description": "DID of the authority that issued the identity (e.g., did:web:kerc.karnataka.gov.in)" + }, + "subjectId": { + "type": "string", + "pattern": "^[A-Za-z0-9._-]+:[A-Za-z0-9X_-]+$", + "description": "Subject identifier in the format authority-domain:id-value (e.g., kerc.karnataka.gov.in:AABPC12345)" + } + } + } + } + }, + "CustomerDetails": { + "type": "object", + "description": "Customer personal and address information", + "required": [ + "fullName", + "installationAddress", + "serviceConnectionDate" + ], + "properties": { + "fullName": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Full name of the customer as per ID proof" + }, + "installationAddress": { + "type": "object", + "description": "The physical location of the installation. Follows the beckn Location schema.", + "required": [ + "address", + "area_code", + "country" + ], + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the location" + }, + "descriptor": { + "type": "object", + "description": "Physical description of the location", + "properties": { + "name": { + "type": "string", + "description": "Name of the location" + }, + "code": { + "type": "string", + "description": "Location code" + }, + "short_desc": { + "type": "string", + "description": "Short description of the location" + }, + "long_desc": { + "type": "string", + "description": "Long description of the location" + } + } + }, + "map_url": { + "type": "string", + "format": "uri", + "description": "URL to the map of the location" + }, + "gps": { + "type": "string", + "pattern": "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?),\\s*[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$", + "description": "GPS coordinates of the installation (e.g., '12.9716,77.5946')" + }, + "address": { + "type": "string", + "minLength": 1, + "description": "Complete postal address of the installation" + }, + "city": { + "type": "object", + "description": "City of the installation", + "properties": { + "name": { + "type": "string", + "description": "Name of the city" + }, + "code": { + "type": "string", + "description": "City code" + } + } + }, + "district": { + "type": "string", + "description": "District or county name" + }, + "state": { + "type": "object", + "description": "State or province of the installation", + "properties": { + "name": { + "type": "string", + "description": "Name of the state" + }, + "code": { + "type": "string", + "description": "State code as per country or international standards" + } + } + }, + "country": { + "type": "object", + "description": "Country of the installation", + "required": [ + "code" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the country" + }, + "code": { + "type": "string", + "pattern": "^[A-Z]{2}$", + "description": "Country code as per ISO 3166-1 alpha-2 format" + } + } + }, + "area_code": { + "type": "string", + "minLength": 1, + "description": "Area code or postal/ZIP code" + }, + "circle": { + "type": "object", + "description": "Circular geo-fence around the location", + "properties": { + "gps": { + "type": "string", + "pattern": "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?),\\s*[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$", + "description": "GPS coordinates of the center" + }, + "radius": { + "type": "object", + "description": "Radius of the circle", + "properties": { + "type": { + "type": "string" + }, + "value": { + "type": "string" + }, + "estimated_value": { + "type": "string" + }, + "computed_value": { + "type": "string" + }, + "range": { + "type": "object", + "properties": { + "min": { + "type": "string" + }, + "max": { + "type": "string" + } + } + }, + "unit": { + "type": "string" + } + } + } + } + }, + "polygon": { + "type": "string", + "description": "Boundary polygon of the location" + }, + "3dspace": { + "type": "string", + "description": "Three dimensional region describing the location" + }, + "rating": { + "type": "string", + "description": "Rating of the location" + }, + "openLocationCode": { + "type": "string", + "pattern": "^[23456789CFGHJMPQRVWX]{4,8}\\+[23456789CFGHJMPQRVWX]{0,4}$", + "description": "Open Location Code (OLC) for the installation location" + } + } + }, + "serviceConnectionDate": { + "type": "string", + "format": "date-time", + "description": "Date and time when the electricity connection was activated (with timezone offset)" + } + } + }, + "ConsumptionProfile": { + "type": "object", + "description": "Connection and consumption characteristics for load management and tariff purposes", + "required": [ + "premisesType", + "connectionType", + "sanctionedLoadKW", + "tariffCategoryCode" + ], + "properties": { + "premisesType": { + "type": "string", + "enum": [ + "Residential", + "Commercial", + "Industrial", + "Agricultural" + ], + "description": "Type of premises for the electricity connection" + }, + "connectionType": { + "type": "string", + "enum": [ + "Single-phase", + "Three-phase" + ], + "description": "Type of electrical connection" + }, + "sanctionedLoadKW": { + "type": "number", + "minimum": 0.5, + "maximum": 10000, + "description": "Sanctioned/approved electrical load in kilowatts (kW)" + }, + "tariffCategoryCode": { + "type": "string", + "minLength": 1, + "description": "Billing/tariff category code assigned by the utility" + } + } + }, + "GenerationProfile": { + "type": "object", + "description": "DER (Distributed Energy Resource) generation capability", + "required": [ + "generationType", + "capacityKW", + "commissioningDate" + ], + "properties": { + "assetId": { + "type": "string", + "minLength": 1, + "description": "Unique identifier for the generation asset" + }, + "generationType": { + "type": "string", + "enum": [ + "Solar", + "Wind", + "MicroHydro", + "Other" + ], + "description": "Type of distributed energy generation" + }, + "capacityKW": { + "type": "number", + "minimum": 0.1, + "maximum": 10000, + "description": "Installed generation capacity in kilowatts (kW)" + }, + "commissioningDate": { + "type": "string", + "format": "date-time", + "description": "Date and time when the generation system was activated (with timezone offset)" + }, + "manufacturer": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "description": "Equipment manufacturer" + }, + "modelNumber": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "description": "Equipment model number" + } + } + }, + "StorageProfile": { + "type": "object", + "description": "Battery/energy storage capability", + "required": [ + "storageCapacityKWh", + "powerRatingKW", + "commissioningDate" + ], + "properties": { + "assetId": { + "type": "string", + "minLength": 1, + "description": "Unique identifier for the storage asset" + }, + "storageCapacityKWh": { + "type": "number", + "minimum": 0.1, + "maximum": 10000, + "description": "Battery storage capacity in kilowatt-hours (kWh)" + }, + "powerRatingKW": { + "type": "number", + "minimum": 0.1, + "maximum": 10000, + "description": "Battery charge/discharge power rating in kilowatts (kW)" + }, + "commissioningDate": { + "type": "string", + "format": "date-time", + "description": "Date and time when the storage system was activated (with timezone offset)" + }, + "storageType": { + "type": "string", + "enum": [ + "LithiumIon", + "LeadAcid", + "FlowBattery", + "Other" + ], + "description": "Type of battery storage technology" + } + } + } + } +} diff --git a/schemas/employment/v1/README.md b/schemas/employment/v1/README.md new file mode 100644 index 0000000..5be8542 --- /dev/null +++ b/schemas/employment/v1/README.md @@ -0,0 +1,38 @@ +# Employment Credential — v1 + +JSON Schema for an employment verification credential. + +## URL + +``` +https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/employment/v1/schema.json +``` + +## Required fields + +| Field | Type | Format | Notes | +|---|---|---|---| +| `name` | string | — | Full name of the employee | +| `employer` | string | — | Legal name of the employer | +| `position` | string | — | Job title or role | +| `startDate` | string | `date` | When employment began | + +## Optional fields + +| Field | Type | Format | Notes | +|---|---|---|---| +| `endDate` | string | `date` | Omit while employment is current | + +`additionalProperties: true` — issuers may include compensation, department, employee ID, etc. + +## Example credential subject + +```json +{ + "name": "Jane Doe", + "employer": "Acme Corp", + "position": "Senior Engineer", + "startDate": "2022-01-10", + "department": "Platform" +} +``` diff --git a/schemas/employment/v1/schema.json b/schemas/employment/v1/schema.json new file mode 100644 index 0000000..22a7090 --- /dev/null +++ b/schemas/employment/v1/schema.json @@ -0,0 +1,36 @@ +{ + "$id": "https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/employment/v1/schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Employment Credential", + "description": "Verifiable credential attesting that a person holds (or held) a position at an organization.", + "type": "object", + "required": ["name", "employer", "position", "startDate"], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Full name of the employee." + }, + "employer": { + "type": "string", + "minLength": 1, + "description": "Legal name of the employing organization." + }, + "position": { + "type": "string", + "minLength": 1, + "description": "Job title or role held by the employee." + }, + "startDate": { + "type": "string", + "format": "date", + "description": "ISO 8601 date (YYYY-MM-DD) on which the employment began." + }, + "endDate": { + "type": "string", + "format": "date", + "description": "ISO 8601 date (YYYY-MM-DD) on which the employment ended. Omit if employment is current." + } + }, + "additionalProperties": true +} diff --git a/schemas/health/v1/README.md b/schemas/health/v1/README.md new file mode 100644 index 0000000..bf05645 --- /dev/null +++ b/schemas/health/v1/README.md @@ -0,0 +1,31 @@ +# Health Credential — v1 + +JSON Schema for a health-related certification credential (fitness-for-duty, professional medical certification, etc.). **Not** intended for clinical records or patient data. + +## URL + +``` +https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/health/v1/schema.json +``` + +## Required fields + +| Field | Type | Format | Notes | +|---|---|---|---| +| `name` | string | — | Full name of the subject | +| `certification` | string | — | Name of the certification | +| `issuingBody` | string | — | Issuing organization | +| `validUntil` | string | `date` | Expiry date (ISO 8601) | + +> Use a domain-specific schema for clinical health data — this schema covers certifications only. + +## Example credential subject + +```json +{ + "name": "Jane Doe", + "certification": "Aviation Medical Class 1", + "issuingBody": "DGCA", + "validUntil": "2027-04-01" +} +``` diff --git a/schemas/health/v1/schema.json b/schemas/health/v1/schema.json new file mode 100644 index 0000000..9de3050 --- /dev/null +++ b/schemas/health/v1/schema.json @@ -0,0 +1,31 @@ +{ + "$id": "https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/health/v1/schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Health Credential", + "description": "Verifiable credential attesting that a person holds a health-related certification (e.g. fitness-for-duty, professional medical certification).", + "type": "object", + "required": ["name", "certification", "issuingBody", "validUntil"], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Full name of the credential subject." + }, + "certification": { + "type": "string", + "minLength": 1, + "description": "Name of the health certification (e.g. \"Aviation Medical Class 1\")." + }, + "issuingBody": { + "type": "string", + "minLength": 1, + "description": "Legal name of the body that issued the certification." + }, + "validUntil": { + "type": "string", + "format": "date", + "description": "ISO 8601 date (YYYY-MM-DD) until which the certification is valid." + } + }, + "additionalProperties": true +} diff --git a/schemas/identity/v1/README.md b/schemas/identity/v1/README.md new file mode 100644 index 0000000..2e67f11 --- /dev/null +++ b/schemas/identity/v1/README.md @@ -0,0 +1,31 @@ +# Identity Credential — v1 + +JSON Schema for a basic identity credential anchored to a government-issued document. + +## URL + +``` +https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/identity/v1/schema.json +``` + +## Required fields + +| Field | Type | Format | Notes | +|---|---|---|---| +| `name` | string | — | Full legal name | +| `dateOfBirth` | string | `date` | ISO 8601 | +| `nationality` | string | — | ISO 3166-1 alpha-2 country code recommended | +| `documentNumber` | string | — | Underlying identity document number | + +> **Privacy note**: identity credentials carry sensitive PII. Issuers should consider selective disclosure (e.g. BBS+ proofs) and minimum-necessary collection. Verifiers must handle this data under applicable privacy law. + +## Example credential subject + +```json +{ + "name": "Jane Doe", + "dateOfBirth": "1990-04-12", + "nationality": "IN", + "documentNumber": "P1234567" +} +``` diff --git a/schemas/identity/v1/schema.json b/schemas/identity/v1/schema.json new file mode 100644 index 0000000..3d419e8 --- /dev/null +++ b/schemas/identity/v1/schema.json @@ -0,0 +1,31 @@ +{ + "$id": "https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/identity/v1/schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Identity Credential", + "description": "Verifiable credential attesting basic identity attributes of a person, anchored to a government-issued document.", + "type": "object", + "required": ["name", "dateOfBirth", "nationality", "documentNumber"], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Full legal name of the person." + }, + "dateOfBirth": { + "type": "string", + "format": "date", + "description": "ISO 8601 date of birth (YYYY-MM-DD)." + }, + "nationality": { + "type": "string", + "minLength": 1, + "description": "Nationality, recommended as an ISO 3166-1 alpha-2 country code (e.g. \"IN\", \"US\")." + }, + "documentNumber": { + "type": "string", + "minLength": 1, + "description": "Identifier of the underlying government-issued document (passport, national ID, etc.)." + } + }, + "additionalProperties": true +} diff --git a/schemas/salary-slip/README.md b/schemas/salary-slip/v1/README.md similarity index 100% rename from schemas/salary-slip/README.md rename to schemas/salary-slip/v1/README.md diff --git a/schemas/salary-slip/schema.json b/schemas/salary-slip/v1/example.json similarity index 100% rename from schemas/salary-slip/schema.json rename to schemas/salary-slip/v1/example.json diff --git a/schemas/salary-slip/v1/schema.json b/schemas/salary-slip/v1/schema.json new file mode 100644 index 0000000..832175e --- /dev/null +++ b/schemas/salary-slip/v1/schema.json @@ -0,0 +1,138 @@ +{ + "$id": "https://raw.githubusercontent.com/nfh-trust-labs/opencred-vc-schemas/main/schemas/salary-slip/v1/schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Salary Slip Credential", + "description": "Verifiable credential representing a salary slip (payslip) issued by an employer to an employee for a specific pay period. Aligned with Schema.org Invoice with salary-specific extensions.", + "type": "object", + "required": ["identifier", "dateCreated", "employer", "employee"], + "properties": { + "@context": { + "description": "JSON-LD context. Should include https://schema.org and the salary namespace.", + "oneOf": [ + { "type": "string" }, + { "type": "array" } + ] + }, + "@type": { + "description": "JSON-LD type(s). Should include \"Invoice\" and \"salary:SalarySlip\".", + "oneOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "identifier": { + "type": "string", + "minLength": 1, + "description": "Unique identifier for this salary slip." + }, + "dateCreated": { + "type": "string", + "format": "date", + "description": "ISO 8601 date the salary slip was issued." + }, + "paymentDueDate": { + "type": "string", + "format": "date", + "description": "Scheduled date for salary payment." + }, + "accountId": { + "type": "string", + "description": "Reference to the payroll account." + }, + "payPeriod": { + "type": "object", + "description": "Pay period covered by this slip.", + "required": ["startDate", "endDate"], + "properties": { + "@type": { "type": "string" }, + "startDate": { "type": "string", "format": "date" }, + "endDate": { "type": "string", "format": "date" } + }, + "additionalProperties": true + }, + "employer": { + "type": "object", + "description": "The organization paying the salary.", + "required": ["name"], + "properties": { + "@type": { "type": "string" }, + "name": { "type": "string", "minLength": 1 }, + "taxID": { "type": "string" }, + "address": { "type": "object" } + }, + "additionalProperties": true + }, + "employee": { + "type": "object", + "description": "The person receiving the salary.", + "required": ["name"], + "properties": { + "@type": { "type": "string" }, + "name": { "type": "string", "minLength": 1 }, + "identifier": { + "oneOf": [ + { "type": "string" }, + { "type": "array" }, + { "type": "object" } + ] + }, + "jobTitle": { "type": "string" } + }, + "additionalProperties": true + }, + "earnings": { + "type": "array", + "description": "Salary line items added to gross pay.", + "items": { "$ref": "#/definitions/salaryComponent" } + }, + "deductions": { + "type": "array", + "description": "Salary line items deducted from gross pay.", + "items": { "$ref": "#/definitions/salaryComponent" } + }, + "employerContributions": { + "type": "array", + "description": "Contributions paid by the employer that do not affect net pay.", + "items": { "$ref": "#/definitions/salaryComponent" } + }, + "totals": { + "type": "object", + "description": "Summary calculations for the pay period.", + "properties": { + "@type": { "type": "string" }, + "grossEarnings": { "$ref": "#/definitions/monetaryAmount" }, + "totalDeductions": { "$ref": "#/definitions/monetaryAmount" }, + "netPay": { "$ref": "#/definitions/monetaryAmount" } + }, + "additionalProperties": true + } + }, + "additionalProperties": true, + "definitions": { + "monetaryAmount": { + "type": "object", + "required": ["currency", "value"], + "properties": { + "@type": { "type": "string" }, + "currency": { + "type": "string", + "minLength": 3, + "maxLength": 3, + "description": "ISO 4217 currency code." + }, + "value": { "type": "number" } + }, + "additionalProperties": true + }, + "salaryComponent": { + "type": "object", + "required": ["component", "amount"], + "properties": { + "@type": { "type": "string" }, + "component": { "type": "string", "minLength": 1 }, + "amount": { "$ref": "#/definitions/monetaryAmount" } + }, + "additionalProperties": true + } + } +}