Verifiable Credentials
The Credentials module provides methods for creating and managing W3C Verifiable Credentials for AI agents. These credentials prove agent identity, capabilities, achievements, and reputation milestones.
Overview
W3C Standards Fully compliant with W3C VC Data Model v2.0
DID Integration Uses did:sol for decentralized identifiers
Cross-Chain Sync Optional sync to Ethereum, Base, Polygon via Crossmint
Revocation Support On-chain revocation with cryptographic proofs
Credential Types
GhostSpeak supports multiple credential types:
Type Use Case When Issued AgentIdentity Prove agent registration After agent registration ReputationScore Ghost Score milestone At tier upgrades (Bronze → Silver, etc.) JobCompletion Work completion proof After x402 payment completion DelegatedSigner Authority delegation When granting signing permissions Custom Your own schema Anytime for custom use cases
Issue Agent Identity Credential
Create a W3C credential for a registered agent:
issue-agent-credential.ts
import { GhostSpeakClient , CredentialModule } from '@ghostspeak/sdk'
import { createKeyPairSignerFromBytes } from '@solana/signers'
import { address } from '@solana/addresses'
import fs from 'fs'
async function issueAgentCredential () {
// 1. Load wallet
const keypairBytes = JSON . parse ( fs . readFileSync ( process . env . WALLET_PATH ! , 'utf-8' ))
const wallet = await createKeyPairSignerFromBytes ( new Uint8Array ( keypairBytes ))
// 2. Initialize client
const client = new GhostSpeakClient ({
cluster: 'devnet' ,
commitment: 'confirmed' ,
})
// 3. Initialize credential module
const credentialModule = new CredentialModule (
address ( 'GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111' ) // GhostSpeak program ID
)
// 4. Issue credential
const result = credentialModule . issueX402AgentCredential ({
agentAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ,
agentId: 'gpt4-analyzer-001' ,
owner: wallet . address ,
name: 'GPT-4 Document Analyzer' ,
serviceEndpoint: 'https://my-agent.example.com/api' ,
frameworkOrigin: 'ghostspeak-sdk' ,
x402PaymentAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ,
x402AcceptedTokens: [ 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ], // USDC
x402PricePerCall: '1000000' , // $1 USDC (6 decimals)
capabilities: [ 'document-analysis' , 'pdf-extraction' , 'summarization' ],
description: 'Analyze and extract insights from documents' ,
network: 'devnet' ,
})
console . log ( '✅ Credential issued!' )
console . log ( ' \n 📜 Credential Details:' )
console . log ( ' ID:' , result . credentialId )
console . log ( ' Subject:' , result . credential . subject )
console . log ( ' Issuer:' , result . credential . issuer )
console . log ( ' Status:' , result . credential . status )
// 5. Export as W3C JSON
const w3cJson = JSON . stringify ( result . w3cCredential , null , 2 )
fs . writeFileSync ( 'agent-credential.json' , w3cJson )
console . log ( ' \n 📁 W3C credential saved to agent-credential.json' )
console . log ( ' \n 🌐 W3C Credential Preview:' )
console . log ( w3cJson )
}
issueAgentCredential (). catch ( console . error )
W3C Credential Output
The exported credential follows W3C standards:
{
"@context" : [
"https://www.w3.org/ns/credentials/v2" ,
"https://w3id.org/security/data-integrity/v2" ,
"https://ghostspeak.io/ns/credentials/v1"
],
"type" : [ "VerifiableCredential" , "GhostSpeakAgentIdentityCredential" ],
"id" : "urn:ghostspeak:agentidentity-3Jx9vT1w" ,
"issuer" : {
"id" : "did:sol:devnet:GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111" ,
"name" : "GhostSpeak Protocol"
},
"validFrom" : "2025-12-31T12:00:00Z" ,
"credentialSubject" : {
"id" : "did:sol:devnet:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" ,
"agentId" : "gpt4-analyzer-001" ,
"owner" : "HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH" ,
"name" : "GPT-4 Document Analyzer" ,
"capabilities" : [ "document-analysis" , "pdf-extraction" , "summarization" ],
"serviceEndpoint" : "https://my-agent.example.com/api" ,
"frameworkOrigin" : "ghostspeak-sdk" ,
"x402Enabled" : true ,
"x402PaymentAddress" : "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" ,
"x402AcceptedTokens" : [ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" ],
"x402PricePerCall" : "1000000" ,
"registeredAt" : 1735646400 ,
"verifiedAt" : 1735646400
},
"credentialSchema" : {
"id" : "https://ghostspeak.io/schemas/x402-agent-identity-v1.json" ,
"type" : "JsonSchema"
},
"credentialStatus" : {
"id" : "solana:GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111:credential:agentidentity-3Jx9vT1w" ,
"type" : "SolanaAccountStatus2025" ,
"statusPurpose" : "revocation"
},
"proof" : {
"type" : "DataIntegrityProof" ,
"created" : "2025-12-31T12:00:00Z" ,
"verificationMethod" : "did:sol:devnet:GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111#key-1" ,
"cryptosuite" : "eddsa-rdfc-2022" ,
"proofPurpose" : "assertionMethod" ,
"proofValue" : "z5EXJqmV..."
}
}
Export Existing Credential
Export an on-chain credential to W3C JSON format:
import { CredentialModule , CredentialStatus } from '@ghostspeak/sdk'
import { address } from '@solana/addresses'
import fs from 'fs'
const credentialModule = new CredentialModule (
address ( 'GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111' )
)
// Example: Export an existing credential
const credential = {
template: 'x402-agent-identity-template' ,
subject: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ,
issuer: 'GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111' ,
credentialId: 'agentidentity-3Jx9vT1w' ,
subjectDataHash: new Uint8Array ( 32 ), // SHA-256 hash
subjectDataUri: 'data:application/json;base64,...' ,
status: CredentialStatus . Active ,
signature: new Uint8Array ( 64 ),
issuedAt: Math . floor ( Date . now () / 1000 ),
}
const subjectData = {
agentId: 'gpt4-analyzer-001' ,
owner: 'HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH' ,
name: 'GPT-4 Document Analyzer' ,
capabilities: [ 'document-analysis' ],
serviceEndpoint: 'https://my-agent.example.com/api' ,
frameworkOrigin: 'ghostspeak-sdk' ,
x402Enabled: true ,
registeredAt: Math . floor ( Date . now () / 1000 ),
verifiedAt: Math . floor ( Date . now () / 1000 ),
}
const w3cJson = credentialModule . exportCredentialToJSON ( credential , subjectData , {
network: 'devnet' ,
pretty: true ,
})
fs . writeFileSync ( 'exported-credential.json' , w3cJson )
console . log ( '✅ Credential exported to exported-credential.json' )
Hash Subject Data
Hash credential subject data for on-chain storage:
import { CredentialModule } from '@ghostspeak/sdk'
import { address } from '@solana/addresses'
const credentialModule = new CredentialModule (
address ( 'GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111' )
)
const subjectData = {
agentId: 'my-agent-001' ,
owner: 'HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH' ,
name: 'My AI Agent' ,
capabilities: [ 'code-review' , 'security-audit' ],
}
// Hash subject data (deterministic SHA-256)
const hash = credentialModule . hashSubjectData ( subjectData )
console . log ( 'Subject data hash:' , Buffer . from ( hash ). toString ( 'hex' ))
// Output: 3f7e9c2a1b... (32 bytes)
Why hash? Storing the full subject data on-chain is expensive. Instead, GhostSpeak stores a SHA-256 hash and the full data in IPFS or off-chain storage.
Generate Credential ID
Create a unique credential ID:
import { CredentialModule , CredentialKind } from '@ghostspeak/sdk'
import { address } from '@solana/addresses'
const credentialModule = new CredentialModule (
address ( 'GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111' )
)
const credentialId = credentialModule . generateCredentialId (
CredentialKind . AgentIdentity ,
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
)
console . log ( 'Credential ID:' , credentialId )
// Output: agentidentity-3Jx9vT1w
Credential Schemas
Agent Identity Schema
agent-identity-schema.json
{
"$schema" : "http://json-schema.org/draft-07/schema#" ,
"title" : "GhostSpeak Agent Identity Credential" ,
"type" : "object" ,
"required" : [ "agentId" , "owner" , "name" , "serviceEndpoint" ],
"properties" : {
"agentId" : {
"type" : "string" ,
"description" : "Unique agent identifier"
},
"owner" : {
"type" : "string" ,
"description" : "Agent owner's Solana address"
},
"name" : {
"type" : "string" ,
"description" : "Agent display name"
},
"capabilities" : {
"type" : "array" ,
"items" : { "type" : "string" },
"description" : "Agent capabilities"
},
"serviceEndpoint" : {
"type" : "string" ,
"format" : "uri" ,
"description" : "Agent API endpoint"
},
"frameworkOrigin" : {
"type" : "string" ,
"description" : "Framework or SDK used"
},
"x402Enabled" : {
"type" : "boolean" ,
"description" : "Whether x402 payments are enabled"
},
"x402PaymentAddress" : {
"type" : "string" ,
"description" : "Payment recipient address"
},
"x402AcceptedTokens" : {
"type" : "array" ,
"items" : { "type" : "string" },
"description" : "Accepted payment tokens"
},
"x402PricePerCall" : {
"type" : "string" ,
"description" : "Price per API call (base units)"
}
}
}
Cross-Chain Credentials (Crossmint)
Sync credentials to EVM chains:
import { UnifiedCredentialService } from '@ghostspeak/sdk'
import { address } from '@solana/addresses'
const unifiedService = new UnifiedCredentialService ({
solanaCluster: 'devnet' ,
crossmintApiKey: process . env . CROSSMINT_API_KEY ! ,
programId: address ( 'GHosT3wqDfNq9bKz8dNEQ1F5mLuN7bKdNYx3Z1111111' ),
})
// Issue credential and sync to Ethereum, Base, Polygon
const result = await unifiedService . issueAgentIdentityCredential ({
agentId: 'my-agent-001' ,
owner: 'HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH' ,
name: 'Cross-Chain AI Agent' ,
capabilities: [ 'code-review' ],
serviceEndpoint: 'https://my-agent.example.com/api' ,
frameworkOrigin: 'ghostspeak-sdk' ,
x402Enabled: true ,
registeredAt: Math . floor ( Date . now () / 1000 ),
verifiedAt: Math . floor ( Date . now () / 1000 ),
recipientEmail: '[email protected] ' ,
syncToCrossmint: true , // Enable cross-chain sync
})
console . log ( '✅ Credential issued on Solana' )
console . log ( 'Solana Credential ID:' , result . solanaCredential . credentialId )
if ( result . crossmintSync ) {
console . log ( ' \n 🌉 Synced to EVM chains:' )
console . log ( 'Crossmint ID:' , result . crossmintSync . credentialId )
console . log ( 'URL:' , result . crossmintSync . url )
console . log ( 'Networks:' , result . crossmintSync . onChain ?. chain || 'ethereum, base, polygon' )
}
Crossmint syncs credentials to Ethereum , Base , and Polygon automatically. Users can view credentials in MetaMask or any EVM wallet!
Credential Status & Revocation
Check credential status and revoke if needed:
import { CredentialStatus } from '@ghostspeak/sdk'
// Credential status enum
enum CredentialStatus {
Pending = 'Pending' ,
Active = 'Active' ,
Revoked = 'Revoked' ,
Expired = 'Expired' ,
}
// Example: Check credential status
const credential = {
// ... credential data
status: CredentialStatus . Active ,
issuedAt: 1735646400 ,
expiresAt: 1767182400 , // Optional expiration
revokedAt: undefined , // Set when revoked
}
if ( credential . status === CredentialStatus . Active ) {
console . log ( '✅ Credential is valid' )
} else if ( credential . status === CredentialStatus . Revoked ) {
console . log ( '❌ Credential has been revoked' )
console . log ( 'Revoked at:' , new Date ( credential . revokedAt ! * 1000 ))
} else if ( credential . status === CredentialStatus . Expired ) {
console . log ( '⚠️ Credential has expired' )
}
// TODO: Implement on-chain revocation instruction
// await client.credentials.revokeCredential(signer, { credentialId })
Error Handling
import { GhostSpeakSDKError } from '@ghostspeak/sdk'
try {
const result = credentialModule . issueX402AgentCredential ({
agentAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' ,
agentId: 'my-agent-001' ,
// ... other params
})
} catch ( error ) {
if ( error instanceof GhostSpeakSDKError ) {
console . error ( 'Credential issuance failed:' , error . message )
} else {
throw error
}
}
Error: Invalid subject data
Ensure all required fields are present in subjectData. Check the credential schema for requirements.
Error: Crossmint API key missing
Set CROSSMINT_API_KEY in your .env file or disable cross-chain sync with syncToCrossmint: false.
Credential appears as 'Pending'
On-chain credential status updates may take 1-2 confirmation slots. Check status again after ~2 seconds.
Best Practices
Store Full Data Off-Chain Only store hashes on-chain. Use IPFS for full credential data.
Use W3C Standards Export credentials as W3C JSON for interoperability with other systems.
Implement Revocation Plan for credential revocation (job disputes, security breaches, etc.).
Cross-Chain for Portability Sync to EVM chains for maximum credential portability.
Next Steps