Docs
Base URL
https://api.guttertokens.com
Authenticate with Authorization: Bearer sk-….
Keys are created in the dashboard, where you can copy one again at any time.
Create an account to get a key. Credits are prepaid; there is no subscription.
Machine-readable
API reference — every endpoint, parameter and error code, generated from two OpenAPI documents: /openapi.json for the relay (chat completions, messages, models), and /management.openapi.json for minting and managing keys without a browser. Point a client generator at whichever one matches what you are building, rather than copying from this page.
Building an agent that will drive this itself? /llms.txt is the same service written for one — the whole lifecycle, including how an agent mints its own keys, with the steps that need a human marked as such.
Models and prices
| Model | Input /MTok | Output /MTok |
|---|---|---|
| claude-opus-4-8 | $1.25 | $6.25 |
| claude-opus-5 | $1.25 | $6.25 |
| claude-sonnet-5 | $0.50 | $2.50 |
| claude-haiku-4-5-20251001 | $0.25 | $1.25 |
Billed on tokens delivered. A request that fails upstream is not charged. Prompt caching is billed separately: writing a prefix to cache costs 25% more than the input price above, and each read after that costs 90% less.
Paying by direct transfer
You can send stablecoins straight to an address we control, with no payment gateway in between and no fee. 1 USDC or 1 USDT becomes $1.00 of credit. Your address is shown on the billing page once you have enrolled a wallet.
Three things have to be true:
-
A network we watch. Today:
Ethereum — USDC and USDTBase — USDC, USDbC and USDTPolygon — USDC, USDC.e and USDT - One of those tokens, sent as a token transfer. Ether, POL and every other token are invisible to us — there is nothing we can read that says they arrived.
- Sent from a wallet you can sign for. It does not have to be enrolled, and it can arrive before you have an account: a transfer from an address we do not know is held until somebody proves they hold that key. You can send first and sign up afterwards with the same wallet, and the credit will be waiting. A withdrawal straight from an exchange is the one case this does not help with — it arrives from the exchange's own wallet, not yours, so you cannot sign for it. Write to us if you have already done that.
Credit lands once the transfer is final on the network you used. On Polygon that is about a minute; on Ethereum, Base and Arbitrum, finality takes roughly fifteen to twenty minutes, and we wait for it rather than guessing. Transfers under $0.50 are ignored.
A wallet is also a way to sign in. You can hold an account with a wallet and no email address at all — see the terms for what that means, in particular that such an account cannot be recovered if you lose the key.
Referrals
Your dashboard has a link with your own code on it. When someone signs up through it and their first deposit of $25 or more is credited, you get 15% of that deposit as credit, up to $50. If the deposit is $25 or more, they get $5 of credit as well.
Both sides are paid 7 days after that deposit is credited, not on the day it lands.
It pays once per person, on their first deposit only — not a share of everything they ever spend. Nothing is paid until a deposit actually clears, so a signup on its own earns nothing, and a first deposit under $25 earns nothing either.
Referral credit is issued rather than bought: it is not refundable, it cannot be paid out in cash, and we withhold or reverse it where a referral is not genuine — referring yourself, or funding the new account from a wallet already on your own. See the terms.
OpenAI SDK (Python)
from openai import OpenAI
client = OpenAI(
base_url="https://api.guttertokens.com/v1",
api_key="sk-...",
)
response = client.chat.completions.create(
model="claude-opus-4-8",
messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)Anthropic SDK (Python)
from anthropic import Anthropic
client = Anthropic(
base_url="https://api.guttertokens.com",
api_key="sk-...",
)
message = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
print(message.content[0].text)Claude Code
export ANTHROPIC_BASE_URL=https://api.guttertokens.com export ANTHROPIC_AUTH_TOKEN=sk-... claude
opencode
Paste into ~/.config/opencode/opencode.json,
merging with whatever is already there. Add one entry under
models per model you want in the picker.
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"gutter": {
"npm": "@ai-sdk/openai-compatible",
"name": "Gutter Tokens",
"options": {
"baseURL": "https://api.guttertokens.com/v1",
"apiKey": "sk-..."
},
"models": {
"claude-opus-4-8": { "name": "claude-opus-4-8" }
}
}
}
}
Restart opencode, then pick the model with /models —
or set "model": "gutter/claude-opus-4-8" at the top
level of the same file to make it the default.
npm must be
@ai-sdk/openai-compatible. The similarly named
@ai-sdk/openai sends
POST /v1/responses, which this API does not
support — every request then fails with a 500
even though the base URL, key and model are all correct.
Streaming
Set stream: true. Responses are server-sent
events and are not buffered — tokens arrive as they are produced.
curl https://api.guttertokens.com/v1/chat/completions \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "claude-haiku-4-5-20251001",
"messages": [{"role": "user", "content": "Count to ten"}],
"stream": true
}'Errors
Errors use the standard shape, so an SDK can branch on
error.type and error.code.
| Status | code | Meaning |
|---|---|---|
| 400 | invalid_request | Malformed body or parameters. |
| 401 | invalid_api_key | Key missing, wrong, or revoked. |
| 403 | insufficient_quota | Out of credit. Add credit and retry. |
| 429 | rate_limit_exceeded | Too many requests. Back off and retry. |
| 503 | model_unavailable | No capacity for that model right now. |
| 500 | internal_error | Something failed on our side. |
Limits
-
Concurrency and request-rate limits apply per source address. They
are set high enough for parallel agent workloads; a
429means back off and retry. - There is no ceiling on how long a single request may run. Long agentic turns are normal traffic.
- Spending is bounded by your prepaid balance, not by a rate limit.
Calling from a browser
-
Every
/v1/*response allows any origin, errors included, so a browser client can read both the answer and the failure.Retry-Afteris exposed on a429so you can back off on the real interval rather than guessing. - A key in a browser is visible to whoever is using it. Ship this only where the key belongs to the person typing it in — never with a key of your own embedded in the page.
Supported endpoints
-
POST /v1/chat/completions— OpenAI Chat Completions, streaming and non-streaming. -
POST /v1/messages— Anthropic Messages, streaming and non-streaming. -
GET /v1/models— the models your key can reach.