VC Service Developer Guide

This guide shows you how to implement a complete verifiable credential payment flow using the VC service endpoints.

Quick Start

Want to get up and running fast? Follow this 5-minute setup:

  1. Enroll a user → Get their DID and keys
  2. Issue a credential → Authorize payments
  3. Sign a presentation → User consents to payment
  4. Make payment → Submit signed presentation
  5. Verify → Bank validates everything

Prerequisites

  • Base URL: https://localhost:4901/vc/v1
  • Content-Type: application/json
  • Authentication: Required for all endpoints (partner API key)

VC Enrollment

Enroll a User

Purpose: Create a user account with cryptographic keys for signing payments.

Endpoint: POST /enroll

Request:

curl -X POST https://localhost:4901/vc/v1/enroll \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
  "entityType": "user",
  "name": "John Doe", 
  "email": "john@example.com",
  "metadata": {
    "department": "engineering"
  }
}'

Response:

{
  "success": true,
  "data": {
    "userDid": "did:key:z6Mk2b84e6986130ed411d0e386722b0ebb5",
    "publicKey": "base64_encoded_32_byte_public_key",
    "verificationMethod": "did:key:z6Mk2b84e6986130ed411d0e386722b0ebb5#key-1"
  }
}

Save these values - you'll need them for the next steps:

  • userDid → Use in credential issuance
  • publicKey → Used by system to verify signatures (you don't need to handle this)
  • verificationMethod → Reference for signature verification
Issue a Credential

Purpose: Create a payment authorization credential for the user.

Endpoint: POST /issue-credential

Request:

curl -X POST https://localhost:4901/vc/v1/issue-credential \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "userDid": "did:key:z6Mk2b84e6986130ed411d0e386722b0ebb5",
    "agentDid": "did:key:z6Mk7b4bcd19d9dee0182ae9e9ef05c9779c",
    "amount": 250,
    "scope": "restaurant",
    "purpose": "Dinner payment",
    "expirationMinutes": 30
  }'

Response:

{
  "success": true,
  "data": {
    "credential": {
      "id": "https://localhost:4901/vc/v1/credentials/uuid-here",
      "type": ["VerifiableCredential", "PaymentConsentCredential"],
      "issuer": "did:key:platform-issuer-did",
      "credentialSubject": {
        "id": "did:key:z6Mk2b84e6986130ed411d0e386722b0ebb5",
        "authorizedAgent": "did:key:z6Mk7b4bcd19d9dee0182ae9e9ef05c9779c",
        "paymentLimit": 250,
        "currency": "USD",
        "scope": "restaurant",
        "purpose": "Dinner payment"
      }
    }
  }
}

What happened: The platform created and signed a credential authorizing the user to make payments up to $250 at restaurants.

Sign a Presentation

Purpose: Get the user's cryptographic consent for the payment.

Endpoint: POST /sign-presentation

Request:

curl -X POST https://localhost:4901/vc/v1/sign-presentation \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "userDid": "did:key:z6Mk2b84e6986130ed411d0e386722b0ebb5",
    "presentation": {
      "context": ["https://www.w3.org/2018/credentials/v1"],
      "type": ["VerifiablePresentation"],
      "verifiableCredential": [
        {
          "id": "https://localhost:4901/vc/v1/credentials/uuid-here",
          "type": ["VerifiableCredential", "PaymentConsentCredential"],
          "issuer": "did:key:platform-issuer-did",
          "credentialSubject": {
            "id": "did:key:z6Mk2b84e6986130ed411d0e386722b0ebb5",
            "authorizedAgent": "did:key:z6Mk7b4bcd19d9dee0182ae9e9ef05c9779c",
            "paymentLimit": 250,
            "currency": "USD",
            "scope": "restaurant",
            "purpose": "Dinner payment"
          }
        }
      ]
    }
  }'

Response:

{
  "success": true,
  "data": {
    "signedPresentation": {
      "context": ["https://www.w3.org/2018/credentials/v1"],
      "type": ["VerifiablePresentation"],
      "verifiableCredential": [...],
      "proof": {
        "type": "Ed25519Signature2020",
        "verificationMethod": "did:key:z6Mk2b84e6986130ed411d0e386722b0ebb5#key-1",
        "proofValue": "user_signature_using_enrollment_private_key"
      }
    }
  }
}

What happened: The system signed the presentation using the user's enrollment private key (stored securely on the server).

Make Payment

Purpose: Process the payment using the signed presentation.

Endpoint: POST /pay

Request:

curl -X POST https://localhost:4901/vc/v1/pay \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "amount": 250,
    "recipient": "did:key:restaurant-recipient-did",
    "currency": "USD",
    "description": "Dinner payment",
    "presentation": {
      "context": ["https://www.w3.org/2018/credentials/v1"],
      "type": ["VerifiablePresentation"],
      "verifiableCredential": [...],
      "proof": {
        "type": "Ed25519Signature2020",
        "verificationMethod": "did:key:z6Mk2b84e6986130ed411d0e386722b0ebb5#key-1",
        "proofValue": "user_signature_using_enrollment_private_key"
      }
    }
  }'

Response:

{
  "success": true,
  "data": {
    "paymentId": "payment-uuid",
    "transactionId": "bank-transaction-id",
    "amount": 250,
    "status": "completed",
    "message": "Payment processed successfully"
  }
}

What happened: The system automatically verified the user's signature using their enrollment public key, then processed the payment.


Complete Working Example

Here's a complete flow you can copy-paste and run:

1. Enroll User

curl -X POST https://localhost:4901/vc/v1/enroll \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "entityType": "user",
    "name": "Test User",
    "email": "test@example.com"
  }'

2. Issue Credential

curl -X POST https://localhost:4901/vc/v1/issue-credential \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "userDid": "PASTE_USER_DID_FROM_STEP_1",
    "agentDid": "did:key:z6Mk7b4bcd19d9dee0182ae9e9ef05c9779c",
    "amount": 100,
    "scope": "test",
    "purpose": "Test payment",
    "expirationMinutes": 60
  }'

3. Sign Presentation

curl -X POST https://localhost:4901/vc/v1/sign-presentation \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "userDid": "PASTE_USER_DID_FROM_STEP_1",
    "presentation": {
      "context": ["https://www.w3.org/2018/credentials/v1"],
      "type": ["VerifiablePresentation"],
      "verifiableCredential": [
        {
          "id": "PASTE_CREDENTIAL_ID_FROM_STEP_2",
          "type": ["VerifiableCredential", "PaymentConsentCredential"],
          "issuer": "PASTE_ISSUER_DID_FROM_STEP_2",
          "credentialSubject": {
            "id": "PASTE_USER_DID_FROM_STEP_1",
            "authorizedAgent": "did:key:z6Mk7b4bcd19d9dee0182ae9e9ef05c9779c",
            "paymentLimit": 100,
            "currency": "USD",
            "scope": "test",
            "purpose": "Test payment"
          }
        }
      ]
    }
  }'

4. Make Payment

curl -X POST https://localhost:4901/vc/v1/pay \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "amount": 100,
    "recipient": "did:key:recipient-did",
    "currency": "USD",
    "description": "Test payment",
    "presentation": "PASTE_SIGNED_PRESENTATION_FROM_STEP_3"
  }'

Common Errors & Solutions

401 Unauthorized

Problem: Invalid signature

Solution: Make sure you're using the signed presentation from /sign-presentation

404 Not Found

Problem: User DID not enrolled

Solution: Call /enroll first to create the user

400 Bad Request

Problem: Invalid request format

Solution: Check JSON syntax and required fields


That's it! You now have a complete, working verifiable credential payment system. The cryptographic complexity is handled automatically - you just make HTTPs requests and get secure payments!

Was this page helpful?