Verifiable Usage Ledger

Hash-chained, optionally signed spend receipts you can re-derive and verify

Overview

A plain usage sink ships events outward, best effort and unsigned. The ledger records the same completed calls in a form you can verify later. Each event is hash-chained to the previous one, so editing any past record breaks every link after it. With a signing seed configured, each entry is Ed25519-signed, so the record is attributable to the proxy that wrote it. All of this ships in the Apache-2.0 binary.

Configuration

Configure a ledger usage sink on an ai_proxy origin:

action:
  type: ai_proxy
  providers:
    - name: openai
      provider_type: openai
      api_key: ${OPENAI_API_KEY}
      default_model: gpt-4o-mini
      models: [gpt-4o-mini]
  usage_sinks:
    - type: ledger
      path: /var/lib/sbproxy/usage-ledger.jsonl
      # Optional 32-byte Ed25519 seed as hex. Resolve from a secret manager.
      signing_seed_hex: ${LEDGER_SIGNING_SEED_HEX}

How it works

  • Chain. entry_hash = SHA-256(prev_hash || seq || recorded_at || event). Changing any field of any past entry changes its hash, which no longer matches the next entry's prev_hash.
  • Signatures. With a seed set, each entry's digest is Ed25519-signed; a receipt verifies against the published public key and a forged entry does not.
  • Exactly-once. The file is replayed on open, so a retried delivery of the same request_id collapses to a single entry.
  • Durability. The ledger file is its own write-ahead log; each entry is written and flushed before the append returns, off the request latency path, so a burst never drops an event.

Verifying

sbproxy ai ledger verify /var/lib/sbproxy/usage-ledger.jsonl \
  --signing-seed-hex "$LEDGER_SIGNING_SEED_HEX"

It prints the entry count and exits 0 on success, or names the first failing sequence number and exits 1, so it slots into a cron check or CI gate. Edit a cost in the file and re-run to watch it fail at the mutated sequence.