Documentation
SparrowCodes speaks OpenAI's Chat Completions and Responses APIs and Anthropic's Messages API. Any OpenAI or Anthropic SDK, or tool that lets you set a base URL, works.
Quickstart
- Create an account and add credits from the Credits page.
- Create an API key under API keys. It is shown once, so store it in your secret manager.
- Set the base URL to
https://api.sparrowcodes.com/v1and use the key as the bearer token.
export SPARROW_API_KEY="sk-sc-v1-…"
curl https://api.sparrowcodes.com/v1/chat/completions \
-H "Authorization: Bearer $SPARROW_API_KEY" \
-d '{"model":"anthropic/claude-sonnet-5.5","messages":[{"role":"user","content":"Hello"}]}'Authentication
Send Authorization: Bearer sk-sc-v1-… on every request. Keys belong to your account and spend from its balance. You can give a key a lifetime or monthly spending limit (monthly limits reset on the 1st, UTC), and disable it at any time; a disabled key is rejected within a second. Over the limit, requests fail with 402 key_limit_reached.
Anthropic SDKs send the key as x-api-key instead; that works too. Keys start with sk-sc-v1- so secret scanners can recognise them: if GitHub finds one of your keys in public code, we disable it within seconds, email the account's owners and admins, and send a key.leaked webhook.
Until an account makes its first top-up it can make 20 requests per minute, and one request can cost at most $0.50. Both limits lift after the first payment.
SDKs and tools
Point any OpenAI-compatible client at https://api.sparrowcodes.com/v1 and use a SparrowCodes model id, which always includes the provider (anthropic/claude-sonnet-5.5).
# pip install openai
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.sparrowcodes.com/v1", api_key=os.environ["SPARROW_API_KEY"])
reply = client.chat.completions.create(
model="anthropic/claude-sonnet-5.5",
messages=[{"role": "user", "content": "Hello"}],
)
print(reply.choices[0].message.content)Coding tools that accept an OpenAI-compatible provider work the same way:
- Claude Code
- Set
ANTHROPIC_BASE_URL=https://api.sparrowcodes.comandANTHROPIC_AUTH_TOKENto your key. See Anthropic API and Claude Code. - Cline
- Settings → API Provider:
OpenAI Compatible. Base URLhttps://api.sparrowcodes.com/v1, your SparrowCodes key, and a model id such asanthropic/claude-sonnet-5.5. - Continue
- Add a model to
config.yamlwithprovider: openai,apiBase: https://api.sparrowcodes.com/v1,apiKeyandmodel: anthropic/claude-sonnet-5.5. - Aider
aider --model openai/anthropic/claude-sonnet-5.5 --openai-api-base https://api.sparrowcodes.com/v1 --openai-api-key $SPARROW_API_KEY- Cursor
- Settings → Models: enter your SparrowCodes key as the OpenAI API key, turn on Override OpenAI Base URL with
https://api.sparrowcodes.com/v1, and add the model id as a custom model. Some Cursor features always use Cursor's own models.
Chat completions
POST /chat/completions takes the same body as OpenAI: messages, tools, tool_choice, response_format, max_tokens or max_completion_tokens, reasoning_effort, stop and stream. Use a model id from the models page, such as openai/gpt-6.1-sol or x-ai/grok-4.7.
Providers differ. When a model does not support an option you sent, we remove it and tell you in the X-Sparrow-Warning response header instead of failing the request. For example, current Claude models ignore temperature.
Reasoning text, when a model returns it, arrives in message.reasoning (or delta.reasoning when streaming).
Streaming
Set "stream": true to receive server-sent events in OpenAI's chunk format, ending with data: [DONE]. The last chunk before [DONE] has empty choices and a usage object with the cost. If you disconnect early you are charged for what was generated up to that point.
Anthropic API and Claude Code
POST /v1/messages speaks Anthropic's Messages API, including streaming events, tools, images, PDFs, extended thinking and cache_control prompt caching. Use the Anthropic SDKs, or anything built on them, by changing the base URL to https://api.sparrowcodes.com. When the request goes to Claude, the body you sent reaches Anthropic unchanged; other models get a translation, so you can run Claude tools on any model.
# Claude Code export ANTHROPIC_BASE_URL="https://api.sparrowcodes.com" export ANTHROPIC_AUTH_TOKEN="sk-sc-v1-…" export ANTHROPIC_MODEL="anthropic/claude-sonnet-5.5" claude
# Python: pip install anthropic
import anthropic
client = anthropic.Anthropic(base_url="https://api.sparrowcodes.com", api_key="sk-sc-v1-…")
msg = client.messages.create(
model="claude-sonnet-5-5", # Anthropic's own ids work, as do ours
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)Model names can be ours (anthropic/claude-sonnet-5.5) or the provider's own (claude-sonnet-5-5, with or without a date suffix). usage follows Anthropic's shape and adds cost in USD. POST /v1/messages/count_tokens returns an estimate. Errors use Anthropic's error shape, so the SDKs raise their usual exceptions.
Responses API
POST /v1/responses speaks OpenAI's Responses API, so client.responses.create and tools built on it work with any model, streamed or not, with function calling and structured output (text.format).
from openai import OpenAI client = OpenAI(base_url="https://api.sparrowcodes.com/v1", api_key="sk-sc-v1-…") r = client.responses.create(model="google/gemini-3.5-flash", input="Hello", instructions="Be brief.") print(r.output_text)
It is stateless: we do not store responses, so previous_response_id and conversation are refused. Send the whole conversation in input, including earlier function_call and function_call_output items. Built-in tools such as web search are not available; define them as function tools.
Fallback models
Add models with up to five alternatives. If the first model fails before it starts answering, because a provider is down, rate-limited or overloaded, we try the next one. Errors caused by your request, such as invalid JSON in a tool call, are returned straight away.
{
"model": "anthropic/claude-sonnet-5.5",
"models": ["openai/gpt-6.1-sol", "x-ai/grok-4.7"],
"messages": [{"role": "user", "content": "…"}]
}The response headers X-Sparrow-Model and X-Sparrow-Provider show which one answered.
Provider routing
Many models are served by more than one provider (for example openai/gpt-oss-120b on Groq, Together and Fireworks, or Claude on Anthropic and Amazon Bedrock). By default we try them in our order and move a provider to the back while it is failing. Add a provider object to choose for yourself. It works on /chat/completions, /messages and /responses.
{
"model": "openai/gpt-oss-120b",
"messages": [{"role": "user", "content": "…"}],
"provider": {
"sort": "throughput", // or "price", "latency"
"order": ["groq", "together"], // try these first, in this order
"ignore": ["fireworks"], // never use these
"data_collection": "deny", // skip providers that may train on prompts
"max_price": {"prompt": 1, "completion": 4}, // USD per 1M tokens
"allow_fallbacks": true // false: only the first matching provider
}
}| Field | Meaning |
|---|---|
| sort | price cheapest first; latency lowest median time to first token over the last 7 days; throughput most tokens per second. |
| order | Providers to try first, in order. Others follow unless allow_fallbacks is false. |
| only / ignore | Allow-list or block-list of provider slugs. |
| data_collection | deny skips providers whose terms let them train on API data. |
| max_price | Skip providers above these input (prompt) or output (completion) prices. |
| allow_fallbacks | Default true. False sends the request to one provider only. |
If nothing matches, the request fails with 503 no_provider_matches and the message lists what was left out and why. The request log in your dashboard shows every attempt and the preferences that applied.
Auto routing
Set "model": "sparrow/auto" and we pick a model for each request: fast, low-cost models for short everyday prompts, and stronger ones when the request is long, includes code, uses tools, asks for high reasoning effort or looks like a hard analytical task. Requests with images only go to vision models, and requests with tools only to models that can call them.
You pay the chosen model's price. X-Sparrow-Model says which model answered, X-Sparrow-Auto-Tier the tier it started from (1 fast, 2 balanced, 3 frontier) and X-Sparrow-Auto-Reason why. If that model is unavailable, the next one in the tier answers.
Response cache
Send X-Sparrow-Cache: on (or "cache": true in the body) and an identical request from your account is answered from our cache instead of calling the model again. Cache hits are free, return in milliseconds, and are marked X-Sparrow-Cache: HIT with usage.cache_hit and usage.saved.
Entries last an hour by default; set X-Sparrow-Cache-TTL in seconds (up to 24 hours). The cache is per account and keyed on the whole request (model, messages, tools and options), so change any of them for a fresh answer. Use it for deterministic work such as classification, extraction or repeated prompts in tests, not for creative replies you want to vary.
curl https://api.sparrowcodes.com/v1/chat/completions \
-H "Authorization: Bearer $SPARROW_API_KEY" \
-H "X-Sparrow-Cache: on" \
-d '{"model":"sparrow/auto","messages":[{"role":"user","content":"Classify: refund request or bug report? …"}]}'Privacy
We don't store chat prompts or answers; usage records keep the model, token counts, cost and timing. Two controls in Settings → Privacy go further:
Mask personal data replaces email addresses, card numbers, phone numbers and secret keys in chat, image and video prompts with [EMAIL], [CARD], [PHONE] and [SECRET] before the request reaches the provider. To mask a single request instead, send X-Sparrow-Redact: on. Responses report the number of masked values in X-Sparrow-Redactions. Matching is pattern based, so treat it as a safety net rather than a guarantee.
Zero retention also stops us storing video prompts and turns off the response cache: requests sent with X-Sparrow-Cache: on go to the provider and return X-Sparrow-Cache: BYPASS.
Your own provider keys
Add your own Anthropic, OpenAI or xAI key in Settings → Provider keys and chat requests to that provider go through your key: they count against your provider quota and the provider bills you directly. We charge a small share of the model's list price per request from your credits, shown on that page, and responses carry X-Sparrow-BYOK: on.
Each key is checked with the provider before it is saved and stored encrypted. If the provider later rejects it, requests fail with 424 provider_key_rejected rather than quietly switching to our key. Speech, image and video models always use our keys.
Usage and cost
Every response includes usage.cost in US dollars, along with token counts and prompt_tokens_details.cached_tokens. Before a request starts we reserve its worst-case cost from your balance and release the unused part when it ends, so a request is refused up front rather than cut off halfway.
Each response has an X-Generation-Id header. Look it up with GET /generation?id=… for latency, provider and fallback details.
Text to speech
POST /audio/speech follows OpenAI's format, so client.audio.speech.create() works unchanged. Send model, voice, input, and optionally response_format (mp3, wav, flac, opus or pcm) and speed (0.5 to 2). The response is the audio file.
curl https://api.sparrowcodes.com/v1/audio/speech \
-H "Authorization: Bearer $SPARROW_API_KEY" \
-d '{"model":"kitten/tts-mini","voice":"Jasper","input":"Hello!"}' \
--output hello.mp3Every account gets free characters each day; after that you pay per character. GET /audio/models lists models, prices and free allowances, and GET /audio/voices?model= lists voices. Response headers show X-Sparrow-Characters, X-Sparrow-Cost-Inr and X-Sparrow-Free-Characters-Left.
Embeddings
POST /embeddings takes OpenAI's body: model, input as a string or an array of up to 2,048 strings, and optional dimensions and encoding_format (float or base64). You pay per input token at the provider's list price; the response's usage.cost shows what the call cost. List the models with GET /models?type=embedding.
curl https://api.sparrowcodes.com/v1/embeddings \
-H "Authorization: Bearer $SPARROW_API_KEY" \
-d '{"model":"openai/text-embedding-3-small","input":["first document","second document"]}'Errors
| Status | Type | What to do |
|---|---|---|
| 400 | invalid_request | Fix the request body; the message names the field. |
| 401 | invalid_api_key | Check the key, or whether it was disabled. |
| 402 | insufficient_credits | Add credits, or lower max_tokens. |
| 402 | key_limit_reached | Raise the key's spending limit or use another key. |
| 402 | trial_request_too_large | Before your first top-up a request can cost at most $0.50. Lower max_tokens or add credits. |
| 404 | model_not_found | Use an id from GET /models. |
| 429 | rate_limited | Slow down and retry after a few seconds. |
| 502 | provider_error | Every provider failed. Retry, or add fallback models. |
| 503 | no_provider_matches | Your provider preferences left nothing to call. Loosen them. |
Other endpoints
GET /models: models you can call now, with prices in USD (and INR). No key needed. Add?type=allfor speech, image and video models.GET /credits: your current balance.GET /key: the calling key's name, limit and spend.GET /generation?id=: details of one request.