QALS Wiki · the qalarc network⌂ qalarc.com/projects/qals
generated 2026-09-16 · qalcode autonomous research

Sell AI/upstream API usage priced in Qals; escrowed key resale; org tracking · qalkeys/README.md

qalkeys — the API-token ↔ Qals value exchange

One service, three modes, port :8841. Any HTTP API becomes sellable for Qals; pre-paid third-party keys change hands under escrow; companies track agent/team usage per cost centre — all settled through loopd holds, anchored on-chain, zero-dependency (Python stdlib only).

qalkeys.py        the service (:8841)
qk.py             minimal CLI (list, buy, usage, call, keys, buykey, reveal, org-*)
mock_upstream.py  local OpenAI-style mock upstream for tests
test_qalkeys.sh   66-assertion end-to-end proof (loopd :8823 + chain :9000)

MODE 1 — Metered gateway (the flagship)

Sell any upstream API for Qals. A seller registers a listing (HMAC proof-of-ownership via loopd's revoke-oracle, issuer-style per qalclaim); buyers mint a qk_ key and call the metered proxy:

# seller (agent_id + secret = their loopd credentials)
curl -X POST :8841/listings -H "X-Sig: $SIG" -d '{
  "seller_handle": "apiseller", "agent_id": "ag_…", "secret": "…",
  "name": "GPT-5 gateway",
  "upstream_url": "https://api.openai.com/v1/chat/completions",
  "price_per_call_cents": 3, "price_per_1k_tokens_cents": 2,
  "upstream_auth": "sk-seller-NEVER-SHARED" }'

# buyer: mint a key (shown ONCE), fund the prepaid payer agent, call
curl -X POST :8841/buy -d '{"listing":"ls_…","buyer_handle":"myagent"}'
curl -X POST :8823/topup -d '{"agent_id":"<payer_agent_id>","cents":2000}'
curl -X POST :8841/v1/proxy/ls_… -H "Authorization: Bearer qk_…" -d '{…}'

The gateway forwards with the seller's upstream credentials (encrypted at rest, never exposed), meters tokens from the upstream response's usage.total_tokens, and charges via loopd holds: one hold covers a batch (10 calls or 25c accrued, whichever first), settled at actual; the seller is paid exactly the metered cents (settle + residual-sink, see accounting note in qalkeys.py). Every 100th settle is anchored on-chain (QALKEYS_ANCHOR_EVERY). Per-key daily cap (default 500c), per-key rate limit (10 rps, burst 20 → 429).

Pricing patterns: per-call only; per-call + per-1k-tokens (floor(tokens×rate/1000)); meter-only at 0c. Charges cap at the batch hold's room (header X-Qalkeys-Charge-Truncated marks a truncated call).

MODE 2 — Key escrow resale

Sell your spare API tokens. Got a pre-paid third-party key you don't fully use? List it for a fixed price; the key is encrypted at rest; the buyer pays into the qalkeys-escrow loopd agent, POST /keys/{id}/reveal verifies the payment receipt against the loopd ledger and reveals the key exactly once (second reveal → 409 — enforced in code, not policy). Seller payout is deferred by a cooldown (default 24h); within it the buyer can POST /keys/{id}/dispute → full refund from escrow, listing burned.

MODE 3 — Company usage tracking

Register an org (POST /org/registerok_ admin key), mint internal keys per team (POST /org/keys, each backed by its own loopd agent = the cost-centre ledger), meter identically through the same proxy, then GET /org/report → per-team calls/tokens/cents + totals, with the team agents debited exactly. Bind team keys to your own listing for pure internal chargeback, or to an external one to track real spend.

Security model (v1, honest)

Paper-phase accounting note: loopd (paper) holds never debit balance and settle credits the release back, so an unconsumed batch residual is swept to the qalkeys-residual sink agent — this keeps the payer's net debit EXACTLY the metered cents and the seller's income EXACTLY the metered cents. In the Move phase, holds debit at hold-time and the sink disappears (same note as qalredeem's sweep).

Upgrade path

  1. x402-compatible header mode (from 09_identity_ai/AI_PAYMENTS_LANDSCAPE.md): unpaid proxy calls return 402 with an accepts array carrying a qals scheme (chain-verifiable B-QALS transfer against the caller's DID); stock x402 clients negotiate it, our facilitator verifies settlement. v1's qk_ Bearer flow is the same interchange with the key as the credential.
  2. Delegated holds: loopd macaroon-style attenuated credentials (L402 lineage) let a buyer derive a capped sub-credential — kills the prepaid sub-agent and the residual sink.
  3. On-chain escrow (qal_credit holds) for MODE 2 → threshold release removes the single trustee.
  4. x402-MCP wrappers: expose listings as MCP tools that 402 when unfunded.

Run / test

python3 qalkeys/qalkeys.py          # :8841 (loopd must be on :8823)
bash qalkeys/test_qalkeys.sh        # 66 checks, self-starts service + mock
python3 qalkeys/qk.py list|buy|usage|call|keys|buykey|reveal|org-*

Env: QALKEYS_ANCHOR_EVERY (100) · QALKEYS_KEY_COOLDOWN_MS (24h) · QALKEYS_BATCH_CALLS (10) · QALKEYS_BATCH_VALUE_CENTS (25) · QALKEYS_RATE_RPS (10) · QALKEYS_RATE_BURST (20) · QALKEYS_DEFAULT_KEY_CAP_CENTS (500) · QALKEYS_PORT (8841)

Files live in qalkeys/data/ (archived, never deleted, by the test).