Guide

SDK Examples

Production-ready code patterns for integrating Truthlock into your applications. Examples are shown in both TypeScript and Go.

JavaScript SDK →Go SDK →

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
}

Next Steps