Client SDKs

OpenAI compatibility

The API is OpenAI-compatible, not OpenAI-identical. This page is the complete list of differences — everything that could surprise a client written against OpenAI.

Endpoints that do not exist#

404, not a different shape

embeddings, moderations, batches, legacy completions, fine_tuning, assistants and vector_stores. An SDK will report these as unknown routes.

Model ids#

Only upfyn-bala, upfyn-yuva and upfyn-rishi. OpenAI names are not aliased and return 400 unknown_model. If you are porting code, this is the one change you cannot skip.

Extra fields in responses#

We add fields rather than change existing ones, so a permissive client is unaffected. A strictly-typed one may hide them.

Additions
{
"id": "chatcmpl-...",
"choices": [ ... ],
"usage": {
"prompt_tokens": 18,
"completion_tokens": 42,
"total_tokens": 60,
"prompt_tokens_details": {
"cached_tokens": 0,
"cache_write_tokens": 0 // Upfyn addition
}
},
"credits_used": 0.31, // Upfyn
"credits_remaining": 4821.44, // Upfyn
"request_id": "req_...", // Upfyn
"session_id": null, // Upfyn
"upfyn_tag": null // Upfyn
}
  • Python: read them from response.model_extra.
  • TypeScript: cast, or read the raw response.

Behavioural differences#

DifferenceWhat happens
max_tokens and max_completion_tokens are mutually exclusiveSending both is 400 conflicting_parameters. Some SDK versions send both — send one.
Unknown body parameters are forwarded to the providerA parameter OpenAI accepts may be rejected by the upstream, so the 400 you see can come from further down the chain.
service_tier: "priority" on Rishi400 unsupported_parameter — that model has no priority tier. It works on Bala and Yuva.
Intermediate usage chunks are suppressed while streamingYou get exactly one usage chunk, at the end. Clients that sum every usage frame would otherwise double-count.
Speech rejects voice-cloning parametersRefused with a 400 rather than silently ignored.
Speech-to-text can 404Those routes are feature-flagged. An SDK reads the 404 as "endpoint does not exist".
SSE comment keepalivesFrames beginning : appear while a model is thinking. Conformant parsers ignore them; a hand-rolled parser must skip any line that is not data:.

Error types#

Some type values are ours: billing_error, auth_error, not_found, api_error. Branch on the HTTP status first — that is always meaningful — and on code second.

402 is the one to handle specially

OpenAI has no direct equivalent. It means out of credits, and no amount of retrying or re-authenticating will change that. An SDK's default retry policy will retry it; turn that off.

Porting a checklist#

  • Change base_url to https://ai.upfyn.com/v1.
  • Change every model id.
  • Set max_retries to 0 and handle retries yourself.
  • Remove any embeddings or moderations calls — there is no substitute here.
  • Send only one of max_tokens / max_completion_tokens.
  • Add stream_options.include_usage if you track cost on streaming calls.
  • Add a 402 branch.

Once those are done the rest of an OpenAI codebase generally runs unchanged. If something does not, it is worth telling us through Support — a compatibility gap we do not know about is a bug.