Documentation
Everything you need to point your code at 400+ models. If you already use the OpenAI SDK, change base_url and nothing else changes.
curl https://api.uttapen.ir/v1/chat/completions \
-H "Authorization: Bearer sk-up-…" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5",
"messages": [{"role": "user", "content": "Introduce yourself in one sentence."}],
"stream": true
}'from openai import OpenAI
client = OpenAI(
base_url="https://api.uttapen.ir/v1",
api_key="sk-up-…",
)
stream = client.chat.completions.create(
model="openai/gpt-5",
messages=[{"role": "user", "content": "Introduce yourself in one sentence."}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="", flush=True)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.uttapen.ir/v1",
apiKey: "sk-up-…",
});
const stream = await client.chat.completions.create({
model: "openai/gpt-5",
messages: [{ role: "user", content: "Introduce yourself in one sentence." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}<?php
// composer require openai-php/client guzzlehttp/guzzle
$client = OpenAI::factory()
->withBaseUri('https://api.uttapen.ir/v1')
->withApiKey('sk-up-…')
->make();
$result = $client->chat()->create([
'model' => 'openai/gpt-5',
'messages' => [['role' => 'user', 'content' => 'Introduce yourself in one sentence.']],
]);
echo $result->choices[0]->message->content;package main
import (
"context"
"fmt"
"github.com/openai/openai-go"
"github.com/openai/openai-go/option"
)
func main() {
client := openai.NewClient(
option.WithBaseURL("https://api.uttapen.ir/v1"),
option.WithAPIKey("sk-up-…"),
)
resp, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Model: "openai/gpt-5",
Messages: []openai.ChatCompletionMessageParamUnion{openai.UserMessage("Introduce yourself in one sentence.")},
})
if err != nil {
panic(err)
}
fmt.Println(resp.Choices[0].Message.Content)
}Getting started
- Quickstart — your first API call in 5 minutesSign up with a phone number, top up your toman wallet, create an sk-up key, and make your first model call with the official OpenAI SDK.
- API keys and authenticationHow sk-up keys work — the Authorization and X-API-Key headers, per-key spending limits, model allow-lists, rate limits, expiry and instant revocation.
- Migrate from OpenAI, OpenRouter or Azure OpenAIMove existing code to uttapen by changing base_url and key — model id format, supported endpoints, fields that pass through, and common mistakes.
Capabilities
- Streaming responses with SSEStream output token by token with stream=true: SSE event format, the uttapen.meta cost event, client disconnects, and proxying from Next.js or Laravel.
- Tool calling (function calling)Declare tools with the OpenAI schema, run the full tool-call loop in Python, steer the model with tool_choice, and accumulate tool_calls while streaming.
- Vision: image and PDF inputSend images by URL or data URI and PDFs as a file part in chat/completions: picking a model, the 20 MB body limit, and how image usage is charged.
- Structured output: JSON and JSON SchemaGet valid JSON out of any model with response_format json_object or json_schema, in Python and Node, plus the Persian-text pitfalls that break parsers.
- Reasoning models: effort, tokens, costDrive o3, DeepSeek R1 and friends with reasoning_effort or the reasoning block, read reasoning tokens in response and stream, and budget the hold.
API reference
- Error codes — 400 to 504 and what to doEvery uttapen API error from 400 to 504 — the JSON shape, what each code means, whether it costs you anything, and how the OpenAI SDKs raise it.
- Rate limits — per-minute, streams and quotasPer-key requests per minute, the X-RateLimit and Retry-After headers, the concurrent stream cap, free-model daily quotas and a correct backoff example.
- LLM API pricing in toman: pay only for real token usagePer-million-token prices in toman, charging on each request's real usage, free failed requests, the hold-and-settle cycle, and the usage report API.
- API privacy: what uttapen stores and what it never logsThe API path never stores prompts or responses. Exactly which metadata is kept, the dashboard chat exception, and how traffic reaches the provider.
SDKs and tools
- Python SDKOfficial openai Python package with uttapen: install, client, chat, streaming with uttapen.meta, tool calling, embeddings, async and error handling.
- Node.js SDKOfficial openai package for Node.js and TypeScript with uttapen: client, cost headers, streaming, AbortController, tool calling, embeddings, errors.
- PHP SDK (Laravel and openai-php)openai-php/client and Guzzle with uttapen in PHP and Laravel: client, chat, cost headers, streaming, tool calling, embeddings and error handling.
- Go SDKOfficial openai-go package with uttapen: client, chat, streaming with the accumulator and uttapen.meta, tool calling, embeddings, openai.Error handling.
- curl and raw HTTP: use the uttapen API without an SDKCall every uttapen endpoint with curl: chat, streaming with -N, cost and rate-limit headers, uttapen.meta, embeddings, models, usage and a deploy check.
- LangChain, LlamaIndex, Vercel AI SDK, Cursor and Open WebUIPoint LangChain, LlamaIndex, Vercel AI SDK, Cursor, Continue and Open WebUI at uttapen with one base URL and an sk-up- key. Verified configs.