API docs

OpenAI-compatible. Two env vars and any harness works — opencode, Cursor, Cline, or plain curl. Base URL: https://trulyopenrouter.vercel.app/api/gw/v1 · contracts on Hedera testnet. Running the stack yourself? Swap the base for http://localhost:4121/v1.

How it fits together

Two contracts on Hedera testnet and one off-chain router. You put HBAR into the vault and get credits. Anyone can run a host — stake, register, serve. Every routed call moves money twice: once to the host in USDC over x402, once against your credits in the vault.

Youany wallet

subscribe(planId) payable — plan 0 is 10 HBAR → 10,000 credits

prompt → POST /v1/chat/completions
Gatewayoff-chain router

checks your limits before any money moves · picks a host on price, latency, stake and reliability

host's guard answers HTTP 402 payment_required
gateway pays $0.001 test USDC over x402 — settled by the Blocky402 facilitator
Hostanyone · 4 HBAR stake

register() on HostRegistry, then serves the completion from its own GPU

gateway calls debit(user, host, credits, receiptHash)
SubscriptionVaultholds the HBAR

credits[you] −N · hostEarnings[host] +90% · accruedFees +10%

host calls withdraw() and pulls its earnings as HBAR
Receiptid = sha256

both legs recorded, id mirrored to HCS topic 0.0.10379640

Two money legs, deliberately separate

The host is paid per request in test USDC by the gateway over x402. Your credits are metered down in the vault, where the host's 90% share accrues in HBAR and is withdrawn separately. HBAR you deposit never converts into USDC — the gateway funds the USDC leg from its own account. A receipt ties both legs to one call.

SubscriptionVault0xd75c46c0e82115ab4d24326dbbbbffe4e7d0c576
  • subscribe(planId) payable — buy credits
  • debit(user, host, amount, receiptHash) — gateway only
  • withdraw() — host pulls earnings as HBAR
  • refund() — cash out unused credits at a fixed rate
  • daily quota + per-user spend caps enforced in-contract
  • PROTOCOL_FEE_BPS = 1000 → 10% fee, 90% to the host
HostRegistry0x5f83c19413fc15181e2e79512947e374c7b8dc56
  • register(...) — 4 HBAR min stake, model id + digest
  • heartbeat() — stay in rotation
  • updatePricing(pricePerReq, pricePer1kTokens)
  • deregister() → release() after a 24h timelock
  • challenge(host, receiptId) — dispute hook
  • eligibleHosts(modelId) — what the router reads
Verify the facilitator yourself (live)
curl -s https://trulyopenrouter.vercel.app/api/gw/api/config | jq
# -> { chainId: 296, registry, vault,
#      facilitator: "https://api.testnet.blocky402.com",
#      usdc: "0.0.429274" }
Run everything locally (CLI, stack, Ledger, Privy)
git clone https://github.com/Lucas749/TrulyOpenRouter && cd TrulyOpenRouter
sh quickstart.sh   # ~15 min, testnet only, nothing costs money
Serve a model (one command, key stays on your machine)
sh host-runner/setup.sh   # pull → stack → digest → register → heartbeat cron
# full manual walkthrough: host-runner/README.md in the repo
Python (openai SDK)
from openai import OpenAI

client = OpenAI(
    base_url="https://trulyopenrouter.vercel.app/api/gw/v1",
    api_key="tor_sk_…",  # create at /api
)

response = client.chat.completions.create(
    model="qwen2.5:0.5b",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
opencode provider
# opencode.json, custom provider pointing at the router
{
  "$schema": "https://opencode.ai/config.json",
  "model": "trulyopenrouter/qwen2.5-7b",
  "provider": {
    "trulyopenrouter": {
      "options": { "baseURL": "https://trulyopenrouter.vercel.app/api/gw/v1", "apiKey": "tor_sk_…" }
    }
  }
}
Keys + receipts (curl)
# issue a scoped key for your login (shown once; easiest at /api)
curl -X POST https://trulyopenrouter.vercel.app/api/gw/api/keys \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $PRIVY_ACCESS_TOKEN" \
  -d '{"scopes":{"models":["qwen2.5:0.5b"]}}'

# chat, response carries tor_receipt + tor_settled
curl -X POST https://trulyopenrouter.vercel.app/api/gw/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer tor_sk_…" \
  -d '{"model":"qwen2.5:0.5b","messages":[{"role":"user","content":"hi"}]}'

# verify the receipt (hashes only, bodies never leave the hosts)
curl https://trulyopenrouter.vercel.app/api/gw/api/receipts/<id>

# network truth
curl https://trulyopenrouter.vercel.app/api/gw/api/hosts
curl https://trulyopenrouter.vercel.app/api/gw/api/stats
Models (live directory)
curl https://trulyopenrouter.vercel.app/api/gw/v1/models
# -> [{ id, hosts, minPricePerReq, calls24h }] — cheapest healthy host wins per call
Receipts (hashes only, bodies never leave hosts)
curl https://trulyopenrouter.vercel.app/api/gw/api/receipts/<id>
# -> { id (sha256), modelDigest, host, priceWei, debitTx, hcsSeq }
# debitTx: vault debit on HashScan · hcsSeq: same id on topic 0.0.10379640
Keys, caps and quota
# scoped key for your login (models allowlist, expiry) — shown once
curl -X POST https://trulyopenrouter.vercel.app/api/gw/api/keys -H 'Content-Type: application/json' -H "Authorization: Bearer $PRIVY_ACCESS_TOKEN" -d '{"scopes":{"models":["qwen2.5:0.5b"]}}'
# member allowance: 429 quota_exceeded past cap · vault debit is the backstop
# key budget accounts derive per prefix (HKDF) — fund explicitly, never auto
Host API (serve + earn)
# register (4 HBAR stake + 1 HBAR gas reserve; key stays on your machine)
sh host-runner/setup.sh
# directory + detail + verify
curl https://trulyopenrouter.vercel.app/api/gw/api/hosts
curl https://trulyopenrouter.vercel.app/api/gw/api/hosts/<address>
# heartbeat (cron every 10 min keeps you in rotation) · leave: tor-host leave
Errors
401 invalid_api_key  — unknown/revoked key or bad wallet signature
402 payment_required — wallet out of credits, subscribe first
404 model_not_found  — model not in key scope, or unknown receipt/host
409 conflict         — e.g. member already active, tap already decided
429 quota_exceeded   — member allowance spent, owner raises it in /team
501 unavailable      — leg not configured (admin token, vault, tap signer)
502 upstream_error   — host/gateway leg failed, receipt still recorded where possible

Manage keys →