API Reference

All requests are JSON over HTTPS. Authenticate with X-API-KEY: zada_….

POST/api/v1/issueX-API-KEY (scope: issue)

Sign a payload through the full ZADA pipeline and (optionally) render an A4 PDF.

Request
{
  "issuer_id": "did:key:z6Mk…",   // the HOT SD-JWT issuer DID (not the cold DID)
  "subject": "patient-1234",
  "claims": { "type": "HealthCertificate", "result": "negative" },
  "generate_pdf": true
}
Response
{
  "zada": "ZADA:6BFOXN%TS3DH...",
  "pdf_url": "https://.../credentials/<tenant>/<id>.pdf",
  "issuer": { "id": "...", "did": "did:key:zCold…", "linked_hot_did": "did:key:zHot…", "name": "...", "kid": "...", "x5t_s256": "..." },
  "issued_at": "2026-04-20T12:00:00Z"
}
POST/api/v1/verifyX-API-KEY (scope: verify)

Decode and verify a ZADA string against the cached trust registry.

Request
{ "zada": "ZADA:6BFOXN%..." }
Response
{
  "valid": true,
  "issuer": { "name": "...", "kid": "...", "x5t_s256": "...", "linked_hot_did": "did:key:zHot…", "trust_source": "registry_cache" },
  "algorithm": "EdDSA",
  "claims": { ... }
}
GET/api/v1/registry/syncPublic

Returns a CBOR-encoded, COSE_Sign1-signed bundle of trusted issuers for offline verification.

Request
Response
Binary application/cose payload (download as zada-trust-bundle.cose)
POST/api/v1/registry/refreshX-API-KEY (scope: issue)

Pull latest entries from the configured ZADA mirror (env MOCK_ZADA_URL) into trust_registry_cache. Seeds 2 mock issuers if no URL is set.

Request
Response
{ "refreshed": 2, "source": "mock-seed" }

Pipeline format

Claims
  └─ CBOR encode
      └─ COSE_Sign1 (alg: EdDSA, kid, x5t#S256)
          └─ ZLIB deflate
              └─ Base45 encode
                  └─ Prepend "ZADA:"
                      └─ QR code (Level H)

Before you start

  1. Create an API key in Dashboard → API Keys (the secret is shown once).
  2. Create a cold issuer in Dashboard → Issuers and link it to your existing hot SD-JWT issuer's did:key:….

Cold credentials are signed by a separate cold-system key, but you address issuers by their hot SD-JWT DID. The cold system handles the mapping — wallets only need to know one DID per issuer.

Issue a credential

curl -X POST https://coldcred.zada.solutions/api/v1/issue \
  -H "X-API-KEY: zada_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "issuer_id": "did:key:zDnaepLCSitGvvprHJZFjaC61aFUmHrKcGLGEkBrf1PAceUna",
    "subject": "patient-1234",
    "claims": { "type": "HealthCertificate", "result": "negative" },
    "generate_pdf": true
  }'

The issuer_id is the hot SD-JWT issuer DID — exactly the one your wallet already has. The iss claim inside the signed cold credential is the cold signing DID (so verifiers can resolve the public key from the credential alone). Use linked_hot_did in the verify response to display the familiar hot identity to users.

Verify a credential

curl -X POST https://coldcred.zada.solutions/api/v1/verify \
  -H "X-API-KEY: zada_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "zada": "ZADA:6BFOXN%TS3DH..." }'

Download offline trust bundle

Public — no authentication required.

curl https://coldcred.zada.solutions/api/v1/registry/sync \
  -o zada-trust-bundle.cose

Refresh trust registry

curl -X POST https://coldcred.zada.solutions/api/v1/registry/refresh \
  -H "X-API-KEY: zada_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxx"