> ## Documentation Index
> Fetch the complete documentation index at: https://developer.verilock.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Verifiable Credentials

> Issue and verify W3C-standard verifiable credentials for portable, privacy-preserving identity.

Verifiable Credentials (VCs) let you issue W3C-standard digital credentials from completed verifications. Users can store these credentials in their wallet and share them with other organizations -- enabling **one-time KYC** with privacy-preserving selective disclosure.

<Info>
  Verilock implements the [W3C Verifiable Credentials Data Model v2.0](https://www.w3.org/TR/vc-data-model-2.0/) standard with signed JWT format. Credentials are anchored to your organization's Decentralized Identifier (DID).
</Info>

## Why Verifiable Credentials?

| Traditional KYC                       | With Verifiable Credentials                      |
| ------------------------------------- | ------------------------------------------------ |
| User re-verifies for every service    | Verify once, reuse everywhere                    |
| Full PII shared each time             | Selective disclosure -- share only what's needed |
| No user control over shared data      | User chooses what to disclose                    |
| No interoperability between providers | W3C standard -- works across platforms           |
| High cost per re-verification         | Issue once, verify for free                      |

## How It Works

<Steps>
  <Step title="Verification completes">
    A user completes identity verification through the standard Verilock flow and receives an **approved** decision.
  </Step>

  <Step title="Credential issuance">
    You issue a verifiable credential containing selected claims from the verification result. The credential is signed as a JWT with your organization's DID.
  </Step>

  <Step title="User stores credential">
    The user receives the credential as a signed JWT. They can store it in a digital wallet (Verilock wallet, or any W3C-compatible wallet).
  </Step>

  <Step title="Selective disclosure">
    When presenting the credential, the user selectively discloses only the claims required -- e.g., "over 18" without revealing their full date of birth.
  </Step>

  <Step title="Third-party verification">
    Any organization with a Verilock API key can verify the credential's authenticity, check revocation status, and read only the disclosed claims.
  </Step>
</Steps>

## Selective Disclosure

Credentials support selective disclosure, allowing holders to reveal only specific claims:

| Full Credential Claims | Age Check         | Identity Check | AML Check       |
| ---------------------- | ----------------- | -------------- | --------------- |
| Full name              | --                | Full name      | --              |
| Date of birth          | --                | --             | --              |
| Nationality            | --                | Nationality    | Nationality     |
| Document number        | --                | --             | --              |
| Age over 18: true      | Age over 18: true | --             | --              |
| AML clear: true        | --                | --             | AML clear: true |
| Address                | --                | --             | --              |

***

## API Endpoints

### Issue a Credential

Issue a W3C Verifiable Credential from an approved verification session.

```
POST /v1/credentials/issue
```

<ParamField body="session_id" type="string" required>
  ID of an **approved** verification session.
</ParamField>

<ParamField body="credential_type" type="string" required>
  Type of credential: `IdentityCredential`, `AgeCredential`, or `AddressCredential`.
</ParamField>

<ParamField body="claims" type="string[]" required>
  Claims to include. Available: `full_name`, `first_name`, `last_name`, `date_of_birth`, `nationality`, `document_type`, `document_number`, `expiry_date`, `address`, `gender`, `age_over_18`, `age_over_21`, `aml_clear`, `identity_verified`.
</ParamField>

<ParamField body="expiration" type="string">
  ISO 8601 expiration date. Default: 1 year from issuance.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST \
    "https://verilock.io/api/v1/credentials/issue" \
    -H "Authorization: Bearer qi_live_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "session_id": "ses_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "credential_type": "IdentityCredential",
      "claims": ["full_name", "nationality", "age_over_18", "aml_clear"],
      "expiration": "2027-03-19T00:00:00Z"
    }'
  ```

  ```python Python theme={null}
  credential = client.credentials.issue({
      "session_id": "ses_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "credential_type": "IdentityCredential",
      "claims": ["full_name", "nationality", "age_over_18", "aml_clear"],
      "expiration": "2027-03-19T00:00:00Z",
  })
  print(credential["jwt"])  # Send to user for wallet storage
  ```

  ```javascript Node.js theme={null}
  const credential = await verilock.credentials.issue({
    session_id: 'ses_a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    credential_type: 'IdentityCredential',
    claims: ['full_name', 'nationality', 'age_over_18', 'aml_clear'],
    expiration: '2027-03-19T00:00:00Z',
  });
  console.log(credential.jwt); // Send to user
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "id": "vc_e5f6a1b2-c3d4-7890-fedc-ba0987654321",
    "status": "issued",
    "credential_type": "IdentityCredential",
    "issuer_did": "did:verilock:org:your-org-id",
    "subject_did": "did:verilock:user:user-uuid",
    "claims": ["full_name", "nationality", "age_over_18", "aml_clear"],
    "issued_at": "2026-03-19T10:00:00Z",
    "expires_at": "2027-03-19T00:00:00Z",
    "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6InZjK3NkLWp3dCJ9.eyJpc3MiOiJkaWQ6dmVyaWxvY2s6b3JnOi4uLiIs..."
  }
  ```
</ResponseExample>

***

### Verify a Credential

Verify a presented credential JWT. Any organization with a valid API key can call this endpoint.

```
POST /v1/credentials/verify-vc
```

<ParamField body="jwt" type="string" required>
  The credential JWT to verify.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST \
    "https://verilock.io/api/v1/credentials/verify-vc" \
    -H "Authorization: Bearer qi_live_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6InZjK3NkLWp3dCJ9..."}'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "valid": true,
    "credential_id": "vc_e5f6a1b2-c3d4-7890-fedc-ba0987654321",
    "issuer_did": "did:verilock:org:issuing-org-id",
    "issuer_verified": true,
    "expired": false,
    "revoked": false,
    "disclosed_claims": {
      "full_name": "Jean Dupont",
      "nationality": "FR",
      "age_over_18": true,
      "aml_clear": true
    },
    "verified_at": "2026-03-19T12:00:00Z"
  }
  ```
</ResponseExample>

***

### Get Credential in W3C Format

Retrieve the full W3C JSON-LD representation of a credential.

```
GET /v1/credentials/{id}/vc
```

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "@context": [
      "https://www.w3.org/ns/credentials/v2",
      "https://www.w3.org/ns/credentials/examples/v2"
    ],
    "type": ["VerifiableCredential", "IdentityCredential"],
    "issuer": "did:verilock:org:your-org-id",
    "validFrom": "2026-03-19T10:00:00Z",
    "validUntil": "2027-03-19T00:00:00Z",
    "credentialSubject": {
      "id": "did:verilock:user:user-uuid",
      "full_name": "Jean Dupont",
      "nationality": "FR",
      "age_over_18": true,
      "aml_clear": true
    }
  }
  ```
</ResponseExample>

***

### Revoke a Credential

```
POST /v1/credentials/{id}/revoke-vc
```

<ParamField body="reason" type="string" required>
  Revocation reason: `user_request`, `data_correction`, `fraud_detected`, `compliance`.
</ParamField>

Revoked credentials immediately fail verification with `revoked: true`.

***

### Resolve a DID

Resolve any Verilock DID to its DID Document.

```
GET /v1/did/{did}
```

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "@context": ["https://www.w3.org/ns/did/v1"],
    "id": "did:verilock:org:your-org-id",
    "verificationMethod": [{
      "id": "did:verilock:org:your-org-id#key-1",
      "type": "JsonWebKey2020",
      "controller": "did:verilock:org:your-org-id"
    }],
    "authentication": ["did:verilock:org:your-org-id#key-1"],
    "assertionMethod": ["did:verilock:org:your-org-id#key-1"],
    "service": [{
      "id": "#verification",
      "type": "VerificationService",
      "serviceEndpoint": "https://verilock.io/api/v1"
    }]
  }
  ```
</ResponseExample>

***

## Use Cases

### 1. Cross-Platform Onboarding (Fintech)

A neobank verifies a user once and issues a VC. The user later signs up for a crypto exchange in the same ecosystem -- instead of redoing KYC, they present their credential.

```javascript theme={null}
// Neobank: Issue credential after KYC approval
const vc = await neobank.credentials.issue({
  session_id: approvedSession.id,
  credential_type: 'IdentityCredential',
  claims: ['full_name', 'date_of_birth', 'nationality', 'aml_clear'],
});
// Send vc.jwt to user's wallet

// Crypto exchange: Verify the user's credential (no re-KYC needed)
const result = await exchange.credentials.verifyVc({ jwt: userJwt });
if (result.valid && result.disclosed_claims.aml_clear) {
  // Onboard user immediately -- no document upload needed
  createAccount(result.disclosed_claims);
}
```

**Impact**: Onboarding drops from 5 minutes to under 10 seconds. Conversion rate increases by 30%.

***

### 2. Age-Gated E-Commerce (Alcohol / Tobacco)

An online retailer needs to verify a buyer is over 18 at checkout, without collecting or storing personal data (GDPR-friendly).

```python theme={null}
# Issue an AgeCredential with minimal claims
vc = client.credentials.issue(
    session_id=session_id,
    credential_type="AgeCredential",
    claims=["age_over_18"],
    expiration="2027-01-01T00:00:00Z",
)

# At checkout, verify the buyer's age credential
result = client.credentials.verify_vc(jwt=buyer_jwt)
if result["valid"] and result["disclosed_claims"]["age_over_18"]:
    # Age verified -- no DOB, name, or document stored
    proceed_to_payment()
```

**Impact**: No PII stored, GDPR Article 5(1)(c) compliant (data minimization). No age verification cost per transaction after initial issuance.

***

### 3. Marketplace Trust Layer (Gig Economy)

A freelance marketplace requires verified identities for service providers. Workers verify once and reuse their credential across multiple marketplace platforms.

```javascript theme={null}
// Marketplace A verifies the worker
const vc = await marketplaceA.credentials.issue({
  session_id: approvedSession.id,
  credential_type: 'IdentityCredential',
  claims: ['full_name', 'nationality', 'identity_verified', 'aml_clear'],
});

// Marketplace B accepts the same credential
const check = await marketplaceB.credentials.verifyVc({ jwt: workerJwt });
if (check.valid && check.disclosed_claims.identity_verified) {
  activateProviderAccount(check.disclosed_claims.full_name);
}
```

***

### 4. Travel & Hospitality (Hotel Check-in)

A hotel chain issues identity credentials to verified guests. Guests use them for instant check-in at any hotel in the chain, without presenting physical ID each time.

```python theme={null}
# Hotel issues credential after first verification
vc = client.credentials.issue(
    session_id=session_id,
    credential_type="IdentityCredential",
    claims=["full_name", "nationality", "document_type"],
)

# Future check-ins: verify the credential
result = client.credentials.verify_vc(jwt=guest_jwt)
if result["valid"]:
    check_in_guest(
        name=result["disclosed_claims"]["full_name"],
        nationality=result["disclosed_claims"]["nationality"],
    )
```

***

### 5. Regulatory Compliance Sharing (Multi-Jurisdiction)

A payment processor operating in the EU and UK issues separate credentials for different regulatory requirements. The user presents the appropriate credential per jurisdiction.

```javascript theme={null}
// Issue EU-compliant credential (AMLD6)
const euCred = await verilock.credentials.issue({
  session_id: session.id,
  credential_type: 'IdentityCredential',
  claims: ['full_name', 'date_of_birth', 'nationality', 'aml_clear', 'address'],
});

// Issue UK-compliant credential (FCA)
const ukCred = await verilock.credentials.issue({
  session_id: session.id,
  credential_type: 'IdentityCredential',
  claims: ['full_name', 'date_of_birth', 'nationality', 'aml_clear'],
});

// Each credential is independently verifiable and revocable
```

***

## Credential Types

| Type                 | Claims Included                    | Use Case                                  |
| -------------------- | ---------------------------------- | ----------------------------------------- |
| `IdentityCredential` | Any combination of identity claims | General KYC, onboarding, compliance       |
| `AgeCredential`      | `age_over_18`, `age_over_21` only  | Age-gated services, minimal data          |
| `AddressCredential`  | `address`, `country_of_residence`  | Proof of residence, shipping verification |

## Pricing

| Operation         | Cost                  |
| ----------------- | --------------------- |
| Issue credential  | \$0.10 per credential |
| Verify credential | Free                  |
| Revoke credential | Free                  |
| DID resolution    | Free                  |

<Warning>
  Verifiable Credentials can only be issued from sessions with `decision: approved`. Attempting to issue from a declined or pending session returns a `422` error.
</Warning>

<Tip>
  Combine Verifiable Credentials with [Zero-Knowledge Proofs](/premium-features/zero-knowledge-proofs) for maximum privacy. Issue a VC with full claims, then let users generate ZK proofs that reveal nothing except "this claim is true."
</Tip>
