> For the complete documentation index, see [llms.txt](https://docs.empe.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.empe.io/getting-started/tutorial/uploading-schema.md).

# Uploading the Credential Schema

**What We Are Doing:**

* Defining a credential schema that describes the claims our credential will carry (e.g., `age`, `first_name`, `last_name`).
* Creating that schema on the platform, then assigning it to our Issuer so its credential configurations are advertised to wallets.

**Why:** A schema is the contract for a credential. It declares the claim names, their types, and which claims are mandatory, so credentials stay consistent and interoperable. Assigning a schema to an Issuer refreshes the Issuer's OpenID4VCI metadata so wallets can discover the schema's credential configurations.

This is a two-step workflow:

1. **Create the schema** with `POST /schemas` — this registers a reusable, versioned schema on the platform.
2. **Assign the schema** to your Issuer with `POST /issuers/:issuerDid/schemas` — this refreshes the Issuer's OpenID4VCI metadata so the schema's credential configurations are advertised to wallets.

Both endpoints require a valid OIDC Bearer token. Set up your environment first:

```bash
ISSUER_BASE_URL=https://your-issuer.evdi.app
ISSUER_DID=did:web:your-issuer.evdi.app:8f3c...   # your Issuer's DID
TOKEN=<your OIDC access token>                     # any valid OIDC access token (JWT); the tutorial reuses the admin token from the authentication step
```

## Step 1 — Create the schema

Create a `schema.json` file with the schema definition:

```json
{
  "name": "KYCCredential",
  "version": "1.0",
  "description": "Know-Your-Customer verification credential.",
  "formats": ["sd-jwt", "jwt-vc-json"],
  "schema": {
    "type": "object",
    "properties": {
      "age": { "type": "number" },
      "first_name": { "type": "string" },
      "last_name": { "type": "string" }
    },
    "required": ["age", "first_name", "last_name"]
  },
  "vct": "https://your-issuer.evdi.app/vct/kyc-credential",
  "disclosureFrame": ["age", "first_name", "last_name"]
}
```

A few notes on the fields:

* **`name`** and **`version`** are required and must be token-like (matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`) — no spaces. Together they form the schema identifier `name@version` (here, `KYCCredential@1.0`).
* **`schema`** is a JSON Schema describing the claims. Every key listed in `required` must also appear in `properties`.
* **`formats`** is optional; each entry is one of `sd-jwt` or `jwt-vc-json`. If omitted, both formats are enabled by default.
* **`vct`** is the credential type identifier used for SD-JWT VC credentials.
* **`disclosureFrame`** lists the claims a holder can selectively disclose when presenting an SD-JWT VC — the holder can reveal, for example, only `age` without exposing `first_name` or `last_name`.
* For JWT-VC-JSON credentials you can additionally set **`jwtVcTypes`** (e.g., `["VerifiableCredential", "KYCCredential"]`); if you leave it out, sensible defaults are derived from the schema name.

Upload it with `curl`:

```bash
curl -X POST "$ISSUER_BASE_URL/schemas" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @schema.json
```

The response echoes back the stored schema, including its identifier and lifecycle status:

```json
{
  "schemaId": "KYCCredential@1.0",
  "name": "KYCCredential",
  "version": "1.0",
  "status": "active",
  "schema": { "...": "the definition you sent" },
  "createdAt": "2026-06-22T12:00:00.000Z",
  "updatedAt": "2026-06-22T12:00:00.000Z"
}
```

Schemas are versioned. Creating a new version of an existing `name` (e.g., `KYCCredential@2.0`) automatically marks the previous active version as `superseded`, so the latest version becomes the default. Older versions remain retrievable with `GET /schemas/:schemaId?includeInactive=true` (or via `GET /schemas/:schemaName/versions`).

## Step 2 — Assign the schema to the Issuer

Creating a schema makes it available on the platform. Assigning it refreshes the Issuer's OpenID4VCI metadata so the schema's credential configurations are advertised to wallets. Assign it by posting the schema identifier (`name@version`):

```bash
curl -X POST "$ISSUER_BASE_URL/issuers/$ISSUER_DID/schemas" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "schemaId": "KYCCredential@1.0" }'
```

The response confirms the assignment:

```json
{ "status": "assigned" }
```

## What you get: credential configuration IDs

Each schema combined with a format produces a **credential configuration id** of the form `name@version:format`. Our `KYCCredential@1.0` schema with both formats enabled yields:

* `KYCCredential@1.0:sd-jwt`
* `KYCCredential@1.0:jwt-vc-json`

These configuration ids are what you reference when creating credential offers later in the tutorial. For example, an SD-JWT VC offer for this schema uses `KYCCredential@1.0:sd-jwt`.

With the schema created and assigned, the Issuer now knows exactly what a "KYC Verifiable Credential" looks like. Next, we'll look at the two credential formats and how selective disclosure works before issuing against these configuration ids.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.empe.io/getting-started/tutorial/uploading-schema.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
