Cardless ID Credential Schema
Version 1.0.0
Cardless ID uses W3C Verifiable Credentials with a composite identity hash for sybil-resistant duplicate detection. Each credential includes a cryptographic proof (Ed25519 signature) that prevents forgery - only the legitimate issuer can create valid credentials. The credential also includes a W3C-standard 'evidence' property with detailed verification metadata (fraud detection, OCR confidence, biometric matching) for risk assessment. The mobile wallet stores both the credential (with hash and evidence) and the original unhashed data locally for user access.
Schema Overview
W3C Verifiable Credential Structure
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2",
"https://cardlessid.org/credentials/v1"
],
"id": "urn:uuid:8b330349-f027-46e3-ae16-8a032903ce9b",
"type": [
"VerifiableCredential",
"BirthDateCredential"
],
"issuer": {
"id": "did:algo:ISSUER_WALLET_ADDRESS_HERE"
},
"issuanceDate": "2025-09-30T17:00:00Z",
"credentialSubject": {
"id": "did:algo:USER_WALLET_ADDRESS_HERE",
"cardlessid:compositeHash": "d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"
},
"evidence": [
{
"type": [
"DocumentVerification"
],
"verifier": "did:algo:ISSUER_WALLET_ADDRESS_HERE",
"evidenceDocument": "DriversLicense",
"subjectPresence": "Digital",
"documentPresence": "Digital",
"verificationMethod": "aws-textract",
"fraudDetection": {
"performed": true,
"passed": true,
"method": "google-document-ai",
"provider": "Google Document AI",
"signals": []
},
"documentAnalysis": {
"provider": "aws-textract",
"bothSidesAnalyzed": true,
"lowConfidenceFields": [],
"qualityLevel": "high"
},
"biometricVerification": {
"performed": true,
"faceMatch": {
"confidence": 0.95,
"provider": "AWS Rekognition"
},
"liveness": {
"confidence": 0.92,
"provider": "AWS Rekognition"
}
}
}
],
"credentialStatus": {
"id": "did:algo:app:REGISTRY_APP_ID",
"type": "AlgorandIssuerRegistry2025"
},
"service": [
{
"id": "#system-attestation",
"type": "ZkProofSystemVersion",
"serviceEndpoint": "https://github.com/REPO_OWNER/REPO_SLUG/commit/COMMIT_HASH_HERE"
}
],
"proof": {
"type": "Ed25519Signature2020",
"created": "2025-09-30T17:00:00Z",
"verificationMethod": "did:algo:ISSUER_WALLET_ADDRESS_HERE#key-1",
"proofPurpose": "assertionMethod",
"proofValue": "z3eF7d8...base64EncodedSignature"
}
}Field Definitions
cardlessid:compositeHash
Type: http://www.w3.org/2001/XMLSchema#string
Description: SHA-256 hash of firstName|middleName|lastName|birthDate (ISO 8601 format)
Purpose: Sybil-resistant duplicate detection - prevents the same person from creating multiple credentials
Example: d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35
service (Optional - System Attestation)
Type: Array<ServiceEndpoint>
Description: Optional array of service endpoints for system attestation and metadata
Purpose: Links to the exact git commit of code that issued the credential for auditability and transparency
Example: {
"id": "#system-attestation",
"type": "ZkProofSystemVersion",
"serviceEndpoint": "https://github.com/owner/repo/commit/abc123def456"
}
Note: Only included when git information is available at build time. Development builds will not include this field.
evidence (W3C Standard)
Type: Array<DocumentVerification>
Description: W3C standard evidence property containing verification metadata and confidence metrics
Purpose: Provides detailed information about the verification process including fraud detection, OCR confidence, and biometric matching
Structure:
fraudDetection:
- • performed: boolean - Whether fraud detection was performed
- • passed: boolean - Overall fraud check result
- • method: string - Fraud detection method (e.g., 'google-document-ai')
- • provider: string - Human-readable provider name
- • signals: array - Fraud signals detected (empty if clean)
documentAnalysis:
- • provider: string - OCR provider (e.g., 'aws-textract')
- • bothSidesAnalyzed: boolean - Whether front and back were processed
- • lowConfidenceFields: string[] - Fields with low OCR confidence
- • qualityLevel: 'high' | 'medium' | 'low' - Overall verification quality
biometricVerification:
- • performed: boolean - Whether biometric verification was performed
- • faceMatch: { confidence: number, provider: string } - Face comparison confidence (0-1)
- • liveness: { confidence: number, provider: string } - Liveness detection confidence (0-1)
Usage Guidelines
Verification
Verifiers should validate the proof signature against the issuer's public key (derived from the Algorand address in the issuer DID). The signature is created from the credential WITHOUT the proof field. Use algosdk.verifyBytes() with the issuer's public key to verify authenticity. The compositeHash prevents duplicate credentials from the same person. The evidence property contains verification quality metrics for risk-based trust decisions.
Wallet Integration
Mobile wallets receive both the credential (with compositeHash, evidence, and cryptographic proof) and the original unhashed personal data (for local storage and user access). The evidence property includes fraud detection results, OCR confidence levels, and biometric matching scores that can be used for risk assessment.
Extension
Additional claims can be added using custom namespaces while preserving core cardlessid: fields. The W3C-standard evidence property is extensible and can include additional verification methods.
Cryptographic Proof
The proof.proofValue contains a base64-encoded Ed25519 signature. To verify: 1) Remove the proof field from credential, 2) Convert to canonical JSON, 3) Verify signature using issuer's public key from Algorand. Note: The evidence property is included in the signed data, ensuring verification metadata cannot be tampered with.
Evidence & Verification Quality
The evidence array follows W3C VC Data Model standards and includes DocumentVerification evidence with fraud detection (Google Document AI), document analysis (AWS Textract OCR confidence), and biometric verification (AWS Rekognition face match and liveness). Quality levels (high/medium/low) help relying parties make risk-based acceptance decisions. High quality requires: fraud check passed, both ID sides processed, no low-confidence fields, and strong biometric scores.
System Attestation (service field)
The optional service array provides system attestation by linking to the exact git commit that issued the credential. This enables verifiers to audit the issuing code for security review and demonstrates the issuer's commitment to transparency. The serviceEndpoint contains a GitHub URL (e.g., https://github.com/owner/repo/commit/abc123) pointing to the exact code version. This field is only included when git information is available at build time and will be omitted in development builds.
API Endpoints
Schema Endpoint
URL: GET /api/credentials/schema
Returns: Complete schema definition with field descriptions and usage notes
CORS: Enabled for third-party access
Security Considerations
- • Signature Verification: Always verify the Ed25519 signature before trusting any credential
- • Issuer Validation: Verify the issuer DID corresponds to a known, trusted Algorand address
- • Composite Hash: Use the composite hash to prevent duplicate credentials from the same person
- • Evidence Verification: Check the evidence property for verification quality - use qualityLevel (high/medium/low) for risk-based acceptance decisions
- • Fraud Detection: Review fraudDetection.passed and fraudDetection.signals for potential fraud indicators
- • Biometric Confidence: For high-security scenarios, require faceMatchConfidence and livenessConfidence above threshold (e.g., 0.85)
- • System Attestation: If the service field is present, you can audit the exact code version that issued the credential by following the GitHub commit URL
- • Expiration: Consider implementing expiration policies for credentials
- • Revocation: Check revocation status if implementing a revocation registry
Example Implementation
JavaScript Verification Example
// Example verification function
async function verifyCardlessCredential(credential) {
// 1. Extract issuer public key from DID
const issuerAddress = credential.issuer.id.replace('did:algo:', '');
const publicKey = algosdk.decodeAddress(issuerAddress).publicKey;
// 2. Remove proof field for signature verification
const { proof, ...credentialWithoutProof } = credential;
// 3. Create canonical JSON
const credentialBytes = new TextEncoder().encode(
JSON.stringify(credentialWithoutProof)
);
// 4. Verify signature
const signature = new Uint8Array(
Buffer.from(proof.proofValue, 'base64')
);
const isValid = algosdk.verifyBytes(
credentialBytes,
signature,
publicKey
);
return isValid;
}Last updated: 11/5/2025 | Schema Version: 1.0.0
Support
- 📧 Email: me@djscruggs.com
- 🐛 Issues: GitHub Issues
- 💬 Community: Discord (coming soon)
