Skip to content
5 changes: 4 additions & 1 deletion .eleventyignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
_includes/
_includes/
ANALYSIS.md
REVIEW.md
PLAN.md
2 changes: 1 addition & 1 deletion chapi/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ permalink: /chapi/
---

The Credential Handler API (CHAPI) enables integration with Issuers, Verifiers,
and Wallets as defined in the [Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/) specification.
and Wallets as defined in the [Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model-2.0/) specification.

## [Issuers](/chapi/issuers/)
a role an entity can perform by asserting claims about one or more subjects, creating a verifiable credential from these claims, and transmitting the verifiable credential to a holder.
Expand Down
2 changes: 1 addition & 1 deletion chapi/issuers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ console.log('Ready to work with credentials!');
To communicate a Verifiable Credential over CHAPI, it must be wrapped in a `WebCredential` object, which is constructed as follows:

#### 1. Make a Verifiable Presentation
Incorporate the Verifiable Credential(s) into a *[Verifiable Presentation](https://www.w3.org/TR/vc-data-model/#presentations-0)*. A Verifiable Presentation contains an array of one or more Verifiable Credentials. For CHAPI, the Verifiable Presentation object does not need to be separately signed.
Incorporate the Verifiable Credential(s) into a *[Verifiable Presentation](https://www.w3.org/TR/vc-data-model-2.0/#presentations)*. A Verifiable Presentation contains an array of one or more Verifiable Credentials. For CHAPI, the Verifiable Presentation object does not need to be separately signed.

```javascript
const testPresentation = {
Expand Down
2 changes: 1 addition & 1 deletion chapi/verifiers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ console.log('Ready to work with credentials!');
```
## Construct a Web Credential Query
#### 1. Make a Verifiable Presentation Request
A verifier can request credentials over CHAPI by forming a *[Verifiable Presentation Request](https://w3c-ccg.github.io/vp-request-spec/)*. The example below illustrates a `QueryByExample`, which specifies the type of Verifiable Credential being requested and an optional reason for the request.
A verifier can request credentials over CHAPI by forming a *[Verifiable Presentation Request](https://www.w3.org/TR/vcalm/#verifiable-presentation-request)*. The example below illustrates a `QueryByExample`, which specifies the type of Verifiable Credential being requested and an optional reason for the request.

```javascript
const testVpr = {
Expand Down
4 changes: 2 additions & 2 deletions chapi/wallets/exchanges/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permalink: /chapi/wallets/exchanges/
> the issuance, verification, transmission, or presentation of verifiable
> credentials.
<figcaption>
<cite>from <a href="https://w3c-ccg.github.io/vc-api/#workflows-and-exchanges">VC API Workflows & Exchanges</a></cite>
<cite>from <a href="https://www.w3.org/TR/vcalm/#workflows-and-exchanges">VCALM Workflows & Exchanges</a></cite>
</figcaption>
</figure>

Expand Down Expand Up @@ -69,7 +69,7 @@ exchange is not yet complete and some *additional information is requested*, as
specified by the contents of the associated verifiable presentation request.

> Read more about possible values in the
> [Verifiable Presentation Requests](https://w3c-ccg.github.io/vp-request-spec/#overview)
> [Verifiable Presentation Requests](https://www.w3.org/TR/vcalm/#verifiable-presentation-request)
> specification.

For example:
Expand Down
4 changes: 2 additions & 2 deletions chapi/wallets/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ When credentials are requested, wallets should show the user what will be shared
This section is written from the perspective of web wallets. CHAPI provides a simple method for a 3rd party website to request an individual present their Decentralized Identifier (DID) and prove their identity. The individual selects a digital wallet to respond to this DID Authentication request.

### Resources
- [Verifiable Presentation Request](https://w3c-ccg.github.io/vp-request-spec/#did-authentication)
- [Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/#presentations)
- [Verifiable Presentation Request](https://www.w3.org/TR/vcalm/#did-authentication)
- [Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model-2.0/#presentations)
- [DID Core Specification](https://www.w3.org/TR/did-core/#authentication)

#### 1. The 3rd Party Site sends a DID Authentication Request
Expand Down
301 changes: 301 additions & 0 deletions chapi/wallets/interaction-url.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
---
title: "QR Code / Interaction URL Flow"
permalink: /chapi/wallets/interaction-url/
---

This page documents the end-to-end flow for wallets that initiate a credential
exchange by scanning a QR code. This is the recommended entry point for native
mobile wallets and any wallet that needs to work outside of a browser CHAPI
event.

The foundation for this flow is the
[VCALM (Verifiable Credentials API Lifecycle Management)](https://www.w3.org/TR/vcalm/)
specification.

---

## Overview

The flow has four steps:

1. **Scan** a QR code that encodes an _interaction URL_
2. **Dereference** the interaction URL to discover available protocols
3. **Select** a protocol and initiate the exchange
4. **Complete** the VCALM exchange loop — presenting credentials as requested
and receiving credentials in return

---

## Step 1 — Scan the QR Code

A QR code in this flow encodes an HTTPS URL called an _interaction URL_. Per the
VCALM spec, the URL MUST contain an `iuv` query parameter set to `1`. Example:

```
https://website.example/interactions/mno456?iuv=1
```

Your wallet scans the QR code and extracts this URL. The URL itself does not
reveal which protocols are supported — that is discovered in Step 2.

---

## Step 2 — Dereference the Interaction URL

To discover the available protocols, send an HTTP GET to the interaction URL
with an `Accept: application/json` header. The `iuv=1` parameter is already
part of the URL from the QR code:

```http
GET /interactions/mno456?iuv=1
Host: website.example
Accept: application/json
```

The response is a `protocols` object listing the supported exchange protocols:

```json
{
"protocols": {
"vcapi": "https://vcapi.service.example/workflows/abc123/exchanges/xyz789",
"OID4VP": "openid4vp://?client_id=..."
}
}
```

Defined protocol keys:

| Key | Description |
|---|---|
| `vcapi` | VCALM exchange URL — use for the VCALM flow described below |
| `OID4VP` | OpenID for Verifiable Presentations URL |
| `OID4VCI` | OpenID for Verifiable Credential Issuance URL |
| `inviteRequest` | VCALM invite-request response URL |

Your wallet should check which keys are present and select the protocol it
supports. If multiple are present, prefer the protocol your wallet is best
able to handle.

---

## Step 3 — Initiate the Exchange (VCALM)

If your wallet selects the `vcapi` protocol, begin the exchange by sending a
`POST` to the exchange URL with an empty JSON body:

```http
POST /workflows/abc123/exchanges/xyz789
Host: vcapi.service.example
Content-Type: application/json

{}
```

The server will respond with one or more of the following fields:

| Field | Meaning |
|---|---|
| _(empty body)_ | Exchange is complete — nothing further needed |
| `verifiablePresentationRequest` | Server is requesting credentials from the wallet |
| `verifiablePresentation` | Server is offering credentials to the wallet |
| `verifiablePresentation` + `verifiablePresentationRequest` | Server offers credentials and simultaneously requests more |
| `redirectUrl` | Exchange is complete — navigate the user to this URL or handle another interaction URL |

A `4xx` HTTP response indicates an error; the body will contain details.

---

## Step 4 — Complete the Exchange Loop

Exchanges are multi-turn. The wallet and server pass messages back and forth
until neither side has outstanding requests.

### Responding to a Verifiable Presentation Request

When the server responds with a `verifiablePresentationRequest`, inspect the
`query` array to understand what is needed:

```json
{
"verifiablePresentationRequest": {
"query": [{
"type": "QueryByExample",
"credentialQuery": [{
"reason": "We need proof of your career credentials.",
"example": {
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v1"
],
"type": "PermanentResidentCard"
}
}]
}],
"challenge": "abc123",
"domain": "vcapi.service.example"
}
}
```

Supported query types ([VCALM spec](https://www.w3.org/TR/vcalm/#verifiable-presentation-request)):

- `QueryByExample` — match credentials by `@context` and `type`
- `DIDAuthentication` — prove control of a DID
- `AuthorizationCapabilityQuery` — present a ZCAP authorization capability
- `DigitalCredentialQueryLanguage` — alternative query format

Find the matching credentials in the wallet, build a signed Verifiable
Presentation, and POST it back to the **same exchange URL**:

```http
POST /workflows/abc123/exchanges/xyz789
Host: vcapi.service.example
Content-Type: application/json

{
"verifiablePresentation": {
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiablePresentation"],
"holder": "did:example:z6Mk...",
"verifiableCredential": [{ ... }],
"proof": { ... }
}
}
```

### Receiving Credentials

When the response includes `verifiablePresentation`, the server is delivering
credentials to the wallet:

```json
{
"verifiablePresentation": {
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiablePresentation"],
"verifiableCredential": [{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://w3id.org/citizenship/v1"
],
"type": ["VerifiableCredential", "PermanentResidentCard"],
"credentialSubject": { ... },
"proof": { ... }
}]
}
}
```

Store each credential in the wallet. If the same response also contains a
`verifiablePresentationRequest`, continue the loop.

### Exchange Complete

The exchange is finished when the server returns either an empty body or a
`redirectUrl`. If a `redirectUrl` is present, offer the user the option to
continue there (e.g., open in browser). If the `redirectUrl` value is
another interaction URL (i.e., it includes `?iuv=1`), then it can be
handled as another interaction to be processed.

---

## Full Exchange Example (JavaScript)

```js
async function runExchange(interactionUrl) {
// Step 2 — discover protocols
// interactionUrl already contains ?iuv=1 as encoded in the QR code
const protocolsResponse = await fetch(
interactionUrl,
{headers: {Accept: 'application/json'}}
);
const {protocols} = await protocolsResponse.json();

if(!protocols.vcapi) {
throw new Error('vcapi protocol not available');
}

// Step 3 — initiate exchange
let body = {};
let response = await fetch(protocols.vcapi, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(body)
});

// Step 4 — exchange loop
await handleExchangeResponse(protocols.vcapi, await response.json());
}

async function handleExchangeResponse(exchangeUrl, body) {
if(Object.keys(body).length === 0) {
// exchange complete
return;
}

if('verifiablePresentation' in body) {
// store the received credentials
await storeCredentials(body.verifiablePresentation.verifiableCredential);
}

if('redirectUrl' in body) {
// offer user option to navigate; if the redirectUrl contains `?iuv=1`
// it is itself an interaction URL and can be processed as a new exchange
offerRedirect(body.redirectUrl);
return;
}

if('verifiablePresentationRequest' in body) {
// find matching credentials and respond
const vp = await buildVerifiablePresentation(body.verifiablePresentationRequest);
const response = await fetch(exchangeUrl, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({verifiablePresentation: vp})
});
await handleExchangeResponse(exchangeUrl, await response.json());
}
}
```

---

## OID4* Protocols

If the `protocols` object contains an `OID4VCI` or `OID4VP` key instead of (or
in addition to) `vcapi`, the value is a protocol-specific URL your wallet can
use to continue the flow using those protocols.

Example `OID4VCI` value:
```
openid-credential-offer://?credential_offer=%7B...%7D
```

See [OID4* Integration](/playground/oid4/) for details on the server-side
setup, and refer to the
[OID4VCI Final Spec](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html)
and
[OID4VP Final Spec](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html)
for wallet-side implementation details.

---

## Sequence Diagram

```mermaid
sequenceDiagram
participant U as User
participant W as Wallet
participant S as VCALM Service

U->>W: Scan QR code (URL already contains ?iuv=1)
W->>S: GET /workflows/abc/exchanges/xyz?iuv=1
S->>W: { protocols: { vcapi: "...", OID4VP: "..." } }
W->>S: POST /workflows/abc/exchanges/xyz {}
S->>W: { verifiablePresentationRequest: { ... } }
W->>U: Show credential request to user
U->>W: Approve
W->>S: POST /workflows/abc/exchanges/xyz { verifiablePresentation: { ... } }
S->>W: { verifiablePresentation: { verifiableCredential: [...] } }
W->>U: Store received credentials
```
8 changes: 4 additions & 4 deletions chapi/wallets/native/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ Below is a partial example response:
```

More complete examples can be found in the
[Example Exchanges](https://w3c-ccg.github.io/vc-api/#exchange-examples)
section of the [VC-API Specification](https://w3c-ccg.github.io/vc-api/).
[Example Exchanges](https://www.w3.org/TR/vcalm/#exchange-examples)
section of the [VCALM Specification](https://www.w3.org/TR/vcalm/).

### OID4VCI

Expand Down Expand Up @@ -334,5 +334,5 @@ When no `verifiablePresentationRequest` object is present, the exchange is
complete.

More complete examples can be found in the
[Example Exchanges](https://w3c-ccg.github.io/vc-api/#exchange-examples)
section of the [VC-API Specification](https://w3c-ccg.github.io/vc-api/).
[Example Exchanges](https://www.w3.org/TR/vcalm/#exchange-examples)
section of the [VCALM Specification](https://www.w3.org/TR/vcalm/).
Loading