> 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/develop/wallet-server/credential-management.md).

# Credential Management

The Wallet Server runs a multi-tenant cloud wallet. Each **holder** is a per-user tenant that stores the Verifiable Credentials (VCs) belonging to one user. A holder acquires a credential by **processing a credential-offer URI**: the platform requests, binds, and stores the credential automatically. (This offer flow is the only way credentials enter a wallet — there is no raw-JSON upload.) Once stored, you can list the credentials in their raw (encoded) form or as decoded payloads.

All endpoints in this section are scoped to a single holder under `/holders/:holderId` and require a valid Bearer token with the **admin** role. Ownership is enforced, so a user can only operate on holders they own.

```
Authorization: Bearer <token>
```

A holder is created beforehand via `POST /agent/holder` (see [Holders and Tenancy](/develop/wallet-server/holders-and-tenancy.md)). The `holderId` returned there is the tenant id used in every path below.

## Acquiring a credential

**POST** `/holders/:holderId/process`

Processes a URI scanned from a QR code or received from an issuer or verifier. The same endpoint handles both directions, dispatching on the URI scheme:

* `openid-credential-offer://...` — accepts a credential offer. The holder resolves the offer, requests the offered credential(s), binds them to the holder's DID, and stores them in the wallet.
* `openid4vp://...` (or an `https://` authorization request) — responds to a verification request by selecting matching credentials and sending the presentation.

### Request Body

* **uri** (string, required): the credential-offer or authorization-request URI.

```
curl -X POST http://localhost:3000/holders/594b464b-20bd-495a-9fb6-87328c759629/process \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{"uri": "openid-credential-offer://?credential_offer_uri=..."}'
```

### Response Body

For a credential offer (issuance):

```
{
  "status": "success",
  "claimed": 1,
  "ids": ["8f2c1d4e-6a7b-4c9d-90ef-12ab34cd56ef"]
}
```

* **status**: `success` on completion.
* **claimed**: number of credentials stored from the offer.
* **ids**: identifiers of the stored credentials, usable to correlate entries returned by the listing endpoints.

For an authorization request (verification) the response is `{ "status": "success", "action": "presentation_sent" }`. For the full issuance and presentation walkthroughs, see [Processing Credential Offers and Presentation Requests](/develop/wallet-server/flows-claim-and-presentation.md).

## Listing raw credentials

**GET** `/holders/:holderId/credentials`

Returns every credential currently stored for the holder in its raw, encoded form (the compact string the wallet received and can present).

```
curl -H 'Authorization: Bearer <token>' \
  http://localhost:3000/holders/594b464b-20bd-495a-9fb6-87328c759629/credentials
```

### Response Body

An array of credential entries:

```
[
  {
    "id": "8f2c1d4e-6a7b-4c9d-90ef-12ab34cd56ef",
    "format": "dc+sd-jwt",
    "credential": "eyJhbGciOi...~WyJzYWx0Ii...~"
  }
]
```

* **id**: the wallet record id for the credential.
* **format**: the stored credential format (see Supported formats below).
* **credential**: the encoded credential — a compact SD-JWT or JWT string, or a JSON object for JSON-LD VCs.

## Listing decoded credentials

**GET** `/holders/:holderId/credentials/decoded`

Returns the same credentials with their payloads decoded, which is convenient for inspecting claims without parsing the compact encoding yourself.

```
curl -H 'Authorization: Bearer <token>' \
  http://localhost:3000/holders/594b464b-20bd-495a-9fb6-87328c759629/credentials/decoded
```

### Response Body

An array of decoded entries:

```
[
  {
    "id": "8f2c1d4e-6a7b-4c9d-90ef-12ab34cd56ef",
    "format": "dc+sd-jwt",
    "decoded": {
      "header": { "alg": "EdDSA", "typ": "dc+sd-jwt" },
      "payload": { "vct": "https://issuer.example.com/vct/employee-badge", "_sd": ["..."] },
      "prettyClaims": {
        "vct": "https://issuer.example.com/vct/employee-badge",
        "employee_id": "E-1024",
        "full_name": "Ada Lovelace",
        "department": "Engineering"
      }
    }
  }
]
```

* **id**: the wallet record id.
* **format**: the decoded credential format.
* **decoded**: the decoded content, which varies by format:
  * **SD-JWT VC** — `header`, `payload`, and `prettyClaims` (claims with selective-disclosure digests resolved into their values); `kbJwt` is included when a key-binding JWT is present.
  * **JWT-VC-JSON** — `header` and `payload`.
  * For a JSON-LD VC stored as a JSON object, `decoded` is the object itself.
* **error** (optional): a message describing why an entry could not be decoded; `decoded` is `null` in that case.

## Supported formats

The cloud wallet can store and list credentials in the formats the platform issues, plus additional formats it may receive during presentation flows:

* **SD-JWT VC** — reported as `dc+sd-jwt`.
* **JWT-VC-JSON** — reported as `jwt_vc_json`.
* **JSON-LD VC** — reported as `ldp_vc`.
* **W3C v2 credentials** — reported with their claim format (`vc+jwt` or `vc+sd-jwt`).
* **mdoc** — reported as `mso_mdoc`.

## Deletion

The holder API surface covers processing URIs and listing credentials (`POST /holders/:holderId/process`, `GET /holders/:holderId/credentials`, and `GET /holders/:holderId/credentials/decoded`). Deleting individual credentials or clearing a holder's store is not currently part of the API.


---

# 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/develop/wallet-server/credential-management.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.
