Skip to main content

API Reference

The Novin Cloud AI API is fully compatible with the OpenAI standard. Any library or tool that works with OpenAI connects to Novin Cloud by changing only the base_url and api_key.

Base URL​

https://iapi.novin.cloud/v1

Authentication​

Pass the API key in the Authorization header:

Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxx

To create a key, see API Keys.

Connecting official libraries​

Python
from openai import OpenAI

client = OpenAI(
api_key=os.environ["NOVIN_API_KEY"],
base_url="https://iapi.novin.cloud/v1",
)
Node.js / TypeScript
import OpenAI from "openai";

const client = new OpenAI({
apiKey: process.env.NOVIN_API_KEY,
baseURL: "https://iapi.novin.cloud/v1",
});
LangChain
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
model="openai/gpt-4o",
api_key=os.environ["NOVIN_API_KEY"],
base_url="https://iapi.novin.cloud/v1",
)
Environment variables (no code changes)

Many tools read these two variables:

export OPENAI_API_KEY="sk-xxxxxxxxxxxx"
export OPENAI_BASE_URL="https://iapi.novin.cloud/v1"

POST /v1/chat/completions​

The primary endpoint for conversing with models.

Main parameters​

ParameterTypeRequiredDescription
modelstring✅The model ID, e.g. openai/gpt-4o
messagesarray✅The array of conversation messages
streamboolean❌Receive the response incrementally (default false)
max_tokensinteger❌Maximum tokens in the response
temperaturenumber❌Degree of creativity, between 0 and 2 (default 1)
top_pnumber❌Nucleus sampling, between 0 and 1
stopstring | array❌Strings that, when encountered, stop generation
toolsarray❌Definitions of callable functions
response_formatobject❌Force output to JSON

messages structure​

[
{"role": "system", "content": "تو یک دستیار فارسی‌زبان هستی."},
{"role": "user", "content": "سلام"},
{"role": "assistant", "content": "سلام! چطور می‌توانم کمک کنم؟"},
{"role": "user", "content": "پایتخت ایران کجاست؟"}
]
RoleUse
systemSets the model's overall behavior — placed at the start of the array
userThe user's message
assistantThe model's previous response, used to preserve history

temperature guide​

ValueBehaviorSuitable for
0 to 0.3Precise and reproducibleData extraction, classification, factual answers
0.7 to 1.0BalancedGeneral conversation
1.2 to 2.0Creative and variedBrainstorming, storytelling

Example request​

curl https://iapi.novin.cloud/v1/chat/completions \
-H "Authorization: Bearer $NOVIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o",
"messages": [
{"role": "system", "content": "تو یک دستیار فارسی‌زبان هستی."},
{"role": "user", "content": "سه نکته برای یادگیری برنامه‌نویسی بگو"}
],
"temperature": 0.7,
"max_tokens": 500
}'

Response structure​

{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1750000000,
"model": "openai/gpt-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "متن پاسخ مدل..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 25,
"completion_tokens": 150,
"total_tokens": 175
}
}

finish_reason values​

ValueMeaning
stopThe response finished naturally
lengthHit the max_tokens cap — the response is incomplete
tool_callsThe model has requested a function call
content_filterContent was blocked by the safety filter

Streaming​

With stream: true, the response is sent as Server-Sent Events.

Each line begins with data: , and the end of the stream is marked with data: [DONE]:

data: {"choices":[{"delta":{"content":"سلام"}}]}

data: {"choices":[{"delta":{"content":" دنیا"}}]}

data: [DONE]

With the official library​

stream = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "یک شعر کوتاه بگو"}],
stream=True,
)

for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)

Manual handling in JavaScript​

const response = await fetch(
"https://iapi.novin.cloud/v1/chat/completions",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: "openai/gpt-4o",
messages: [{ role: "user", content: "سلام" }],
stream: true,
}),
}
);

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";

while (true) {
const { done, value } = await reader.read();
if (done) break;

buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() ?? "";

for (const line of lines) {
if (!line.startsWith("data: ")) continue;
const data = line.slice(6).trim();
if (data === "[DONE]") break;

const chunk = JSON.parse(data);
const delta = chunk.choices?.[0]?.delta?.content;
if (delta) process.stdout.write(delta);
}
}
note

In streaming mode, the usage field is usually sent at the end of the stream. For an accurate usage report, see the Usage page.


GET /v1/models​

The list of models available to your key.

curl https://iapi.novin.cloud/v1/models \
-H "Authorization: Bearer $NOVIN_API_KEY"
{
"object": "list",
"data": [
{
"id": "openai/gpt-4o",
"object": "model",
"created": 1750000000,
"owned_by": "openai"
}
]
}

The id value is exactly what you should send in the model parameter.


JSON output​

To get a structured, machine-readable response:

response = client.chat.completions.create(
model="openai/gpt-4o",
messages=[
{"role": "system", "content": "خروجی را فقط به صورت JSON بده."},
{"role": "user", "content": "نام و پایتخت سه کشور آسیایی"},
],
response_format={"type": "json_object"},
)
tip

When using response_format, also mention the word "JSON" in the system message so the model produces a more correctly structured output.


Function calling​

Models with this capability can determine that, in order to respond to the user, a function on your side needs to be called.

tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "دریافت وضعیت آب و هوای یک شهر",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "نام شهر"}
},
"required": ["city"],
},
},
}]

response = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "هوای تهران چطوره؟"}],
tools=tools,
)

tool_call = response.choices[0].message.tool_calls[0]
print(tool_call.function.name) # get_weather
print(tool_call.function.arguments) # {"city": "تهران"}

The model doesn't execute the function itself; it only indicates which function should be called with which inputs. Executing the function and returning the result to the model is your responsibility.

For the list of models that support this capability, see Models.


Error codes​

CodeMeaningAction
400Invalid requestCheck the messages structure and parameters
401Invalid keyCheck the key; it may have been deleted or expired
402Insufficient balanceTop up your wallet
404Model not foundMatch the model ID against /v1/models
429Rate limit exceededWait, or increase the key's RPM/TPM limit
500 / 502 / 503Service-side errorRetry with increasing delay

Smart retries​

For 429 and 5xx errors, retry with exponential backoff:

import time
from openai import RateLimitError, APIError

def ask_with_retry(messages, model="openai/gpt-4o", retries=4):
for attempt in range(retries):
try:
return client.chat.completions.create(
model=model, messages=messages
)
except (RateLimitError, APIError):
if attempt == retries - 1:
raise
time.sleep(2 ** attempt) # 1, 2, 4, 8 seconds
warning

Do not retry 401, 402, and 404 errors — these errors aren't resolved by retrying and only add unnecessary load.

Next steps​