Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
O402
OpenAI-compatible HTTP gateway, paid with x402.
One binary, one TOML file. Clients speak the OpenAI HTTP API (base_url; dummy Authorization is stripped). Payment is x402 v2, not an API key. TLS terminates at a reverse proxy. o402 holds no seller private keys — only pay-to addresses and upstream LLM keys. Run a remote facilitator for verify/settle.
Requires Rust 1.95. Default features: evm + svm. Image stays default features (no full). No OpenTelemetry.
Install
macOS / Linux
|
Windows (PowerShell)
irm https://sh.qntx.org/o402/ps | iex
Or via Cargo:
# from this tree: cargo install --path crates/o402
Run
# edit gateway.toml; for payment copy deploy/gateway.example.toml
serve --config is required. Bind comes from server.bind (default 0.0.0.0:8080 for containers). o402 init writes the unpaid example. There is no sync command.
CLI: o402 init [--path gateway.toml] and o402 serve --config PATH.
HTTP
| Method | Path | Auth |
|---|---|---|
GET |
/health |
unpaid — liveness { "status": "ok", "service": "o402", "version": "…" } |
GET |
/ready |
unpaid — 200 when payment is off, or when facilitator GET /supported succeeds; 503 otherwise |
GET |
/v1/models and /openai/v1/models |
unpaid — proxied to Bifrost |
GET |
/v1/pricing |
unpaid — o402 rates |
POST |
/v1/chat/completions, /v1/completions, /v1/embeddings, /v1/responses (and /openai prefixed) |
paid upto (token usage) |
| other exported HTTP | /v1/*, /openai/*, /anthropic/*, /genai/*, /bedrock/*, /cohere/*, /litellm/*, /langchain/*, /pydanticai/* |
paid exact (flat price) |
GET |
/v1/realtime, Upgrade: websocket, /api/*, / |
404 — cannot bill |
Unknown models are forwarded. Catalog [[models]] is optional (rate/upstream overrides only).
Point an OpenAI SDK at server.base_url (/v1/...) or server.base_url/openai (Bifrost drop-in). Dummy Authorization is stripped; the gateway injects the upstream key.
Config
TOML with deny_unknown_fields. After parse, a string is replaced only when the entire value is $VAR or ${VAR}. "Bearer $TOKEN" is not expanded. Auth header values are the full header ($FACILITATOR_AUTH_HEADER = Bearer …). dotenvy loads .env from the process cwd at start.
Examples: deploy/gateway.example.toml (paid EVM+SVM), deploy/gateway.full.example.toml (production extras; not used by Docker), and deploy/gateway.unpaid.example.toml (payment.enabled = false). Env names: deploy/o402.env.example.
server.base_url is required when payment is on (r402 never derives origin from Host). Loopback http is allowed; public URLs must be https.
Payment
Cargo features match the facilitator production matrix. Default binary is EVM+SVM. Rebuild with extras (and a facilitator built with the same extras) to advertise those namespaces.
| Feature | Namespace | Schemes | Named asset |
|---|---|---|---|
evm (default) |
eip155 |
exact, upto |
usdc |
svm (default) |
solana |
exact |
usdc |
near |
near |
exact |
usdc |
xrpl |
xrpl |
exact |
xrp, rlusd |
hedera |
hedera |
exact |
usdc, hbar |
avm |
algorand |
exact |
usdc |
aptos |
aptos |
exact |
usdc |
keeta |
keeta |
exact |
usdc |
tvm |
tvm |
exact |
usdt |
stellar |
stellar |
exact |
usdc |
concordium |
ccd |
exact |
usdr, ccd |
experimental-tron |
tron |
exact |
usdt |
full = production extras minus experimental-tron. No casper. SVM upto stays out (voucher signer / seller key). o402 holds no seller keys.
TOML price values are asset units, not a USD peg. shared_decimals is a scale check: mixing Stellar USDC (7), HBAR (8), or RLUSD (15) with USDC-6 fails startup. Same-decimal mixes (USDC-6 + XRP-6) load; treating those rates as dollars is economically inconsistent.
[payment.facilitator] url is the remote facilitator (POST /verify, POST /settle, GET /supported). Optional path-keyed auth:
[]
= "$FACILITATOR_AUTH_HEADER"
Metrics
Default: off. Optional observability.metrics_bind = "127.0.0.1:9090" serves GET /metrics on that bind only. It is never mounted on the payment port (:8080). No OpenTelemetry.
Docker Compose
Gateway HTTP 8080 is loopback/internal. Caddy publishes 80/443 and terminates TLS. Reverse proxy uses flush_interval -1 so SSE is not buffered.
# fill o402.env (pay-to + OPENAI_API_KEY); set server.base_url and the Caddyfile hostname
Bifrost admin UI: http://127.0.0.1:8081 (loopback). Public traffic hits Caddy → o402 → Bifrost.
Image: default features only (evm+svm). HEALTHCHECK is GET /health. Official caddy:2 — no rate-limit plugin.
systemd
Host + reverse proxy: set server.bind = "127.0.0.1:8080" and terminate TLS at Caddy (change deploy/Caddyfile o402:8080 to 127.0.0.1:8080). The container keeps 0.0.0.0:8080 so Compose Caddy can reach it on the Docker network.
Unit: EnvironmentFile=-/etc/o402/o402.env, ExecStart=/usr/bin/o402 serve --config /etc/o402/gateway.toml, Restart=on-failure. TimeoutStopSec=65s covers HTTP drain plus inflight settle (2 × server.shutdown_timeout_secs default 30, plus slack).
Crates
See crates/README.md for the crate table.
Contributing
See CONTRIBUTING.md for development setup, PR expectations, and the release checklist.
Security
This library has not been independently audited. Use at your own risk.
See SECURITY.md for scope and reporting.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project shall be dual-licensed as above, without any additional terms or conditions.
A QuantX open-source project.
Code is law. We write both.