1. Get an API key
Create an account, then open API keys and create one. Accounts made with a phone get free tokens; the others run on credits after any free trial.
Your key
export DECUFFED_API_KEY=dc_sk_…
2. Send a request
- OpenAI base URL
https://api.decuff.ai/v1- Anthropic base URL
https://api.decuff.ai- Model
decuffed-flash
OpenAI curl
curl -N https://api.decuff.ai/v1/chat/completions \
-H "Authorization: Bearer $DECUFFED_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"decuffed-flash","stream":true,"messages":[{"role":"user","content":"Hello"}]}'
Models
GET /v1/models lists what your key can call. The names on the models page work too.
Claude Code and Codex
These keep the agent on decuffed-flash within the API’s limits: 4,096 output tokens, no separate thinking, function tools only.
Claude Code
export ANTHROPIC_BASE_URL=https://api.decuff.ai
export ANTHROPIC_AUTH_TOKEN=$DECUFFED_API_KEY
export ANTHROPIC_MODEL=decuffed-flash
export ANTHROPIC_DEFAULT_OPUS_MODEL=decuffed-flash
export ANTHROPIC_DEFAULT_SONNET_MODEL=decuffed-flash
export ANTHROPIC_DEFAULT_HAIKU_MODEL=decuffed-flash
export CLAUDE_CODE_MAX_CONTEXT_TOKENS=65536
export CLAUDE_CODE_MAX_OUTPUT_TOKENS=4096
export MAX_THINKING_TOKENS=0
claude
Codex · ~/.codex/config.toml
model = "decuffed-flash"
model_provider = "decuff"
model_reasoning_effort = "none"
model_reasoning_summary = "none"
model_context_window = 65536
web_search = "disabled"
[features]
multi_agent = false
[model_providers.decuff]
name = "decuff"
base_url = "https://api.decuff.ai/v1"
env_key = "DECUFFED_API_KEY"
wire_api = "responses"
Run codex with DECUFFED_API_KEY set. Codex ignores OPENAI_BASE_URL and would send your prompt to OpenAI, so set the provider as above. No web search, images or sub-agents.
SillyTavern and other apps
Any app with an OpenAI-compatible option works.
- API
- Chat Completion
- Chat Completion Source
- Custom (OpenAI-compatible)
- Custom endpoint
https://api.decuff.ai/v1- API key
- Your
dc_sk_ key - Model
decuffed-flash
Keep response length at 4,096 tokens or less. Web apps that call the API from another website are blocked by the browser.
curl only, or over Tor
Makes an account with no email or phone, saves its keys to decuff-account.json and sends a first message.
curl
API=https://api.decuff.ai
decuff() { curl -s "$@"; }
TERMS=$(decuff $API/v1/service | sed 's/.*"termsVersion":"\([^"]*\)".*/\1/')
(umask 077; decuff $API/v1/accounts -H "Content-Type: application/json" \
-d "{\"acceptedTerms\":\"$TERMS\"}" > decuff-account.json)
KEY=$(sed 's/.*"key":"\([^"]*\)".*/\1/' decuff-account.json)
decuff $API/v1/chat/completions -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"model":"decuffed-flash","messages":[{"role":"user","content":"Hello"}]}'
An account made this way gets only the free trial GET /v1/service lists as allowances.freeUnverifiedTokens (0 means none). Past that, calls return 402 until it has credits or a verified phone. To add either, sign in on the account page with the accessKey from the file.
The onion, vplomjjsd3hicadr6inrzu2uyykrqw4yc7wxjnjooj5smctmmpbhnkad.onion, serves this site and the same API with no cookies, Google sign-in or cards. Tor hides that you use decuff, not what you send to the model. On Whonix, drop --socks5-hostname.
Protocols
POST /v1/chat/completions- OpenAI Chat Completions: text, function tools, streaming.
POST /v1/responses- OpenAI Responses, stateless: send
store: false and the full history. Reasoning requested with include: ["reasoning.encrypted_content"] is bound to your account and model and lasts 24 hours. POST /v1/messages- Anthropic Messages: text, tool use, streaming.
POST /v1/messages/count_tokens- Exact input token count.
GET /v1/models- Models your key can use.
Text only. Chat Completions and Messages apply temperature and stop sequences and ignore other options (top_p, penalties, seed, n, response_format). Responses rejects an unsupported option with a 400 that names it.
Errors and limits
Errors are JSON: {"error":{"type":…,"message":…}}. A stream that fails partway ends with an event: error line carrying the same object.
400 | The request uses a field, size or feature the API doesn’t support. The message names it. |
401 | The API key is missing, wrong or revoked, or it’s an account key. Requests need a dc_sk_ key. |
402 | No credits or free tokens left for this request. Free-token refusals may say why in error.code: free_tokens_need_verification, free_trial_used or free_trial_capacity_exhausted. |
403 | Spending is paused, the call came from a browser on another website, or an API key was used on an account endpoint. |
404 | Wrong path. OpenAI base URLs end in /v1. |
429 | Too many requests, too many at once, or today’s wake time is used up. Wait for Retry-After. |
502 | The model stopped partway. Check usage before you retry. |
503 | A model or the service is offline or paused. Flash is always on. |
- Requests
- 30 a minute, 2 at once
- On free tokens
- 20 requests a minute
- Output
- 4,096 tokens per request
- Request
- 2 MB, 100 messages, 32 tools
If a connection drops, check usage before retrying: the request may have run.
Inspect the implementation
The source archive has the gateway, serving configuration and tests. Published source doesn’t prove what we run; see the privacy page.