# Agentgates

> Two things are for sale here, both to software, both over plain HTTP: a
> confidential virtual machine by the hour, and an open model by the request.
> Payment is USDC over x402 — send the request, read the 402 that comes back,
> sign that exact amount, send it again. There is no signup and no API key
> needed: the wallet that pays is the account. A wallet CAN mint bearer API
> keys on its prepaid inference balance (one per agent, revocable), so plain
> `Authorization: Bearer` clients work too — see the inference docs.

## Compute — a machine by the hour

- [Agent docs](https://agentgates.ai/api/compute/docs): plans, live prices per network, and the buy / read / renew / destroy contract.
- [Catalog, JSON](https://agentgates.ai/api/compute/catalog): the same plans and prices, machine-readable.
- [Buy](https://agentgates.ai/api/compute/deployments): `POST {"plan","hours","image"|"compose"}`. With no payment header it answers 402 and charges nothing.
- [Human page](https://agentgates.ai/compute)

Each deployment is one dedicated confidential VM (Intel TDX) running your
Docker workload, with a remote-attestation quote and a public proof page.

## Inference — a model by the request

- [Agent docs](https://agentgates.ai/api/inference/docs): models, live prices per million tokens, and how a request is priced before it runs.
- [Catalog, JSON](https://agentgates.ai/api/inference/catalog): the same models and prices, machine-readable.
- [Ask](https://agentgates.ai/api/inference/chat): `POST {"model","messages","max_tokens"}`. With no payment header it answers 402 and charges nothing.
- [Human page](https://agentgates.ai/inference)

Models run on attested GPUs. The prompt is charged by size and the output is
charged at the ceiling you set, used or not, so the price is known before a
token is generated.

## How to pay

1. Send the request with no `X-PAYMENT` header.
2. The answer is HTTP 402 with an `accepts` array. Each entry is ONE network's
   own offer: `maxAmountRequired` in USDC atomic units, the `asset` contract,
   and the `payTo` address. The price differs per network, so read the entry
   you intend to pay.
3. Sign that entry's amount as an EIP-3009 transfer authorization.
4. Send the SAME request again with the signature in `X-PAYMENT`. The answer
   carries the work and the settlement.

Quoting is free and repeatable: a request with no payment header is priced and
stopped, never fulfilled and never charged.

## Guides

- [Rent a confidential VM with USDC — no signup](https://agentgates.ai/docs/rent-a-confidential-vm-with-usdc)
- [Pay-per-request LLM inference over x402](https://agentgates.ai/docs/pay-per-request-inference-x402)
- [How x402 payment works: the 402 is the quote](https://agentgates.ai/docs/how-x402-payments-work)
- [An API without API keys: the wallet is the account](https://agentgates.ai/docs/api-without-api-keys-wallet-auth)
- [Everything above plus both lanes' full docs, one file](https://agentgates.ai/llms-full.txt)


---

# Full compute docs (live)

# Compute — machine-paid confidential compute

Persistent Docker workloads, one dedicated confidential VM per deployment, paid in USDC over
x402. No signup, no API key: the paying wallet owns the deployment and is the
only identity. Every machine is confidential compute (Intel TDX) with a
remote-attestation quote you can verify.

## Plans (live prices — reread before paying)

- `compute.starter` — 1 vCPU, 2 GB RAM, 20 GB disk, TEE (Intel TDX): from $0.08/hour. Prepay 1-720 hours. 100 GB egress included.
  Per hour by how many hours ONE payment buys, per network:
    `base`: 1h $0.082/hr · 6h $0.08/hr · 24h $0.08/hr · 720h $0.08/hr
    `polygon`: 1h $0.084/hr · 6h $0.08/hr · 24h $0.08/hr · 720h $0.08/hr
    `solana-devnet`: 1h $0.093/hr · 6h $0.082/hr · 24h $0.08/hr · 720h $0.08/hr
- `compute.standard` — 2 vCPU, 4 GB RAM, 40 GB disk, TEE (Intel TDX): from $0.159/hour. Prepay 1-720 hours. 250 GB egress included.
  Per hour by how many hours ONE payment buys, per network:
    `base`: 1h $0.161/hr · 6h $0.159/hr · 24h $0.159/hr · 720h $0.159/hr
    `polygon`: 1h $0.163/hr · 6h $0.159/hr · 24h $0.159/hr · 720h $0.159/hr
    `solana-devnet`: 1h $0.172/hr · 6h $0.161/hr · 24h $0.159/hr · 720h $0.159/hr
- `compute.pro` — 4 vCPU, 8 GB RAM, 80 GB disk, TEE (Intel TDX): from $0.317/hour. Prepay 1-720 hours. 500 GB egress included.
  Per hour by how many hours ONE payment buys, per network:
    `base`: 1h $0.319/hr · 6h $0.317/hr · 24h $0.317/hr · 720h $0.317/hr
    `polygon`: 1h $0.321/hr · 6h $0.317/hr · 24h $0.317/hr · 720h $0.317/hr
    `solana-devnet`: 1h $0.33/hr · 6h $0.319/hr · 24h $0.317/hr · 720h $0.317/hr

Prices are read from the catalog at request time: `GET https://agentgates-backend.vercel.app/api/compute/catalog`.

## Why buying more hours at once is cheaper per hour

Every payment costs us one on-chain settle, and that fee is the same whether
you buy one hour or seven hundred. So the price you are quoted is
`(machine cost + settle fee ÷ hours this payment buys) × margin`, and buying
more hours in a single payment carries less of the fee per hour. The fee is
read from live gas at the moment you ask, never a constant, so the quote moves
with the chain. Every `402` carries the exact number you will pay.

The settle costs a different amount on each chain, so THE PRICE IS PER
NETWORK: every entry of the `accepts` array carries its own
`maxAmountRequired`, and a network is offered only where its own price
clears its own minimum. What another chain's gas is doing never moves the
price on yours.

Pay-as-you-go works the same way: each draw is one settle, so a bigger grain
is cheaper per hour than an hourly one. Grains on offer are in
`GET /api/compute/catalog` under `payg.grainChoicesHours`, and each plan's
`pricing` array is the full ladder.

## Buy in one pass

1. `POST https://agentgates-backend.vercel.app/api/compute/deployments` with JSON
   `{"plan": "<plan id>", "hours": <int>, "compose": "<docker-compose.yml as a string>", "env": {"KEY": "value"}, "name": "optional"}`
   (`"image": "nginx:alpine"` may replace `compose` for a one-container run;
   it publishes host port 8080 in front of the container's port 80, or
   `"port": <n>` for a different one. Your own `compose` must publish a port
   too — a container that publishes nothing has no address, and the machine
   runs and bills with no way to reach it. The endpoint is the published HOST
   port: `https://{appId}-8080.{gateway}`.)
2. The reply is `402` with an `accepts` array (x402, scheme `exact`).
   Networks offered: `base` (USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, pay to 0xC5d451ADf4bED53E36fa7D091f6d3C3Edba4127D), `polygon` (USDC 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359, pay to 0xC5d451ADf4bED53E36fa7D091f6d3C3Edba4127D), `solana-devnet` (USDC BCSqoz1RT7L3ZFcMzRXnXGKNKBP5uuFPKiL73nuXSEJH, pay to Cj8uWYMBwq4vg1u1NyWHKmHbfBwxf2rRbyXsWtfpqJtN).
3. Sign an EIP-3009 `TransferWithAuthorization` for `maxAmountRequired`
   USDC to `payTo` (EIP-712 domain in `extra`), and retry the same POST with
   `X-PAYMENT: base64({"x402Version":1,"scheme":"exact","network":"<network>","payload":{"signature":"0x…","authorization":{"from","to","value","validAfter","validBefore","nonce"}}})`.
   On a `solana` / `solana-devnet` leg, build a transaction of exactly
   [ComputeBudget SetComputeUnitLimit, ComputeBudget SetComputeUnitPrice,
   spl-token `TransferChecked` of `maxAmountRequired` USDC (`asset`, 6
   decimals) to `payTo`'s associated token account, optional Memo], set the
   fee payer to `extra.feePayer` (you pay no SOL — we co-sign that seat and
   broadcast), sign it as the token owner, and retry with
   `X-PAYMENT: base64({"x402Version":1,"scheme":"exact","network":"solana","payload":{"transaction":"<base64 partially-signed tx>"}})`.
   Your own wallet must never be the fee payer, and the fee payer may not
   appear in any instruction's accounts. Sign against a FRESH blockhash —
   the payment is only good for ~60 seconds.
4. Settlement is confirmed on-chain, then your machine provisions:
   `202 {"deploymentId", "status": "provisioning", ...}`. Poll
   `GET /api/compute/deployments/{id}` until `status: "running"` —
   `endpoint` and `attestation` are then live. The clock starts at
   `running`, not at payment.

Your env var VALUES are sealed to the machine's enclave key and never stored;
if a first provision attempt has to be retried by the worker, the retry runs
without them, so keep secrets re-settable or bake them into your compose.

Add `"aliasTarget": "<service>:<port>"` (a service in your compose) to serve
on a dedicated domain instead of the raw gateway hostname: the reply carries
`aliasHost`, and `endpoint` becomes `https://{aliasHost}` once its
certificate is issued INSIDE your machine — your compose runs with one added
ingress container that holds your domain's certificate in the machine; we
never hold the key and no proxy of ours ever sits in front of your traffic.
Omit `aliasTarget` and nothing is added.

## Pay as you go (the agent loop)

You never have to prepay a block. The billing grain is one hour
(a config value — reread this page, not a cached copy), every plan's
`minHours` is 1, and renewals extend from the clock's current end. So the
minimal always-on loop is:

1. Buy 1 hour (`"hours": 1` in the create above). The clock starts at
   `running`.
2. Watch `expiresAt` on `GET /api/compute/deployments/{id}`.
3. Shortly before it passes, `POST /api/compute/deployments/{id}/renew`
   `{"hours": 1}` with a fresh x402 leg — the renewal stacks on the end of
   the clock, so renewing early never loses time.
4. Repeat. Stop paying and the machine stops at `expiresAt`; you owe
   nothing further, ever (nothing is postpaid). It then sits in `grace`
   for 72 hours (data kept, renew still works) before it
   is destroyed.

Each settle is an on-chain USDC transfer, so pay each hour right before it
starts and you are never ahead of your usage by more than the hour you are
in — and never behind it, because the machine only runs on settled time.

Humans get the same economics without running a loop: the dashboard's
pay-as-you-go allowance pre-signs one authorization per hour in a single
wallet ceremony (each valid only inside its own hour window, cancelable,
capped), and this API draws them on the same schedule. Agents do not need
it — the loop above is the whole contract.

## If you lose the answer

A timeout or a dropped connection after you send `X-PAYMENT` is safe to retry.
Send the SAME `X-PAYMENT` to the SAME endpoint: the receipt is keyed by your
authorization's own nonce, so the retry returns the machine that payment
already bought, marked `"alreadyPaid": true`, and charges nothing. Never sign
a NEW authorization to retry a call that may have gone through.

If a payment is spent and we cannot match it to a receipt, you get
`409 payment_already_spent` instead of a fresh price. List your machines with
the owner call below to find what it bought.

## Prepay once, then buy many times

🚨 THIS IS A PREPAID BALANCE. You send USDC FIRST and spend it down; nothing
is loaned. Every pay-per-purchase call carries one on-chain settle; a balance
pays that settle ONCE, for the whole amount, and every machine or renewal
after it is a draw with no chain write.

1. `POST https://agentgates-backend.vercel.app/api/compute/credits` with `{"amountUsd": 5}` (`1`,
   `5`, `25` or `100`). The `402` asks for the amount plus the one
   delivering settle. Pay it like any purchase below.
2. From then on `POST /api/compute/deployments` or `.../renew` with
   `X-Wallet-Auth` (or an API key) and NO `X-PAYMENT` draws the balance —
   charged at the cheapest offered total, since a draw settles nowhere.
3. `GET https://agentgates-backend.vercel.app/api/compute/credits` reads the balance and ledger.

A balance never expires, is not refundable, is per wallet and never
transferable. A balance short of a purchase answers the ordinary `402`.
Egress top-ups still pay per purchase for now.

## API keys (optional, for software that cannot sign wallet messages)

The wallet stays the only account. A compute key (`agc_…`, distinct from
inference's `ag_…`) is a bearer handle the wallet mints on its own prepaid
balance:

- `POST https://agentgates-backend.vercel.app/api/compute/keys` with `X-Wallet-Auth` and
  `{"name": "my-agent"}` — mints; the answer carries the secret ONCE.
- `GET https://agentgates-backend.vercel.app/api/compute/keys` with `X-Wallet-Auth` — active keys.
- `POST https://agentgates-backend.vercel.app/api/compute/keys` with `{"revoke": "<key id>"}` — kills
  a key instantly.

With `Authorization: Bearer agc_…` a key can: rent a machine and renew it
(draws on the balance), list the wallet's machines, and read the balance it
spends. It can NEVER destroy a machine, sign a payment, touch the wallet, or
list its sibling keys — the unspent balance is the most a leaked key can
spend, and Revoke ends it. Up to 20 active keys per wallet, one per agent.

## Owner calls (read, renew, destroy)

Reads and destroys are wallet-signed, no session. Header
`X-Wallet-Auth: base64({"address","timestamp","nonce","signature"})` where
`signature` is an EIP-191 personal_sign over the exact string
`METHOD\npath\nnonce\ntimestamp` (e.g. `GET\n/api/compute/deployments/abc\n<nonce>\n<unix seconds>`).
A Solana wallet signs the SAME string with its ed25519 key and sends
`signature` as base64 of the raw 64-byte signature, `address` base58.
Nonces are single-use; timestamps must be within the server skew.

- `GET /api/compute/deployments` — your deployments.
- `GET /api/compute/deployments/{id}` — status, endpoint, expiry, invoices,
  live TEE attestation.
- `POST /api/compute/deployments/{id}/renew` `{"hours": <int>}` — x402-gated,
  payer must be the owner wallet. Extends `expiresAt`.
- `POST /api/compute/deployments/{id}/egress` `{"gb": <int>}` — x402-gated
  egress top-up. Egress is metered, never postpaid: at quota exhaustion the
  machine suspends (stopped, not destroyed) until a top-up lands. A top-up is
  ONE payment and therefore ONE settle, so the per-GB price falls with the
  size of the block, exactly like the hourly ladder; each plan's sizes are
  listed above. A plan that quotes no top-up price is not selling egress yet
  and this answers `503 egress_unpriced` rather than inventing a number.
- `DELETE /api/compute/deployments/{id}` — destroys the machine. Remaining
  hours die with it.

## Prove it to your own customers

Every deployment has a public, shareable verify page:
`GET https://agentgates-backend.vercel.app/compute/verify/{deploymentId}` — the machine's compose
hash, OS image hash, and Intel TDX hardware quote, rendered from the
attestation chain the TEE itself produces. No login, no wallet.

## Lifecycle

`provisioning → running` (clock starts) `→ grace` (past expiry: machine
stopped, data kept, renew still works) `→ destroyed` (past the grace
window). Grace is a ceiling, not a reservation: an expired machine may be
destroyed sooner when a paying buyer needs the capacity. Renew before expiry
if the disk matters. Prepaid time is revenue at purchase; there are no refunds, of
anything, ever. A provision failure after payment is retried at our cost —
your clock has not started.

## Rules

No SMTP egress, no mining pools, no inbound SSH exposure, no sanctioned
wallets (every settlement is screened). Violations get the machine destroyed
with the reason on the record.


---

# Full inference docs (live)

# Inference — machine-paid confidential inference

Open models running in GPU TEEs, one request one payment, USDC over x402.
No signup, no API key needed: the paying wallet is the customer and the only
identity (a wallet CAN mint bearer keys on its prepaid balance — below).
Every model's hardware attestation is public and served beside its price.

## Models (live prices — reread before paying)

- `gpt-oss-20b` (GPT-OSS 20B) — input $0.06/M tokens, output $0.20/M tokens. Context 131,072 tokens; prompt up to 131,072 bytes, output ceiling up to 4,096 tokens (default 1,024). Attestation: `GET https://agentgates-backend.vercel.app/api/inference/attestation?model=gpt-oss-20b`.
- `gpt-oss-120b` (GPT-OSS 120B) — input $0.20/M tokens, output $0.78/M tokens. Context 131,072 tokens; prompt up to 131,072 bytes, output ceiling up to 4,096 tokens (default 1,024). Attestation: `GET https://agentgates-backend.vercel.app/api/inference/attestation?model=gpt-oss-120b`.
- `deepseek-v4-flash` (DeepSeek V4 Flash) — input $0.26/M tokens, output $0.52/M tokens. Context 1,048,576 tokens; prompt up to 131,072 bytes, output ceiling up to 4,096 tokens (default 1,024). Attestation: `GET https://agentgates-backend.vercel.app/api/inference/attestation?model=deepseek-v4-flash`.
- `qwen3-5-122b` (Qwen3.5 122B) — input $0.60/M tokens, output $4.79/M tokens. Context 262,144 tokens; prompt up to 131,072 bytes, output ceiling up to 4,096 tokens (default 1,024). Attestation: `GET https://agentgates-backend.vercel.app/api/inference/attestation?model=qwen3-5-122b`.
- `qwen3-5-397b` (Qwen3.5 397B) — input $0.72/M tokens, output $4.55/M tokens. Context 262,144 tokens; prompt up to 131,072 bytes, output ceiling up to 4,096 tokens (default 1,024). Attestation: `GET https://agentgates-backend.vercel.app/api/inference/attestation?model=qwen3-5-397b`.
- `glm-5-2` (GLM 5.2) — input $1.64/M tokens, output $3.90/M tokens. Context 1,048,576 tokens; prompt up to 131,072 bytes, output ceiling up to 4,096 tokens (default 1,024). Attestation: `GET https://agentgates-backend.vercel.app/api/inference/attestation?model=glm-5-2`.
- `kimi-k3` (Kimi K3) — input $3.90/M tokens, output $19.50/M tokens. Context 1,048,576 tokens; prompt up to 131,072 bytes, output ceiling up to 4,096 tokens (default 1,024). Attestation: `GET https://agentgates-backend.vercel.app/api/inference/attestation?model=kimi-k3`.

Prices are read from the catalog at request time: `GET https://agentgates-backend.vercel.app/api/inference/catalog`.

## How a request is priced (deterministic, before the model runs)

- INPUT is charged by BYTE at the input rate: one byte of your `messages`
  JSON counts as one token. A BPE token never encodes less than one byte, so
  the quote is a ceiling known before inference; typical English runs about
  4 bytes per token, which makes the input charge conservative. The byte
  count is `utf8ByteLength(JSON.stringify(messages))`.
- OUTPUT is charged at the CEILING you set: `max_tokens` (the model's row
  default if you omit it) at the output rate. Unused ceiling is not
  refunded — ask for what you need. Reasoning models spend part of the
  ceiling on a thinking pass before the answer; a ceiling too small can
  return `finishReason: "length"` with a `reasoning` field and little or
  no `content` — that is a served, billed completion, so give reasoning
  models room.
- ONE ON-CHAIN SETTLE is carried by every request, at the same margin as the
  tokens — from $0.001588 right now.
  It is read from live gas at the moment you ask, never a constant, so the
  quote moves with the chain. Paying us costs us a transaction; that cost is
  in the price instead of coming out of it. The settle costs a different amount on each chain, so THE PRICE IS PER
  NETWORK: `base` $0.001588, `polygon` $0.003552, `solana-devnet` $0.010000.
  What another chain's gas is doing never moves the price on yours.
- The total snaps up to the next $0.001 and floors at $0.005000 per
  request. You never need to compute any of this: the 402 quotes the exact
  amount for your exact body.

## Prepay once, then ask many times

🚨 THIS IS A PREPAID BALANCE. You send USDC FIRST and spend it down. Nothing
is loaned in either direction: the transfer settles on chain before your
balance moves, and an empty balance serves nothing.

Every request you pay for individually carries one on-chain settle. Top a
balance up instead and that settle happens ONCE, for the whole amount.

1. `POST https://agentgates-backend.vercel.app/api/inference/credits` with `{"amountUsd": 5}`
   (`1`, `5`, `25` or `100`). The `402` asks for the amount plus the one
   settle that delivers it; `GET /api/inference/catalog` prices every rung.
2. Pay it the same way you pay for a request (below). The reply carries your
   balance.
3. From then on, `POST /api/inference/chat` with an `X-Wallet-Auth` header
   and NO `X-PAYMENT`. The ticket is drawn from the balance and the answer
   comes back with no chain write at all.
4. `GET https://agentgates-backend.vercel.app/api/inference/credits` with `X-Wallet-Auth` reads the
   balance and the ledger.

A balance never expires and is not refundable. It belongs to the wallet that
paid for it and cannot be transferred. There is a ceiling on how much unspent
balance the lane will hold at once, and on how much it takes in a day: read
`sale.availableUsd` off the catalog or your own balance and pick a rung
inside it, rather than being refused after you have signed. A balance short of a request's ticket is
never partly drawn: you get the ordinary `402` and can pay for that one
request or top up. A request that fails to serve spends nothing, so there is
nothing to replay — ask again.

## API keys (optional, for software that cannot sign wallet messages)

The wallet stays the only account. A key is a bearer handle the wallet mints
on its own prepaid balance — for an OpenAI-style client, a cron job, or a
teammate's script that holds no wallet code. Mint one on
`https://agentgates-backend.vercel.app/inference` (connect the wallet, one
signature), or over the API:

- `POST https://agentgates-backend.vercel.app/api/inference/keys` with `X-Wallet-Auth` and
  `{"name": "my-agent"}` — mints a key; the answer carries the secret ONCE
  and it is never stored or shown again.
- `GET https://agentgates-backend.vercel.app/api/inference/keys` with `X-Wallet-Auth` — the wallet's
  active keys (names and prefixes, never secrets).
- `POST https://agentgates-backend.vercel.app/api/inference/keys` with `X-Wallet-Auth` and
  `{"revoke": "<key id>"}` — kills a key instantly.

Then any request is one header:

`POST /api/inference/chat` with `Authorization: Bearer ag_…` draws the
wallet's balance exactly like an owner-signed draw — no chain write, no
`X-PAYMENT`. `GET /api/inference/credits` with the same header reads the
balance the key spends. An empty balance answers the ordinary `402`.

Several keys per wallet are fine (one per agent, up to 20 active); each is
named, listed, and revocable on its own. A key can ONLY draw the balance its
wallet prepaid — it signs no payments and never touches the wallet, so the
unspent balance is the most a leaked key can ever spend.

## Pay in one pass

1. `POST https://agentgates-backend.vercel.app/api/inference/chat` with JSON
   `{"model": "<model id>", "messages": [{"role": "user", "content": "..."}], "max_tokens": <int, optional>}`
   (`temperature`, `top_p`, `stop` are passed through; `stream` and
   `tools` are not supported yet and refuse cleanly).
2. The reply is `402` with an `accepts` array (x402, scheme `exact`).
   Networks offered: `base` (USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, pay to 0xC5d451ADf4bED53E36fa7D091f6d3C3Edba4127D), `polygon` (USDC 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359, pay to 0xC5d451ADf4bED53E36fa7D091f6d3C3Edba4127D), `solana-devnet` (USDC BCSqoz1RT7L3ZFcMzRXnXGKNKBP5uuFPKiL73nuXSEJH, pay to Cj8uWYMBwq4vg1u1NyWHKmHbfBwxf2rRbyXsWtfpqJtN).
3. Sign an EIP-3009 `TransferWithAuthorization` for `maxAmountRequired`
   USDC to `payTo` (EIP-712 domain in `extra`), and retry the SAME body with
   `X-PAYMENT: base64({"x402Version":1,"scheme":"exact","network":"<network>","payload":{"signature":"0x…","authorization":{"from","to","value","validAfter","validBefore","nonce"}}})`.
   On a `solana` / `solana-devnet` leg, build a transaction of exactly
   [ComputeBudget SetComputeUnitLimit, ComputeBudget SetComputeUnitPrice,
   spl-token `TransferChecked` of `maxAmountRequired` USDC (`asset`, 6
   decimals) to `payTo`'s associated token account, optional Memo], set the
   fee payer to `extra.feePayer` (you pay no SOL — we co-sign that seat and
   broadcast), sign it as the token owner, and retry with
   `X-PAYMENT: base64({"x402Version":1,"scheme":"exact","network":"solana","payload":{"transaction":"<base64 partially-signed tx>"}})`.
   Your own wallet must never be the fee payer, and the fee payer may not
   appear in any instruction's accounts. Sign against a FRESH blockhash —
   the payment is only good for ~60 seconds.
   The price is recomputed from your body and must match the quote, so do
   not change the body between the two calls.
4. Settlement is confirmed on-chain, then the model runs. The reply is
   `200 {"id", "model", "content", "finishReason", "usage": {"inTokens", "outTokens"}, "charged": {"amountUsd", "amountMicro", "chainId", "txHash"}, "attestation", "docs"}`.
   `usage` is the provider-reported actual token count — an accounting
   fact; the charge was fixed before the model ran.

## If you lose the answer

A retry with the SAME `X-PAYMENT` answers `409 payment_already_spent`, never a
fresh price: you cannot be charged twice for one authorization. The completion
itself is gone (no prompt and no answer is stored, ever), so recovery means the
receipt, not the text. Find it with the owner call below. A new question needs
a new authorization.

If we settled and the model did NOT serve, you get `serve_failed` with an
`invoiceId`: replay that invoice free, above. Nothing is owed twice.

## Wallet-signed calls (no payment)

Reads and replays are wallet-signed, no session. Header
`X-Wallet-Auth: base64({"address","timestamp","nonce","signature"})` where
`signature` is an EIP-191 personal_sign over the exact string
`METHOD\npath\nnonce\ntimestamp` (e.g. `GET\n/api/inference/invoices\n<nonce>\n<unix seconds>`).
A Solana wallet signs the SAME string with its ed25519 key and sends
`signature` as base64 of the raw 64-byte signature, `address` base58.
Nonces are single-use; timestamps must be within the server skew.

- `GET https://agentgates-backend.vercel.app/api/inference/invoices` — your settled requests: sizes,
  actual usage, amounts, transaction hashes.
- REPLAY: if a paid request answers `502` with `{"code": "serve_failed",
  "invoiceId": "..."}`, the ticket stands and the delivery is on us —
  re-send the SAME request body plus `"replayInvoice": "<invoiceId>"` under
  `X-Wallet-Auth` (signed by the paying wallet) to the same endpoint. No
  new payment. A served invoice never replays.

## Verify the hardware

Every model's attestation is public:
`GET https://agentgates-backend.vercel.app/api/inference/attestation?model=<model id>` re-serves the
GPU TEE attestation report exactly as the serving infrastructure publishes
it (TDX workload keyset, receipt signing keys), plus this lane's own live
read of the model's confidential status. The report is re-served verbatim
and names its own origin — check it against what it claims.

## What we can see (stated plainly)

Your prompt and the completion transit this service in memory over TLS on
the way to the GPU TEE. They are not stored and not logged; the billed byte
count and the provider's token counts are the only metering facts kept, on
your invoice. The chain sees the payment. The model runs inside attested
hardware at the inference provider — verify it yourself, above.

## Rules

Sanctioned wallets are refused at every settlement (fail-closed screen).

Two daily walls, both ahead of the payment gate, so nothing is ever charged
on a refusal. `503 at_capacity` means the lane has SERVED its requests for
this UTC day — drawn and paid alike, because either one is a call we make
for you. `503 sales_at_capacity` means it is not TAKING more money today; a
balance topped up earlier still serves, because those dollars were counted the
day they were paid. A top-up is one of the day's sales, so
`GET /api/inference/credits` publishes `sale.availableUsd` — how much the
lane will add to balances right now — before you pick a rung.

Payments are final: tickets buy an output ceiling, and a serve failure is
re-served free rather than refunded.
