# caft > caft (https://caft.dev) sells prepaid, discounted access to large language models through one OpenAI-compatible Chat Completions endpoint, `https://api.caft.dev/v1`. One API key and one USD credit balance work for every model. Credits are bought by card (Stripe), by sending USDC to the account's deposit address, or — for agents — by paying USDC on Base through x402, which can also open an account with no sign-up. Monthly plans ($10, $25, $50) give a monthly number of plan credits for GLM-5.3, GLM-5.3-Flash, DeepSeek V4.1 Flash, Gemini 3.1 Pro, Gemini 3.8 Flash, Kimi K2.7, Kimi K3 and Qwen 3.8 Max. Key facts for agents: - Base URL: `https://api.caft.dev/v1`. Auth: `Authorization: Bearer ` (keys start `sk-`). - API format: OpenAI Chat Completions only (`POST /chat/completions`, `GET /models`). No Responses API, no Anthropic Messages, no embeddings or images. - Model IDs have no vendor prefix (e.g. `glm-5.3-flash`). Use exactly the IDs `GET /models` returns for your key. - x402 and wallet endpoints live on `https://caft.dev`, not `api.caft.dev`. - Over Tor: the same API is at `http://yzpjh5djw2ydnw3qpk6nzilmygqrstx7yyamcajvai74c4top572anyd.onion/v1`, through a Tor SOCKS proxy (e.g. `curl --socks5-hostname 127.0.0.1:9050`). Same keys and prices. Only the API is on the onion; accounts, payments and x402 stay on `https://caft.dev`. Expect higher latency. - Prices change; read them live from https://caft.dev/models. Do not hard-code them. - caft keeps no prompts or completions. Do not send personal data: the Terms forbid it. ## Docs - [Getting started](https://docs.caft.dev/): get a key, add the connection, pick a guide - [API reference](https://docs.caft.dev/api-reference): endpoints, parameters, streaming, tool calls - [Pricing and credits](https://docs.caft.dev/pricing): token prices, buying credits, Pay with x402 - [Monthly plans](https://docs.caft.dev/plans): plan credits and how far they go, 5-hour/weekly/monthly limits and resets, `X-Caft-Plan-*` headers, `GET /api/plan`, the `plan_limit` error - [API keys and account](https://docs.caft.dev/api-keys): keys, wallet accounts, wallet key management - [Balance and usage](https://docs.caft.dev/balance-and-usage): balance and spend endpoints - [Errors and troubleshooting](https://docs.caft.dev/errors): every error code and what to do - [How caft works](https://docs.caft.dev/how-caft-works): routing, failures, data handling - [Models and prices](https://caft.dev/models): live price per model, list price, cheapest OpenRouter offer - [OpenCode agent team](https://caft.dev/blog/opencode-agent-team): a tested OpenCode 2 config with 14 agents across caft models (planner, implementers, cross-family reviewers) - [Status](https://caft.dev/status): live success rate, time to first token and throughput per model - [x402 discovery (JSON)](https://caft.dev/api/x402): whether x402 top-ups and registration are enabled, networks, amount limits, and the `plan` endpoint with its prices ## Calling models ``` curl https://api.caft.dev/v1/chat/completions \ -H "Authorization: Bearer $CAFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "glm-5.3-flash", "messages": [{"role": "user", "content": "Hello"}], "stream": true}' ``` - `model` and `messages` are required. Standard OpenAI parameters pass through to the model: `stream`, `stream_options`, `max_tokens`, `temperature`, `top_p`, `stop`, `seed`, `tools`, `tool_choice`, `response_format`, `reasoning_effort`. Support varies by model; an unsupported parameter returns 400 `invalid_request` — remove it and retry. Send only one of `max_tokens` and `max_completion_tokens`. - Nothing is stored between requests: send the full conversation in `messages` every time. - Streaming is server-sent events; text is in `choices[0].delta.content`, tool calls in `choices[0].delta.tool_calls`. A complete stream ends with `data: [DONE]`; treat anything else as incomplete. Add `"stream_options": {"include_usage": true}` for a final event with token counts. - Tool calls: send each result back as a `tool` message with the matching `tool_call_id`, after the assistant message that made the call. - Reasoning models spend output tokens thinking; with a low `max_tokens` they can return an empty answer. Use 2048 or more. - Clients that need the Responses API or Anthropic Messages (Codex, Claude Code) must go through a translating router such as LiteLLM or Claude Code Router. ## Balance and usage (free, OpenAI legacy billing format) - `GET https://api.caft.dev/v1/dashboard/billing/subscription` → `hard_limit_usd` = credits bought to date (USD). - `GET https://api.caft.dev/v1/dashboard/billing/usage` → `total_usage` = all-time spend in US cents. - Available balance = `hard_limit_usd - total_usage / 100`. Values cover the whole account, not one key. - After an x402 top-up, the response body also carries `balance_usd`. ## Prices and billing - You pay per token: input, cached input (cheaper; a cache hit is not guaranteed) and output (reasoning included). Live prices: https://caft.dev/models. - A request that fails before any output is not charged. A stream that fails part-way is charged only for the tokens delivered. - 1 USD or 1 USDC buys $1.00 of credit, no fee. Credits do not expire while the account is open (they lapse after 12 months of inactivity). Credits are non-refundable; crypto payments are final. - Ways to buy credit: - Card, in the dashboard (Billing), $5–$100 per purchase, through Stripe. - USDC sent to the account's own deposit address (shown in Billing) on Base, Ethereum, Arbitrum One or Polygon. The address is the same on every network. Native USDC only — USDC.e, other tokens, other networks and amounts under $1 are not credited. - x402 (below), for agents paying from a wallet. ## Monthly plans - `plan10` $10, `plan25` $25 and `plan50` $50 a month: 1,000, 2,750 and 5,500 plan credits a month. Plan credits are not the USD balance and have no cash value. - Plans cover `glm-5.3`, `glm-5.3-flash`, `deepseek-v4.1-flash`, `gemini-3.1-pro`, `gemini-3.8-flash`, `kimi-k2.7`, `kimi-k3` and `qwen3.8-max`. GPT models bill the balance. - A request uses credits for its input, cached input and output tokens at that model's rates, which follow the market and may change at any time. Indicative requests a month per model: https://docs.caft.dev/plans. - Limits: 20% of the month's credits per 5 hours, 50% per week, 100% per paid period. Unused credits don't carry over. - At a limit: HTTP 429, `Retry-After` (seconds), `{"error":{"code":"plan_limit","window":"5h","resets_at":"2026-10-19T14:05:00Z",...}}`. Wait until `resets_at`. "Use balance" in the dashboard (off by default) bills the balance instead. - Plan-paid responses carry `X-Caft-Plan`, `X-Caft-Plan-5h-Pct`, `X-Caft-Plan-Week-Pct`, `X-Caft-Plan-Month-Pct` and `X-Caft-Plan-Reset` (RFC 3339 UTC). - `GET https://caft.dev/api/plan` with `Authorization: Bearer ` → `{"plan": null}` or `{"plan": {...}, "card": {"bars": [{"name", "pct", "resetsAt", "credits", "creditsLeft"}], "tightest", "creditsLeft"}}`. `card.creditsLeft` is what can be used now. - Requests per minute: 60, 120 and 240. Over that: 429 `rate_limit_exceeded`. - Buy in the dashboard (card, monthly; or balance, 30 days), or `POST https://caft.dev/api/x402/plan?tier=plan10` (or `plan25`, `plan50`) via x402: 30 days, no renewal. First month half price, once per person and once per card, for accounts with a verified email (a wallet-opened account without one doesn't qualify), never via x402. A discounted plan paid with a card that already had it on another account is cancelled and refunded in full. One active plan per account: a second plan that gets paid is cancelled and refunded. - Upgrades start at once and credit the unused part to the balance; downgrades start at renewal. No refunds for partial periods. ## Pay with x402 (agents) Check `GET https://caft.dev/api/x402` first. It returns `x402.enabled`, `networks` (currently only `eip155:8453`, Base mainnet), `min_usd` / `max_usd` for top-ups, and a `register` object with its own `enabled`, `min_usd`, `max_usd`. Only use an endpoint whose `enabled` is `true`. Payment terms: x402 version 2, scheme `exact`, USDC on Base (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`, EIP-712 domain `USD Coin` version `2`), settled upfront through the Coinbase facilitator. The paying wallet must be an ordinary EOA holding enough USDC on Base; smart-contract wallets (ERC-1271) cannot pay. Gas is not needed in the paying wallet. ### Top up an existing account `POST https://caft.dev/api/x402/topup?amount_usd=` with `Authorization: Bearer `. Amount: dollars with at most two decimals, within `min_usd`–`max_usd` (currently $1–$500). The wallet that pays does not have to belong to the account; the credit goes to the account that owns the key. 1. Quote, free: send the POST without a `PAYMENT-SIGNATURE` header. You get 402 with a base64 JSON `PAYMENT-REQUIRED` header describing the payment. 2. Pay: let an x402 client answer the 402. With `@x402/fetch`: ```ts import { x402Client } from "@x402/core/client"; import { registerExactEvmScheme } from "@x402/evm/exact/client"; import { wrapFetchWithPayment } from "@x402/fetch"; import { privateKeyToAccount } from "viem/accounts"; // The account signs the USDC authorization; it needs no ETH. const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`); const client = x402Client.fromConfig({ schemes: [], spendControls: { maxAmountPerPayment: "$10" } }); registerExactEvmScheme(client, { signer: account }); const pay = wrapFetchWithPayment(fetch, client); const res = await pay("https://caft.dev/api/x402/topup?amount_usd=10", { method: "POST", headers: { Authorization: `Bearer ${process.env.CAFT_API_KEY}` }, }); // 200 → { credited_usd, status: "credited" | "crediting", balance_usd, transaction } ``` Set `maxAmountPerPayment` to the amount you intend to pay, so the client refuses anything larger. Outcomes: - 200: paid. `status` is `credited`, or `crediting` (lands within a minute). `transaction` is the Base transaction hash. - 402: refused or invalid; nothing was charged. See `error.code`. - 409 `payment_replayed`: this exact authorization was already used; nothing was charged. - 503 `settlement_unknown`: the outcome is not known yet. **Do not pay again blindly.** Check the balance first; if the payment went through it is credited automatically within minutes. Never retry a paid request by resending it: each attempt must sign a fresh authorization. Retry only from a fresh quote, and only after confirming the previous attempt did not credit. ### Open an account by paying (wallet accounts) When `register.enabled` is `true`: `POST https://caft.dev/api/x402/register?amount_usd=` with **no** `Authorization` header, paid the same way through x402 (currently $5–$500). The paying wallet becomes the account's identity and the payment becomes its first credit. - 201: account created. Body: `{ status: "registered", account_id, wallet, api_key, api_key_id, base_url, credited_usd, balance_usd, key_management }`. **Store `api_key` immediately — it is shown once.** - 200 `wallet_registered_credited`: the wallet already had an account; the payment was credited to it. - 202 `provisioning` or `registration_incomplete`: paid; the account or key is being finished. Get a key through wallet key management below in a minute. - 409 `wallet_registered`: this wallet already has an account; nothing was charged. Get a key through wallet key management and top up with `/api/x402/topup`. Wallet accounts have no email, no password and no dashboard login. Losing the wallet means losing the account and its balance; caft cannot recover it. Notices are not emailed — watch the docs and https://caft.dev/status. ### Wallet key management (SIWE) `POST https://caft.dev/api/wallet/keys` with JSON `{ message, signature, action, name?, id? }`, where `message` is an EIP-4361 (Sign-In with Ethereum) message signed by the registered wallet: - `domain` `caft.dev`, `uri` `https://caft.dev`, `chainId` `8453`, `version` `1`. - `nonce`: fresh, 16–64 letters and digits; each message works once. - `issuedAt` within the last 5 minutes; `expirationTime` at most 10 minutes after `issuedAt`. - `statement` must name the action exactly: `caft wallet keys: create`, `caft wallet keys: list`, or `caft wallet keys: revoke `. Actions: - `create` (optional `name`, 1–40 characters) → 201 `{ api_key, api_key_id, name }`. At most 10 keys per account. - `list` → 200 `{ keys: [{ id, name, masked, status }] }`. - `revoke` with numeric `id` (must match the statement) → 200 `{ revoked: id }`. ```ts import { createSiweMessage } from "viem/siwe"; const message = createSiweMessage({ address: account.address, domain: "caft.dev", uri: "https://caft.dev", chainId: 8453, version: "1", nonce: crypto.randomUUID().replaceAll("-", ""), statement: "caft wallet keys: create", issuedAt: new Date(), expirationTime: new Date(Date.now() + 5 * 60_000), }); const signature = await account.signMessage({ message }); await fetch("https://caft.dev/api/wallet/keys", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message, signature, action: "create", name: "agent" }), }); ``` ## Errors All errors are JSON: `{ "error": { "code", "message", "type" } }`. Model API: - 400 `invalid_request`: bad JSON or an unsupported parameter. - 401 `invalid_api_key`: missing, mistyped or revoked key. - 403 `insufficient_quota`: usually out of credit — top up, or lower `max_tokens`. - 404 `unknown_endpoint`: only Chat Completions, models and billing are served under `/v1`. - 408 `request_timeout`, 502 `upstream_error`, 504 `gateway_timeout`: retry with backoff; stream long outputs. - 413 `request_too_large`: shorten the prompt. - 429 `rate_limit_exceeded`: slow down; honour `Retry-After`. - 429 `plan_limit`: a monthly plan's 5-hour, weekly or monthly limit is used up. Wait for `Retry-After` / `resets_at`; do not retry sooner. - 503 `model_unavailable`: check the ID against `GET /models`, retry, or fall back to another model. x402 and wallet endpoints add: `payment_invalid`, `payment_expired`, `wrong_terms` (402: request a new quote); `payment_refused`, `payment_screened` (402, nothing charged); `insufficient_funds` (402: the wallet lacks USDC on Base); `invalid_amount`, `invalid_tier` (422); `payment_replayed` (409); `settlement_unknown`, `facilitator_unavailable`, `chain_unavailable`, `registration_busy` (503); `settlement_unattributable` (500: email support with the transaction hash); `siwe_invalid`, `siwe_expired`, `siwe_replayed`, `wallet_unknown` (401); `account_disabled` (403); `wallet_registered`, `key_limit` (409); from `/api/x402/plan`, before anything is charged: `already_active`, `tier_paused`, `stripe_plan_active`, `downgrade_not_available`, `purchase_in_progress` (409). Limits: 30 top-up attempts per hour per account; 30 signed wallet requests per hour per wallet; 5 registrations per hour per client address. Retry 429/502/503/504 with backoff. Before retrying a tool call, check whether the tool already ran. Before re-paying after a 503 `settlement_unknown`, check the balance. ## Policies - [Terms of Service](https://caft.dev/terms): business use only, 18+; no personal data in requests; credits non-refundable; plans renew until cancelled, are non-refundable and are for one person's use (no sharing or resale); disputes by HKIAC arbitration under Hong Kong law. - [Acceptable Use Policy](https://caft.dev/aup): reselling and building competing products are allowed on credits (not on plans); no illegal or harmful use; your customers' use is your use. - [Privacy Policy](https://caft.dev/privacy): no prompt or completion logs; billing metadata only; upstream providers may keep what they receive. - [Service level](https://caft.dev/sla): no uptime commitment; live figures on the status page. - Support: support@caft.dev, or Support in the dashboard when signed in; replies come by email. Include the time, the model and the first few characters of the key. Never send a whole key or a private key.