> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didx.co.za/llms.txt
> Use this file to discover all available pages before exploring further.

# Anatomy of an SD-JWT credential preset

> How an SD-JWT credential preset is structured, attribute by attribute.

This page walks through the shape of an **SD-JWT** credential preset field by field. For the mDoc shape, see [Anatomy of an mDoc credential preset](/products/didx-me/guides/issuers/mdoc-credential-preset-anatomy).

## SD-JWT in one minute: the VCT

The **VCT (Verifiable Credential Type)** is a URL, defined by the SD-JWT-VC specification, that names the kind of credential. It's the credential's *type identifier*: a verifier looking at a presented credential reads its `vct` value to know what kind of credential it is, what fields it carries, and how to interpret them. Two credentials with the same VCT are the same kind of credential.

The URL itself doesn't need to resolve to anything, but the convention is that it could — pointing to a published metadata document describing the credential type, schema, and display rules.

The VCT is the bridge between everyone who touches the credential:

* The **preset** declares the VCT in its `templateType`.
* The **issued credential** carries the VCT in its `vct` claim.
* The **presentation request** uses the VCT in `templateCredentials[].type` to filter the holder's wallet down to credentials of the right kind.

```
preset.templateType  ─────►  credential.vct  ─────►  presentation request type matcher
```

If those three values don't match exactly, nothing connects: the wallet won't surface the right credentials, and verification won't happen. So picking the VCT correctly is the foundational decision in publishing a preset.

The platform builds the VCT for you, derived from the preset's `<author>` and `<code>`:

```
https://didx.co.za/vct/<author>/<code>     e.g. https://didx.co.za/vct/acme/degree-certificate
```

Everything else on this page is configuration *around* that identifier.

## The shape, end to end

```json theme={null}
{
  "id": "didx:basic-identity",
  "author": "didx",
  "code": "basic-identity",
  "credentialFormat": "sd-jwt",
  "templateName": "Basic Identity Credential",
  "templateDescription": "Standard basic identity credential",
  "templateType": "https://didx.co.za/vct/didx/basic-identity",
  "templateAttributes": {
    "firstName": {
      "type": "string",
      "name": "First Name",
      "required": true,
      "alwaysDisclosed": false
    },
    "lastName": {
      "type": "string",
      "name": "Last Name",
      "required": true,
      "alwaysDisclosed": false
    }
  },
  "issuerConfig": { "signer": "did:web" },
  "validUntil": { "start": "validFrom", "future": { "years": 5 } }
}
```

## Identifier and metadata

The shared metadata fields (`id`, `author`, `code`, `templateName`, `templateDescription`, `credentialFormat`) are documented on the [credential presets intro](/products/didx-me/guides/issuers/credential-presets-intro#identifier-and-metadata). The fields specific to SD-JWT are below.

### `templateType` (the VCT)

The VCT for this preset. Set automatically (see [SD-JWT in one minute](#sd-jwt-in-one-minute-the-vct)); not user-supplied.

### `issuerConfig`

How the platform signs credentials issued from this preset:

```json theme={null}
{ "signer": "did:web" }
// or
{ "signer": "certificate", "keyType": "P-256" }
```

* **`did:web`** (the typical default) — credentials are signed using the tenant's `did:web` DID. Verifiers fetch the DID document to validate the signature.
* **`certificate`** — credentials are signed using an x509 certificate from the tenant's certificate pool. The optional `keyType` (`P-256` or `Ed25519`) narrows the selection to a specific algorithm.

### `validUntil`

How long the issued credentials remain valid. Optional; defaults to five years measured from `validFrom`.

```json theme={null}
{ "start": "validFrom", "future": { "years": 5 } }
```

| Field                                            | What it is                                                                                                                                               |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `start`                                          | When the validity window starts counting. `"validFrom"` (the typical SD-JWT choice) or `"issuance"` (required when `signer` is `certificate`).           |
| `future.days` / `future.months` / `future.years` | The duration of the window. Specify any combination; the total must not exceed the platform cap (5 years for DID-signed, 1 year for certificate-signed). |

## `templateAttributes`: the credential's fields

A flat map from attribute name to its definition. Each entry expresses a field on the credential and how it should behave at presentation time.

```json theme={null}
"firstName": {
  "type": "string",
  "name": "First Name",
  "required": true,
  "alwaysDisclosed": false
}
```

| Field             | What it is                                                                                                                    |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `type`            | Data type. Primitives: `string`, `number`, `boolean`, `date`. Compound: `object` (with `properties`), `array` (with `items`). |
| `name`            | Human-readable label the wallet shows the holder (e.g. `"First Name"`, not `"firstName"`).                                    |
| `description`     | Optional explanation of the attribute.                                                                                        |
| `required`        | Whether the issuer must supply a value for this attribute when issuing.                                                       |
| `alwaysDisclosed` | Whether the attribute is always revealed when the credential is presented, regardless of selective disclosure.                |

The attribute keys you declare (e.g. `firstName`, `lastName`) are what issuers pass under `attributes` when calling the issuance endpoint, and what verifiers ask for in a presentation request. They become the JSON keys on the issued credential itself.

### Nested objects and arrays

SD-JWT supports nested attribute structures. An `object` attribute carries its own `properties` map; an `array` attribute carries an `items` schema:

```json theme={null}
"address": {
  "type": "object",
  "name": "Address",
  "required": false,
  "alwaysDisclosed": false,
  "properties": {
    "country": {
      "type": "string",
      "name": "Country",
      "required": true,
      "alwaysDisclosed": true
    }
  }
},
"nationalities": {
  "type": "array",
  "name": "Nationalities",
  "required": false,
  "alwaysDisclosed": false,
  "items": { "type": "string" }
}
```

### `alwaysDisclosed` and selective disclosure

For SD-JWT credentials, the holder controls what they share on a per-presentation basis. `alwaysDisclosed: false` (the default) means an attribute can be withheld when the credential is presented; `alwaysDisclosed: true` means it is always revealed.

Set `alwaysDisclosed: true` only for fields whose presence is meaningful in itself, typically trust signals like a `verified` flag, where the credential carries no useful meaning without it. For ordinary personal data (name, date of birth, etc.), leave it `false` and let the holder decide.

## What happens at issuance time

When an issuer issues a credential against the preset, the platform uses its structure directly:

1. The issuer calls the issuance endpoint with `presetId` and an `attributes` map containing values for each key in `templateAttributes`.
2. The platform validates the attribute values against `templateAttributes`: required fields must be present, types must match, and undeclared keys are rejected.
3. It produces an SD-JWT credential typed with the preset's `templateType`, signed by the configured `issuerConfig.signer`, with the validity window from `validUntil`.
4. The credential is offered to the holder's wallet, where they can accept it.
5. Once accepted, the credential lives in the wallet, ready to be used in any presentation request that asks for credentials of this `type` from a trusted issuer.
