> 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/issuer/issuance-sessions.md).

# Issuance Sessions

Every credential offer created by an issuer opens an **issuance session** that the platform tracks from the moment the offer is generated until the credential is delivered to a wallet (or the offer expires). Issuance sessions let you observe issuance progress, retrieve the offer URI again, and regenerate the QR code — without re-creating the offer.

All issuance-session endpoints require a valid Bearer token:

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

The service validates the JWT against the configured JWKS endpoint; any valid token is accepted at this layer (see [Authentication](/develop/issuer.md#authentication)).

## How a session is created

A session is opened automatically when you create a credential offer — there is no separate create-session endpoint. The offer response returns an `issuanceSessionId`, which is the handle for every operation on this page.

**POST** `/issuers/:issuerDid/credential-offers`

```bash
POST /issuers/did:key:z6Mkk.../credential-offers
Authorization: Bearer <token>
Content-Type: application/json
```

### Request Body

```json
{
  "credentialConfigurationIds": ["EmployeeBadge@1.0:sd-jwt"],
  "requirePin": false,
  "issuanceMetadata": {
    "claimsByConfigurationId": {
      "EmployeeBadge@1.0:sd-jwt": {
        "employee_id": "EMP-001",
        "full_name": "Ada Lovelace",
        "department": "Engineering"
      }
    }
  }
}
```

### Response Body

```json
{
  "credentialOfferUri": "openid-credential-offer://?credential_offer=...",
  "issuanceSessionId": "d07d0df5-0d64-4f1a-9aa7-7e7f9c2a1d70",
  "credentialConfigurationIds": ["EmployeeBadge@1.0:sd-jwt"]
}
```

* **credentialOfferUri**: The `openid-credential-offer://` URI a wallet scans or follows to claim the credential.
* **issuanceSessionId**: The identifier of the session opened for this offer. Use it to track progress and to fetch the session's QR code.
* **credentialConfigurationIds**: The credential configuration ids the offer covers, each of the form `Name@Version:format`.
* **userPin**: Present only when `requirePin` is `true`; the PIN the holder must enter to complete the pre-authorized code flow.

Optional fields such as `userPin` are omitted from the JSON when they do not apply (for example, when `requirePin` is `false`) rather than returned as `null`. Keep the returned `issuanceSessionId` — it is the path parameter for the get-session and QR-code endpoints below.

## List sessions for an issuer

Returns all issuance sessions belonging to a single issuer DID, most useful for an operator dashboard that shows pending and completed offers. The `issuerId` query parameter filters sessions to one issuer; it is not checked against existing issuers, and omitting it returns all issuance sessions across all issuers.

**GET** `/issuance-sessions?issuerId=<issuerId>`

```bash
GET /issuance-sessions?issuerId=did:key:z6Mkk...
Authorization: Bearer <token>
```

### Response Body

```json
[
  {
    "id": "d07d0df5-0d64-4f1a-9aa7-7e7f9c2a1d70",
    "issuerId": "did:key:z6Mkk...",
    "state": "OfferCreated",
    "credentialOfferUri": "openid-credential-offer://?credential_offer=...",
    "createdAt": "2026-06-22T12:34:56.789Z",
    "expiresAt": "2026-06-22T12:49:56.789Z",
    "issuedCredentials": []
  }
]
```

* **issuerId**: The issuer DID to filter by, passed as the `issuerId` query parameter.

For a freshly created `OfferCreated` session, `issuedCredentials` is an empty array (no credentials have been issued yet), and the optional `userPin` and `errorMessage` fields are absent from the JSON because they do not apply.

## Get a single session

Reads one session by its identifier, returning its current state and all tracking fields.

**GET** `/issuance-sessions/:sessionId`

```bash
GET /issuance-sessions/d07d0df5-0d64-4f1a-9aa7-7e7f9c2a1d70
Authorization: Bearer <token>
```

### Response Body

```json
{
  "id": "d07d0df5-0d64-4f1a-9aa7-7e7f9c2a1d70",
  "issuerId": "did:key:z6Mkk...",
  "state": "Completed",
  "credentialOfferUri": "openid-credential-offer://?credential_offer=...",
  "createdAt": "2026-06-22T12:34:56.789Z",
  "expiresAt": "2026-06-22T12:49:56.789Z",
  "issuedCredentials": ["EmployeeBadge@1.0:sd-jwt"]
}
```

Optional fields are omitted when they do not apply: `userPin` appears only when the offer required a PIN, and `errorMessage` appears only when the session ended in the `Error` state.

**Session fields**

* **id**: Internal session identifier (the same value as `issuanceSessionId` from the offer response).
* **issuerId**: The issuer DID that owns the session.
* **state**: Current lifecycle state of the session (see below).
* **credentialOfferUri**: The credential offer URI tied to the session.
* **createdAt**: ISO 8601 timestamp of when the session (and offer) was created.
* **expiresAt**: ISO 8601 timestamp after which the offer can no longer be claimed.
* **userPin**: The PIN for the pre-authorized code flow, present only when the offer required one.
* **errorMessage**: A human-readable error message when the session ended in the `Error` state; otherwise absent.
* **issuedCredentials**: The credential configuration ids issued in this session (for example `EmployeeBadge@1.0:sd-jwt`). It is an empty array until issuance completes, and is filled in as credentials are issued (fully populated once the state reaches `Completed`).

## Session states

The `state` field advances through the OpenID4VCI pre-authorized code flow as the wallet interacts with the issuer:

* **OfferCreated**: The offer has been generated and the session is waiting for a wallet to retrieve it.
* **OfferUriRetrieved**: A wallet has fetched the offer payload from the offer URI.
* **AuthorizationInitiated** / **AuthorizationGranted**: Authorization steps preceding token issuance.
* **AccessTokenRequested** / **AccessTokenCreated**: The wallet has requested and received an access token to call the credential endpoint.
* **CredentialRequestReceived**: The wallet has submitted a credential request.
* **CredentialsPartiallyIssued**: At least one — but not all — of the offered credentials has been issued.
* **Completed**: All offered credentials have been issued; `issuedCredentials` lists their configuration ids.
* **Error**: Issuance failed; `errorMessage` describes what went wrong.

To track issuance progress, poll **GET** `/issuance-sessions/:sessionId` and watch the `state` field. A session is finished when it reaches `Completed` (success) or `Error` (failure), or when `expiresAt` has passed without completion.

## Get the session QR code

Returns a PNG QR code that encodes the session's credential offer URI. This is handy for re-displaying an offer for an existing session without creating a new one — for example, refreshing the QR shown in an operator panel.

**GET** `/issuance-sessions/:sessionId/qr-code`

```bash
GET /issuance-sessions/d07d0df5-0d64-4f1a-9aa7-7e7f9c2a1d70/qr-code
Authorization: Bearer <token>
Accept: image/png
```

### Response

* **Body**: A 400×400 PNG image (`Content-Type: image/png`) of the QR code.
* **Header `X-Credential-Offer-Uri`**: The `openid-credential-offer://` URI encoded in the QR code, so callers can copy the offer without decoding the image.

A wallet that scans this QR code is taken through the same flow as the original offer, and its progress is reflected in the same session. The endpoint always regenerates the image from the session's stored offer URI, so it stays valid for the life of the offer (until `expiresAt`).

<figure><img src="/files/euvQwqLt5KDV5BhtoHoV" alt="Issuance session QR code in the operator console"><figcaption><p>An issuance session and its QR code in the operator console (Issuance Sessions tab)</p></figcaption></figure>

## Notes

* Use the `issuanceSessionId` from the offer response as the `:sessionId` path parameter for the get-session and QR-code endpoints.
* If you need the offer URI and QR at creation time rather than after the fact, the credential-offer endpoint has a `qr-code` variant (`POST /issuers/:issuerDid/credential-offers/qr-code`) that returns the PNG directly with `X-Credential-Offer-Uri`, `X-Issuance-Session-Id`, and `X-Pin` headers. See the credential issuance flow documentation.


---

# 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/issuer/issuance-sessions.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.
