# Bu0y docs

> One key. Your usual tools. Point anything OpenAI-compatible at `https://api.bu0y.com/v1`.

- Site: https://bu0y.com
- API base: `https://api.bu0y.com/v1`
- Agent index: https://bu0y.com/llms.txt
- Full API dump: https://bu0y.com/llms-full.txt
- Support: https://discord.gg/85ebxAjKgz

## Get a key

1. Open https://bu0y.com/account
2. Create a passkey (the desk shows the terms first; read to the end and accept)
3. Mint a `bu0y_…` key (shown once)
4. Add credits (USDC on Solana or Base, or USDG on Robinhood Chain, min $1)

Agents without a passkey: Solana challenge → mint → deposit → sync. See `llms-full.txt`.

## Three fields every client needs

| Field | Value |
|-------|-------|
| Base URL | `https://api.bu0y.com/v1` |
| API key | your `bu0y_…` secret |
| Model | any id from [Models](https://bu0y.com/models) or `/v1/models` — you pick it; clients do not auto-fill |

Stop the base URL at `/v1`. Clients append `/chat/completions`.

## Cursor

1. Settings → Models
2. OpenAI API Key = your `bu0y_…` key
3. Override OpenAI Base URL = `https://api.bu0y.com/v1`
4. Add a model id from [Models](https://bu0y.com/models) (copy the id), then Verify

If it fails: Network → HTTP Compatibility Mode → HTTP/1.1. Ask mode is the reliable check for chat-completions gateways.

## Hermes

`custom_providers` **must be a YAML list** (hyphen before each entry). A dict
produces `Unknown provider 'custom:bu0y'`.

```yaml
# ~/.hermes/config.yaml
custom_providers:
  - name: bu0y
    base_url: https://api.bu0y.com/v1
    api_key: bu0y_…

model:
  default: glm4.6
  provider: custom:bu0y
```

Or run `hermes model` → Custom endpoint (writes the list form). Leave the base
URL at `/v1`. Always set a model id from [Models](https://bu0y.com/models)
and prefer an explicit `max_tokens` in requests.
## OpenAI SDK

```js
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.BU0Y_KEY,
  baseURL: "https://api.bu0y.com/v1",
});
```

Python: `OpenAI(api_key=…, base_url="https://api.bu0y.com/v1")`.

## Anywhere else

If the tool says OpenAI compatible / custom provider / base URL, use the three fields above. That covers Cline, Continue, LibreChat, Open WebUI, LangChain, Vercel AI SDK, and most agent stacks.

```bash
curl https://api.bu0y.com/v1/chat/completions \
  -H "Authorization: Bearer $BU0Y_KEY" \
  -H "content-type: application/json" \
  -d '{"model":"glm4.6","messages":[{"role":"user","content":"hi"}],"max_tokens":256}'
```

## Add credits

Prepaid, non-refundable, no withdraw. Send USDC on Solana or Base, or USDG on Robinhood Chain to your deposit address, then sync.

Check `GET /v1/deposits/status` first. A network with `configured: false` is unavailable and disabled in the desk. Configuration status does not guarantee RPC or bridge health.

## Rules

- Prepaid only
- Always set `max_tokens` — Bu0y reserves worst-case before fill (default ceiling 4096 if omitted)
- Your `max_tokens` is sent upstream exactly as you set it. Bu0y reserves against a 1024-token floor underneath it — reasoning models bill tokens they never show — but that floor never inflates what is asked for, and you are billed for tokens actually used.
- `stream: true` relays tokens as they are produced — first token in about a second, and no total time cap. Reasoning models put chain-of-thought in `delta.reasoning`, separate from `delta.content`. Buffered (non-streaming) fills wait for the whole answer and cap at 480s, so prefer streaming for anything long
- Settlement completes before the terminal frame either way: a `[DONE]` you have seen is a request already written to the ledger
- Hang up mid-stream and you are billed for the tokens that already reached you, estimated from what was sent and rounded down — not for the rest of an answer you never got. The same holds if the provider stops mid-answer: the error frame carries `bu0y.billed_micros` for what reached you, and a stream that broke before any output costs nothing
- Images work on vision models (`content` parts, https or `data:` URLs, 20 per message). Audio and video are refused — their cost cannot be bounded before the fill
- Tool calling works end to end — `tools`, `tool_choice`, `tool_calls`, `role: "tool"`, buffered and streamed. Sampling parameters (`temperature`, `stop`, `seed`, `response_format`, `top_k`, …) pass through to the provider untouched. `best_of` is refused with a 400 — it multiplies generated tokens with no way to count them, so it cannot be reserved honestly. So are `plugins`, `web_search_options`, `modalities`, `audio` and `image_config`, which are priced upstream outside token usage. `n` up to 8 is supported and every choice comes back, buffered or streamed; each is billed
- `min_tokens_per_sec` / `max_seconds` on a request ask for a route that finishes: a route known to decode slower is skipped even if it is cheaper, and the cheapest of the rest fills. 503 `unmet_speed` if every route is known to be slower. `bu0y.speed_floor` in the response says `verified` or `unverified` (the filling route had no record yet)
- Everything Bu0y adds is optional and additive: extra request fields can be omitted or sent via `extra_body`, and extra response data sits in `bu0y` and inside `error`, which SDKs ignore. SDKs retry on HTTP status, not `error.type`: a 400 is final until you change `max_tokens`; a 503 gets the SDK's own backoff
- Use catalog model slugs (`kimik3`, `gpt4o`, …) from /models
- `/v1/models` prices include margin — what you pay, not our cost. `input` / `output` carry the low, average and high across every source quoting that model. If the cheapest source cannot serve you, a dearer one may fill; set `max_input_per_1m` / `max_output_per_1m` to bound that (or `max_price_multiple`, at most N times the cheapest print on the model's book), or price the exact request with `/v1/quote`
- Reasoning models can spend a small `max_tokens` entirely on thinking and return `content: ""` with `finish_reason: "length"` — check `reasoning_tokens`, and use `max_tokens` ≥ 128
- Prompt caching is automatic on models whose market prices it: repeat a byte-identical prompt prefix (system prompt, earlier turns, tool schemas — volatile content last) and the cached slice bills at the cache-read rate, typically about a tenth of the input price. `usage.prompt_tokens_details.cached_tokens` reports the hit. Nothing to enable, no `cache_control`
- Per-request history is `GET /v1/account/usage`. Signed-in desk also shows your points handle and rank.
- Public points: [Points](https://bu0y.com/points). One point is one cent billed. Handles are hashes. $BU0Y would count this sheet.
- Nothing fills under the margin floor (503). If a smaller ceiling would have worked, `error.retry_max_tokens` says exactly which — retry there rather than giving up on the model
- Routing is source-blind. No response names a marketplace, or shows what one charged us. Every fill carries `market` and `available` price ranges in `bu0y` instead: `billed_micros == available.low` means you were filled at the best price purchasable
- Bu0y does not store prompts or completions. Billing metadata only. The marketplace that fills still receives the prompt.
- Full errors / Hermes YAML / agent mint: [llms-full.txt](https://bu0y.com/llms-full.txt)

## FAQ

**How is this different from OpenRouter?**
OpenRouter is a catalog of official APIs behind one key. Bu0y shops inference marketplaces on every request and fills at the cheapest source that can actually deliver. Prepaid USDC. Source-blind. Nothing fills under the margin floor.

**Why prepaid?**
No tab. We reserve the worst-case bill before a fill runs. Credits are usage rights. Not a balance you can withdraw. Not a refund.

**Can I pick which marketplace fills?**
No. Cheapest survivor that clears policy wins. The response does not name the source. That is the product.

**What is 402 vs 502?**
402 means the reserve for your `max_tokens` is bigger than your balance. Fund the account or lower the ceiling. 502 means the marketplaces failed. Retry. They are not the same error.

**Do you store prompts?**
No. Billing metadata only: tokens, prices, timestamps. The marketplace that fills still receives the prompt, because it has to run it.

**What are points?**
Fill spend as points at [Points](https://bu0y.com/points). Handles are hashes, not names or wallets. One point is one cent. $BU0Y would count this sheet. Sign in to see yours.

**Where do I get help?**
Discord. That is the support channel: https://discord.gg/85ebxAjKgz

## Changelog

**2026-09-02 — slow and broken fills.** Three things a client can see:

- Briefly this afternoon a large `max_tokens` was refused up front with a 400 (`unservable_max_tokens`) when the model's recent speed could not finish it inside the ceiling. Withdrawn the same day: a ceiling is not a forecast, and it cost agent loops a 400 and a retry on every request. A long answer that reaches the wall is handled by the wall, not refused in advance.
- Timeout errors now say which clock ran out, including when it was the source's own gateway giving up before the first byte.
- New request hints `min_tokens_per_sec` and `max_seconds`: pay more for a route that finishes. A route whose recent decode speed is slower is skipped even when cheapest; 503 `unmet_speed` when no route is known to qualify.
- A broken stream can carry a charge. If the provider stops mid-answer, the closing error frame includes `bu0y.billed_micros` and `bu0y.completion_tokens` for the output that reached you. Read the error frame rather than assuming an errored stream was free, and keep the partial output. A stream that breaks before any output still costs nothing.
- Fills can run longer. The absolute ceiling is 480s, up from 300s, and mid-answer silence is judged per model between 20s and 180s. A client-side timeout should be longer than 480s, or you will hang up on fills that would have finished and be billed for what was delivered.

Everything else in that release is internal and needs nothing from you.

## Full reference

https://bu0y.com/llms-full.txt
