Guide
SDK Examples
Production-ready code patterns for integrating Truthlock into your applications. Examples are shown in both TypeScript and Go.
End-to-End: Issue and Verify a Credential
Complete workflow from creating an issuer to minting and verifying an attestation.
full-workflow.tsTypeScript
import { TruthlockClient, Algorithm, Verdict } from '@truthlock/sdk';
const client = new TruthlockClient({
baseUrl: 'https://api.truthlocks.com',
auth: { type: 'apiKey', apiKey: 'tl_live_...', tenantId: 'your-tenant-id' },
});
// Step 1: Create issuer + register key (one-time setup)
const issuer = await client.issuers.create({
name: 'Acme University',
legal_name: 'Acme University Inc.',
display_name: 'Acme U',
});
await client.issuers.trust(issuer.id);
await client.keys.register(issuer.id, {
kid: 'ed-key-2026',
alg: Algorithm.Ed25519,
public_key_b64url: 'MCowBQYDK2VwAyEA...', // Your Ed25519 public key
});
// Step 2: Mint a degree credential (sends email to recipient)
const attestation = await client.attestations.mint({
issuer_id: issuer.id,
kid: 'ed-key-2026',
alg: Algorithm.Ed25519,
schema: 'degree',
claims: {
student_name: 'Jane Doe',
institution: 'Acme University',
degree_type: 'Bachelor of Science',
field_of_study: 'Computer Science',
graduation_date: '2026-05-15',
honors: 'Magna Cum Laude',
},
recipient_email: 'jane.doe@example.com',
});
console.log('Minted:', attestation.id, 'Log:', attestation.log_index);
// Step 3: Verify the attestation
const result = await client.verify.verifyOnline({
attestation_id: attestation.id,
});
switch (result.verdict) {
case Verdict.Valid:
console.log('Valid! Signed by:', result.issuer_name);
break;
case Verdict.Revoked:
console.log('Revoked at:', result.revoked_at);
break;
case Verdict.Invalid:
console.log('Signature invalid or tampered');
break;
}full-workflow.goGo
package main
import (
"context"
"fmt"
"log"
truthlock "github.com/truthlocks/sdk-go"
)
func main() {
client := truthlock.NewClient(truthlock.Config{
BaseURL: "https://api.truthlocks.com",
TenantID: "your-tenant-id",
APIKey: "tl_live_...",
})
ctx := context.Background()
// Step 1: Create issuer + register key
issuer, err := client.Issuers.Create(ctx, &truthlock.CreateIssuerRequest{
Name: "Acme University", LegalName: "Acme University Inc.",
})
if err != nil { log.Fatal(err) }
if _, err := client.Issuers.Trust(ctx, issuer.ID); err != nil { log.Fatal(err) }
_, err = client.Keys.Register(ctx, issuer.ID, &truthlock.RegisterKeyRequest{
KID: "ed-key-2026", Alg: truthlock.AlgEd25519,
PublicKeyB64: "MCowBQYDK2VwAyEA...",
})
if err != nil { log.Fatal(err) }
// Step 2: Mint
att, err := client.Attestations.Mint(ctx, &truthlock.MintRequest{
IssuerID: issuer.ID, KID: "ed-key-2026", Alg: truthlock.AlgEd25519,
Schema: "degree",
Claims: map[string]interface{}{
"student_name": "Jane Doe", "institution": "Acme University",
"degree_type": "Bachelor of Science", "graduation_date": "2026-05-15",
},
RecipientEmail: "jane.doe@example.com",
})
if err != nil { log.Fatal(err) }
fmt.Printf("Minted: %s (log: %d)\n", att.ID, att.LogIndex)
// Step 3: Verify
result, err := client.Verify.VerifyOnline(ctx, &truthlock.VerifyRequest{
AttestationID: att.ID,
})
if err != nil { log.Fatal(err) }
switch result.Verdict {
case truthlock.VerdictValid:
fmt.Printf("Valid! Signed by: %s\n", result.IssuerName)
case truthlock.VerdictRevoked:
fmt.Printf("Revoked at: %s\n", result.RevokedAt)
case truthlock.VerdictInvalid:
fmt.Println("Signature invalid or tampered")
}
}Batch Minting with Rate Limiting
Mint credentials for multiple recipients with concurrency control and error collection.
batch-mint.tsTypeScript
import { TruthlockClient, Algorithm, TruthlockError } from '@truthlock/sdk';
interface Recipient {
name: string;
email: string;
department: string;
}
async function batchMint(
client: TruthlockClient,
issuerId: string,
recipients: Recipient[],
) {
const CONCURRENCY = 10;
const results: { email: string; id?: string; error?: string }[] = [];
for (let i = 0; i < recipients.length; i += CONCURRENCY) {
const batch = recipients.slice(i, i + CONCURRENCY);
const settled = await Promise.allSettled(
batch.map(r =>
client.attestations.mint({
issuer_id: issuerId,
kid: 'ed-key-2026',
alg: Algorithm.Ed25519,
schema: 'employment-verification',
claims: {
employee_name: r.name,
employer: 'Acme Corp',
department: r.department,
employment_type: 'Full-time',
start_date: new Date().toISOString().split('T')[0],
},
recipient_email: r.email,
}),
),
);
for (let j = 0; j < settled.length; j++) {
const s = settled[j];
results.push({
email: batch[j].email,
id: s.status === 'fulfilled' ? s.value.id : undefined,
error: s.status === 'rejected' ? s.reason?.message : undefined,
});
}
}
const ok = results.filter(r => r.id).length;
console.log(`Minted ${ok}/${recipients.length} attestations`);
return results;
}Webhook Signature Verification
Securely verify incoming webhooks from Truthlock to ensure they haven't been tampered with.
webhook-handler.tsTypeScript
import { verifyWebhookSignature } from '@truthlock/sdk';
import express from 'express';
const app = express();
app.use(express.raw({ type: 'application/json' }));
app.post('/webhooks/truthlock', (req, res) => {
const signature = req.headers['x-truthlock-signature'] as string;
const isValid = verifyWebhookSignature(
req.body,
signature,
process.env.WEBHOOK_SECRET!,
);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body.toString());
switch (event.type) {
case 'attestation.minted':
console.log('New attestation:', event.data.id);
// Update your database, notify users, etc.
break;
case 'attestation.revoked':
console.log('Revoked:', event.data.id, 'Reason:', event.data.reason);
// Invalidate cached verification results
break;
case 'issuer.trusted':
console.log('Issuer trusted:', event.data.issuer_id);
break;
}
res.json({ received: true });
});Caching Verification Results
Cache verification results to reduce API calls. Only cache VALID results — revocations should always be checked fresh.
cached-verify.tsTypeScript
import { TruthlockClient, Verdict } from '@truthlock/sdk';
// Simple in-memory cache with TTL
const cache = new Map<string, { result: any; expires: number }>();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
async function verifyWithCache(
client: TruthlockClient,
attestationId: string,
) {
// Check cache first
const cached = cache.get(attestationId);
if (cached && cached.expires > Date.now()) {
return cached.result;
}
// Fetch fresh result
const result = await client.verify.verifyOnline({ attestation_id: attestationId });
// Only cache VALID results (revocations must be checked each time)
if (result.verdict === Verdict.Valid) {
cache.set(attestationId, {
result,
expires: Date.now() + CACHE_TTL,
});
}
return result;
}Document Attestation with SHA-256
Attest a PDF document by computing its SHA-256 hash and including it in the claims for integrity verification.
document-attest.tsTypeScript
import { createHash } from 'crypto';
import { readFile } from 'fs/promises';
import { TruthlockClient, Algorithm } from '@truthlock/sdk';
async function attestDocument(
client: TruthlockClient,
issuerId: string,
filePath: string,
) {
const fileBuffer = await readFile(filePath);
const sha256 = createHash('sha256').update(fileBuffer).digest('hex');
const fileName = filePath.split('/').pop() || 'document';
const attestation = await client.attestations.mint({
issuer_id: issuerId,
kid: 'ed-key-2026',
alg: Algorithm.Ed25519,
schema: 'custom',
content_type: 'application/pdf',
claims: {
document: {
sha256,
name: fileName,
size: fileBuffer.length,
content_type: 'application/pdf',
},
subject: 'Employment Contract',
signer: 'Jane Doe',
signed_date: new Date().toISOString().split('T')[0],
},
});
console.log('Document attested:', attestation.id);
console.log('SHA-256:', sha256);
return attestation;
}document-attest.goGo
func attestDocument(ctx context.Context, client *truthlock.Client, issuerId, filePath string) error {
data, err := os.ReadFile(filePath)
if err != nil {
return fmt.Errorf("read file: %w", err)
}
hash := sha256.Sum256(data)
hashHex := hex.EncodeToString(hash[:])
att, err := client.Attestations.Mint(ctx, &truthlock.MintRequest{
IssuerID: issuerId,
KID: "ed-key-2026",
Alg: truthlock.AlgEd25519,
Schema: "custom",
ContentType: "application/pdf",
Claims: map[string]interface{}{
"document": map[string]interface{}{
"sha256": hashHex,
"name": filepath.Base(filePath),
"size": len(data),
"content_type": "application/pdf",
},
"subject": "Employment Contract",
"signer": "Jane Doe",
"signed_date": time.Now().Format("2006-01-02"),
},
})
if err != nil {
return fmt.Errorf("mint: %w", err)
}
fmt.Printf("Document attested: %s (SHA-256: %s)\n", att.ID, hashHex)
return nil
}