Shared Inference (api.cyan.kiwi/v1)

cyankiwi Shared Inference serves a curated set of open models behind one OpenAI-compatible endpoint, billed per token. To make your first request with curl or the OpenAI SDK, see the API Usage guide.

Base URL:  https://api.cyan.kiwi/v1

Zero data retention. Your prompts and the completions we return are not stored at any point in serving, and they are never used for training. We keep only usage metadata for each request (tokens, cost, timing and status) for billing. See the Privacy Notice for details.


Credits and rate limits

Requests are billed per token from your prepaid credits, and each API key has per-minute rate limits. Both are shown on the Account tab. A new account starts with a zero balance, so add credits there before your first request. Closing the connection cancels the request, whether streaming or non-streaming.

Models

The model catalog at GET /v1/models is public: no API key required (one sent along is simply ignored), and responses can be cached briefly. It lists only models available to customers.

The response is a standard OpenAI model list whose items carry extra metadata you can rely on programmatically:

Field Meaning
id the value to pass as model in requests
context_length, max_output_length token budgets of the model
pricing USD per token as exact decimal strings: prompt, completion, input_cache_read
quantization precision of the served weights (fp8, fp4, …)
input_modalities, output_modalities what the model accepts and returns
supported_features, supported_sampling_parameters what the model supports (for example tools, json_mode, reasoning)
license the model’s license

Cached input. When a request hits the prompt cache, the cached input tokens bill at input_cache_read instead of prompt, and the hit shows up as usage.prompt_tokens_details.cached_tokens on the response. Caching granularity varies by model, and a hit is never guaranteed on any individual request.

The same ids are shown on the Inference tab of the workspace.

Streaming

Streams follow the standard OpenAI format and end in one of two ways:

  • Success: a final usage chunk (empty choices) followed by data: [DONE], even without stream_options.include_usage.
  • Failure after the response has started: one server_error / mid_stream_error frame, then the stream closes without [DONE].

A stream that closes without [DONE] did not complete, even if no error frame arrived. During silent phases, SSE keep-alive comments (: keepalive) may arrive; SSE parsers skip them.

Request limits

A request that exceeds one of these is rejected, not trimmed. It never runs and it is never charged.

limit applies to if exceeded
Request body 2 MiB all routes 413 request_too_large
Chat messages must be a nonempty list of objects chat 400 invalid_request_body
Non-null max_tokens / max_completion_tokens must be integers; stream boolean; temperature, top_p, presence_penalty, frequency_penalty finite numbers (not booleans) chat + completions 400 invalid_request_body
Non-null n and best_of must be 1; omitted/null/1 allowed chat + completions 400 too_many_completions (invalid_request_body if not an integer)
prompt_token_ids and input_ids are not accepted; on completions, prompt must be text (a string, or a list of strings) chat + completions 400 token_ids_not_supported
chat_template_kwargs may not carry chat_template or tokenize chat 400 template_override_not_permitted
A JSON schema must be an object, and each entry under properties (and similar keyword maps) a schema object or a boolean response_format, tools 400 invalid_json_schema
regex, ebnf, guided_json, guided_regex, guided_grammar, guided_choice, guided_whitespace_pattern, guided_decoding_backend, structural_tag, prompt_embeds are not accepted chat + completions 400 unsupported_parameter

All of these errors have type invalid_request_error. When a field is refused, the param key of the error names it, so an SDK surfaces it directly. For an invalid tool schema, param is the tool’s path, for example tools[0].function.parameters.

n or best_of above 1 is refused with 400, not silently reduced to one choice.

Text completions are not currently served. /v1/completions answers 400 completions_not_supported unless a model declares support for it, and none does today. Use /v1/chat/completions. The limits in the table above still apply to the route, and are checked before that refusal. /v1/embeddings likewise answers 400 embeddings_not_supported, because no model supports embeddings today.

Token log-probabilities are not supported. logprobs, top_logprobs and prompt_logprobs with truthy values are rejected with 400 logprobs_not_supported rather than silently ignored, on every model. False, zero and null are no-ops.

Other unsupported parameters are dropped. A sampling parameter a model does not support is ignored rather than rejected, so check supported_sampling_parameters in the model catalog for what each model honors.

Errors

Errors use the standard OpenAI envelope, so SDK exception handling works unchanged. The error object carries message, type, param and code, and transient failures also carry a Retry-After header.

For example, a single-choice refusal is:

{"error":{"message":"Only n=1 is supported; omit 'n' or set it to 1","type":"invalid_request_error","param":"n","code":"too_many_completions"}}

An invalid-key response is:

{"error":{"message":"Invalid API key","type":"invalid_request_error","param":null,"code":"invalid_api_key"}}
Situation Status type code param
Malformed JSON / invalid field 400 invalid_request_error invalid_request_body or specific validation code field or null
Request rejected 400 invalid_request_error invalid_request field or null
Context too long 400 invalid_request_error context_length_exceeded messages
Content policy / refusal 400 invalid_request_error content_policy_violation null
Missing key 401 invalid_request_error missing_api_key null
Invalid / revoked key 401 invalid_request_error invalid_api_key null
Unknown or inaccessible model 404 invalid_request_error model_not_found model
Body too large 413 invalid_request_error request_too_large null
Credits exhausted 429 insufficient_quota insufficient_credits null
Key rate limit 429 rate_limit_error rate_limit_exceeded null
Server at capacity 429 rate_limit_error server_overloaded null
Model at capacity 429 rate_limit_error capacity_unavailable null
Internal failure 500 server_error internal_error null
Invalid response from the model 502 server_error model_error null
Service temporarily unavailable 503 service_unavailable_error service_unavailable null
Model timed out 504 server_error timeout null
Failure after the response started 200 already committed server_error mid_stream_error null

insufficient_credits and content_policy_violation are not transient: add credit or revise the request instead of retrying. For the other 429 and 5xx errors, honor Retry-After and retry. We shed load instead of queueing: at capacity you get an immediate server_overloaded 429 rather than a slow response.

A failure detected after the response has started sends one error frame and closes, with no [DONE]:

data: {"error":{"message":"The model could not complete this request","type":"server_error","param":null,"code":"mid_stream_error"}}

SDKs raise a base APIError on this frame, not an HTTP-status exception.

Key rotation. Rotating on the Account tab revokes the old key immediately and issues a new one. Your credits carry over, and the new key gets the current rate limits. Revoking without rotating just disables API access; remaining credits are kept for your next key.