Klokk Ledger
Klokk Ledger is an independent indexer and verification service. It reads Klokk Anchor proofs back off the public IOTA ledger, stores them, and serves a read-only verification API — so anyone can verify a proof without trusting the operator, and even if the ledger node later prunes old transactions. It needs no API key and no secrets; it only reads public data, and on first run backfills the full package history automatically.
Image: klokkme/ledger / ghcr.io/klokk-me/ledger (tags stable, latest). SQLite is pure-Go (no CGO); PostgreSQL optional.
docker-compose.yml
Section titled “docker-compose.yml”services: klokk-ledger: image: klokkme/ledger:stable restart: unless-stopped ports: - "127.0.0.1:8080:8080" volumes: - ledger-data:/app/data environment: ACCEPT_TERMS: "true" # accepts the terms of use: https://klokk.me/terms IOTA_NETWORK: "mainnet" IOTA_ANCHOR_PACKAGE: "0x..." # same package your anchor writes to DB_DRIVER: "sqlite" DB_DSN: "data/klokk-ledger.db" POLL_INTERVAL: "60s"
volumes: ledger-data:services: klokk-ledger: image: klokkme/ledger:stable restart: unless-stopped ports: - "127.0.0.1:8080:8080" environment: ACCEPT_TERMS: "true" # accepts the terms of use: https://klokk.me/terms IOTA_NETWORK: "mainnet" IOTA_ANCHOR_PACKAGE: "0x..." # same package your anchor writes to DB_DRIVER: "postgres" DB_DSN: "postgres://klokk:klokk@postgres:5432/klokk_ledger?sslmode=disable" POLL_INTERVAL: "60s" depends_on: postgres: condition: service_healthy
postgres: image: postgres:18-alpine restart: unless-stopped environment: POSTGRES_DB: klokk_ledger POSTGRES_USER: klokk POSTGRES_PASSWORD: klokk volumes: - postgres-data:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U klokk -d klokk_ledger"] interval: 10s timeout: 5s retries: 5
volumes: postgres-data:services: klokk-ledger: image: klokkme/ledger:stable restart: unless-stopped read_only: true tmpfs: - /tmp cap_drop: [ALL] security_opt: - no-new-privileges:true pids_limit: 200 ports: - "127.0.0.1:8080:8080" volumes: - ledger-data:/app/data environment: ACCEPT_TERMS: "true" # accepts the terms of use: https://klokk.me/terms IOTA_NETWORK: "mainnet" IOTA_ANCHOR_PACKAGE: "0x..." # same package your anchor writes to DB_DRIVER: "sqlite" DB_DSN: "data/klokk-ledger.db" POLL_INTERVAL: "60s"
volumes: ledger-data:services: klokk-ledger: image: klokkme/ledger:stable restart: unless-stopped read_only: true tmpfs: - /tmp cap_drop: [ALL] security_opt: - no-new-privileges:true pids_limit: 200 ports: - "127.0.0.1:8080:8080" environment: ACCEPT_TERMS: "true" # accepts the terms of use: https://klokk.me/terms IOTA_NETWORK: "mainnet" IOTA_ANCHOR_PACKAGE: "0x..." # same package your anchor writes to DB_DRIVER: "postgres" DB_DSN: "postgres://klokk:klokk@postgres:5432/klokk_ledger?sslmode=disable" POLL_INTERVAL: "60s" depends_on: postgres: condition: service_healthy
postgres: image: postgres:18-alpine restart: unless-stopped read_only: true tmpfs: - /var/run/postgresql - /tmp cap_drop: [ALL] cap_add: [CHOWN, DAC_OVERRIDE, FOWNER, SETGID, SETUID] security_opt: - no-new-privileges:true environment: POSTGRES_DB: klokk_ledger POSTGRES_USER: klokk POSTGRES_PASSWORD: klokk volumes: - postgres-data:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U klokk -d klokk_ledger"] interval: 10s timeout: 5s retries: 5
volumes: postgres-data:Environment variables
Section titled “Environment variables”| Variable | Default | Description |
|---|---|---|
ACCEPT_TERMS Required |
— | Set to true to accept the terms of use. Without it Klokk Ledger logs the link and exits. |
IOTA_ANCHOR_PACKAGE Required |
— | Address of the klokk_anchor Move package to index — the same one your anchor writes to. |
IOTA_NETWORK |
mainnet | mainnet, testnet or devnet (selects the default GraphQL endpoint; override with IOTA_GRAPHQL_URL). |
DB_DRIVER / DB_DSN |
sqlite / data/… | sqlite or postgres, with the matching file path or DSN. |
LISTEN_ADDR |
:8080 | Address the HTTP API listens on. |
POLL_INTERVAL |
60s | How often to poll the ledger for new proof events (e.g. 30s, 5m). |
ADDRESSES |
all | Optional comma-separated anchor sender addresses to index. Empty = every proof for the package. |
TRUSTED_PROXIES |
— | Proxies in front of your reverse proxy whose addresses are skipped when finding the client address for the rate limit: cloudflare and/or addresses or CIDRs, comma-separated. Set cloudflare behind Cloudflare. |
Verification API
Section titled “Verification API”All endpoints are served openly. GET /api/v1/verify/{tx}?root=<expected> returns the independently-indexed proof and whether it matches the expected Merkle root — the same cross-check Klokk Anchor performs via LEDGER_URLS.
| Endpoint | Description |
|---|---|
GET /api/v1/status |
Network, package, indexed count, last index time. |
GET /api/v1/verify/{tx} |
Verification verdict; pass ?root= to compare against the indexed root. |
GET /api/v1/proofs/{tx} |
A single indexed proof by transaction digest. |
GET /api/v1/proofs |
List proofs for a sender, with company_token/period filters. |
GET /api/v1/companies/{token}/proofs |
Proofs for a company token, optionally by period. |