The DeepFA AI API,
OpenAI-compatible
GPT, Claude, Gemini, Grok and DeepSeek behind one address and one key. Because the API is exactly the OpenAI standard, the libraries and tools you already have — the official Python and JavaScript clients, VS Code extensions, Cursor — connect to DeepFA by changing one base URL, and run on rial credit.
Change one URL and it works everywhere
OpenAI-compatible means the request and response shape of our API is exactly the OpenAI standard — not that we only serve OpenAI models. So anything built for OpenAI — your own code, a server, a mobile app, an automation, the VS Code extensions, Cursor — connects by changing one base URL and runs GPT, Claude, Gemini, Grok and DeepSeek on a rial-denominated balance.
curl https://deepfa.ir/api/v1/chat/completions \ -H "Authorization: Bearer $DEEPFA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6-luna", "messages": [{"role": "user", "content": "سلام"}] }'
from openai import OpenAI client = OpenAI( api_key="YOUR_DEEPFA_KEY", base_url="https://deepfa.ir/api/v1", ) answer = client.chat.completions.create( model="claude-sonnet-5", messages=[{"role": "user", "content": "سلام"}], ) print(answer.choices[0].message.content)
import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_DEEPFA_KEY", baseURL: "https://deepfa.ir/api/v1", }); const answer = await client.chat.completions.create({ model: "gemini-3.8-flash", messages: [{ role: "user", content: "سلام" }], });
The endpoints
| POST | /chat/completions | Chat, with streaming and tool calling |
| POST | /responses | OpenAI's Responses API, for Codex and OpenAI models |
| POST | /messages | Anthropic's Messages API, for Claude Code and Claude models |
| POST | /messages/count_tokens | Count a Claude request's tokens, free |
| GET | /models | The models your key may call |
| GET | /balance | Balance and this key's ceilings |
| POST | /embeddings | Text to vectors, for search |
| POST | /images/generations | Image generation |
| POST | /images/edits | Image to image |
| POST | /audio/transcriptions | Speech to text |
| POST | /audio/speech | Text to speech |
| POST | /videos | Video from text, an image or a video |
| GET | /videos/{id} | How a video is getting on |
| GET | /videos/{id}/content | The finished video |
| POST | /music | A song with lyrics and vocals, or instrumental |
| GET | /music/{id} | How a song is getting on, and its lyrics |
| GET | /music/{id}/content | The finished song |
| POST | /podcasts | A one- or two-voice podcast from a script |
| GET | /podcasts/{id} | How a podcast is getting on, and its transcript |
| GET | /podcasts/{id}/content | The finished podcast |
| POST | /agents/runs | Start an agent: research, analysis or a site |
| GET | /agents/runs/{id} | A run: its status and files |
Every endpoint spends the same API credit: chat and embeddings by the tokens they use, images per image, video by length and resolution, music per request, transcription per minute and speech per character. What each call cost is returned in a response header and listed on your usage page.
The agents, from your own code
An agent takes a job from end to end: it searches the web, writes and runs code in a sandbox, and hands back an answer with the files it produced - a report, a chart, a spreadsheet or a finished web page. All three agents of the panel run from your own code with the same key.
One POST to /agents/runs with the agent and its input; you get a run id.
GET /agents/runs/{id} every few seconds; the status moves from processing to completed.
The answer and a list of files; each one has a URL you download with the same key.
curl https://deepfa.ir/api/v1/agents/runs \ -H "Authorization: Bearer $DEEPFA_API_KEY" \ -H "Content-Type: application/json" \ -d '{"agent":"research","input":{"topic":"...","depth":"standard","language":"fa"}}'
A run is charged when it finishes, from your API credit: the model it used, each web search and the sandbox session. A run that fails, is cancelled or produces nothing is not charged.
What each model costs
Per million tokens. The same work can cost twenty times more on one model than another, so it is worth reading before you choose one.
| Model | Maker's list price | Against the list price | Input | Cached input | Output | 1M in + 1M out |
|---|---|---|---|---|---|---|
| OpenAI | ||||||
| text-embedding-3-small openai | 0.02 USD | — | 50 | — | 0 | 0.0286 USD |
| text-embedding-3-large openai | 0.13 USD | — | 325 | — | 0 | 0.19 USD |
| gpt-6-luna openai | 0.60 USD | up to 57% less at least 17% in every plan | 75 | 7.5 | 375 | 0.26 USD |
| gpt-6.1-terra openai | 6.00 USD | up to 57% less at least 17% in every plan | 750 | 37.5 | 3,750 | 2.57 USD |
| gpt-6.1-sol openai | 12.00 USD | up to 57% less at least 17% in every plan | 1,500 | 75 | 7,500 | 5.14 USD |
| gpt-5.3-codex openai | 15.75 USD | up to 43% less | 1,750 | 175 | 14,000 | 9.00 USD |
| gpt-6-astra openai | 60.00 USD | up to 60% less at least 23% in every plan | 7,000 | 700 | 35,000 | 24.00 USD |
| Anthropic (Claude) | ||||||
| claude-haiku-5-5 anthropic | 0.60 USD | up to 14% less | 150 | 15 | 750 | 0.51 USD |
| claude-sonnet-5-5 anthropic | 12.00 USD | up to 43% less | 2,000 | 200 | 10,000 | 6.86 USD |
| claude-sonnet-5 anthropic | 12.00 USD | up to 39% less | 2,125 | 212.5 | 10,687.5 | 7.32 USD |
| claude-opus-5-5 anthropic | 24.00 USD | up to 43% less | 4,000 | 200 | 20,000 | 13.72 USD |
| claude-opus-5 anthropic | 30.00 USD | up to 43% less | 5,000 | 500 | 25,000 | 17.15 USD |
| claude-fable-5 anthropic | 60.00 USD | up to 43% less | 10,000 | 1,000 | 50,000 | 34.29 USD |
| claude-fable-5-1 anthropic | 60.00 USD | — | 25,000 | 625 | 125,000 | 85.73 USD |
| Google (Gemini) | ||||||
| gemini-3.7-flash google | 4.50 USD | up to 57% less at least 17% in every plan | 562.5 | 56.25 | 2,812.5 | 1.93 USD |
| gemini-3.8-flash google | 9.00 USD | up to 79% less at least 59% in every plan | 562.5 | 56.25 | 2,812.5 | 1.93 USD |
| gemini-3.1-pro-preview google | 14.00 USD | up to 59% less at least 21% in every plan | 1,250 | 125 | 8,750 | 5.72 USD |
| gemini-4-argon google | 12.00 USD | up to 43% less | 2,000 | 200 | 10,000 | 6.86 USD |
| xAI (Grok) | ||||||
| grok-4.3 xai | 3.75 USD | up to 43% less | 1,250 | 200 | 2,500 | 2.14 USD |
| grok-4.6 xai | 8.00 USD | up to 43% less | 2,000 | 500 | 6,000 | 4.57 USD |
| grok-4.7 xai | 8.00 USD | up to 43% less | 2,000 | 500 | 6,000 | 4.57 USD |
| DeepSeek | ||||||
| deepseek-flash deepseek | 1.50 USD | up to 43% less | 300 | 6 | 1,187.5 | 0.85 USD |
| deepseek-v4-pro deepseek | 5.28 USD | — | 3,250 | 108.25 | 9,875 | 7.50 USD |
| Perplexity | ||||||
| sonar perplexity | 2.00 USD | — | 2,500 | — | 2,500 | 2.86 USD |
| sonar-reasoning-pro perplexity | 10.00 USD | — | 5,000 | — | 20,000 | 14.29 USD |
The input and output columns are credits per million tokens. The money column is the same amount at the lowest price per credit (the largest API pack). "Up to" is the saving at the cheapest credit (the largest API pack, as in the money columns); "at least … in every plan" is the saving at the dearest credit any plan or pack sells. The list price is a million input plus a million output tokens on the maker's own site.
| Model | Maker's list price | Against the list price | Unit | Credits | USD |
|---|---|---|---|---|---|
| Images | |||||
| gpt-image-2.5-sunburst Images | 0.22 USD | up to 80% less at least 62% in every plan | per image | 75 | 0.0429 |
| gpt-image-2.5-flare Images | 0.22 USD | up to 80% less at least 62% in every plan | per image | 75 | 0.0429 |
| gpt-image-1 Images | 0.17 USD | — | per image | 625 | 0.36 |
| flux-3 Images | 0.048 USD | — | per image | 125 | 0.0714 |
| flux-3-klein Images | 0.009 USD | — | per image | 25 | 0.0143 |
| flux-schnell Images | 0.003 USD | — | per image | 25 | 0.0143 |
| nano-banana-2.1 Images | 0.0336 USD | up to 15% less | per image | 50 | 0.0286 |
| nano-banana-2-lite Images | 0.0336 USD | up to 15% less | per image | 50 | 0.0286 |
| Text to speech | |||||
| tts-1 Text to speech | — | — | per 1,000 characters | 37.5 | 0.0214 |
| tts-1-hd Text to speech | — | — | per 1,000 characters | 75 | 0.0429 |
| gpt-4o-mini-tts Text to speech | — | — | per 1,000 characters | 37.5 | 0.0214 |
| eleven-v4 Text to speech | — | — | per 1,000 characters | 200 | 0.11 |
| eleven-v4-turbo Text to speech | — | — | per 1,000 characters | 100.1 | 0.0572 |
| gemini-3.8-flash-lite-tts Text to speech | 0.0153 USD | up to 2% less | per 1,000 characters | 26.3 | 0.015 |
| Transcription | |||||
| gpt-transcribe Transcription | — | — | per minute | 11.25 | 0.0064 |
| whisper-1 Transcription | — | — | per minute | 15 | 0.0086 |
| gpt-4o-transcribe Transcription | — | — | per minute | 15 | 0.0086 |
| gpt-4o-mini-transcribe Transcription | — | — | per minute | 7.5 | 0.0043 |
| Video | |||||
| kling-3-turbo-pro Video | 0.70 USD | — | per 5-second clip | 1,425 | 0.81 |
| luma-ray-32 Video | 0.50 USD | — | per 5-second clip, 540p | 1,250 | 0.71 |
| grok-imagine-15 Video | 0.24 USD | up to 76% less at least 54% in every plan | per 3-second clip, 480p | 100 | 0.0571 |
| minimax-h3-max Video | 0.40 USD | up to 29% less | per 5-second clip, 768p | 500 | 0.29 |
| wan-30 Video | 0.25 USD | — | per 5-second clip, 480p | 500 | 0.29 |
| kling-3-pro Video | 0.84 USD | — | per 5-second clip | 1,700 | 0.97 |
| kling-o3 Video | 0.70 USD | — | per 5-second clip | 1,750 | 1.00 |
| google-veo-31 Video | 3.20 USD | up to 44% less | per 8-second clip, 720p | 3,125 | 1.79 |
| google-veo-31-fast Video | 1.20 USD | up to 64% less at least 31% in every plan | per 8-second clip, 720p | 750 | 0.43 |
| google-veo-31-lite Video | 0.40 USD | up to 46% less | per 8-second clip, 720p | 375 | 0.21 |
| seedance-25 Video | 1.10 USD | up to 8% less | per 5-second clip, 480p | 1,775 | 1.01 |
| kling-4 Video | 0.47 USD | — | per 3-second clip, 720p | 1,075 | 0.61 |
| kling-video-pro Video | 0.84 USD | — | per 5-second clip | 1,700 | 0.97 |
| kling-video-o3 Video | 0.70 USD | — | per 5-second clip | 1,750 | 1.00 |
| luma-dream-machine Video | 0.15 USD | — | per 5-second clip, 540p | 375 | 0.21 |
| wan-video-25 Video | 0.25 USD | — | per 5-second clip, 480p | 625 | 0.36 |
| bytedance-upscaler Video | 0.0072 USD | — | per second of video, 1080p | 20 | 0.0114 |
| happy-horse-edit Video | 0.28 USD | up to 29% less | per second of video, 720p | 350 | 0.20 |
| kling-o3-pro-edit Video | 0.17 USD | — | per second of video | 420 | 0.24 |
| grok-imagine-edit Video | 0.06 USD | — | per second of video, 480p | 150 | 0.0857 |
| Music | |||||
| suno-v6 Music | — | — | per request, 2 songs | 150 | 0.0857 |
| lyria-3.5 Music | — | — | per song | 250 | 0.14 |
| minimax-music-2.5 Music | — | — | per song | 375 | 0.21 |
Images, video, speech and transcription spend the same API credit, and the dollar column is at the lowest price per credit (the largest API pack).
In your editor
{ "models": [{ "title": "DeepFA", "provider": "openai", "model": "claude-sonnet-5", "apiKey": "YOUR_DEEPFA_KEY", "apiBase": "https://deepfa.ir/api/v1" }] }
"github.copilot.chat.customOAIModels": [{ "modelId": "claude-sonnet-5", "displayName": "DeepFA Claude Sonnet 5", "endpoint": "https://deepfa.ir/api/v1", "apiKey": "YOUR_DEEPFA_KEY" }]
# Settings → Models → OpenAI API Base URL: https://deepfa.ir/api/v1 API Key: YOUR_DEEPFA_KEY Model: gpt-6.1-sol / claude-sonnet-5-5
Provider: OpenAI Compatible Base URL: https://deepfa.ir/api/v1 API Key: YOUR_DEEPFA_KEY Model ID: claude-sonnet-5
// ~/.claude/settings.json { "env": { "ANTHROPIC_BASE_URL": "https://deepfa.ir/api", "ANTHROPIC_AUTH_TOKEN": "YOUR_DEEPFA_KEY", "ANTHROPIC_MODEL": "claude-sonnet-5-5" } }
# ~/.codex/config.toml model = "gpt-6.1-sol" model_provider = "deepfa" [model_providers.deepfa] name = "DeepFA" base_url = "https://deepfa.ir/api/v1" env_key = "DEEPFA_API_KEY" wire_api = "responses"
You create and revoke keys from your own dashboard. Each key can be held to a daily and a monthly credit ceiling, to IP addresses, endpoints and models, and to an end date, or switched off for a while.
An OpenAI-compatible gateway, for developers and businesses
The DeepFA AI API is a gateway that speaks the OpenAI standard: the same /v1/chat/completions path, the same request body, the same response shape and the same error format. Any library, extension or service that works with OpenAI today connects to DeepFA by changing the base URL and the key — no rewrite, no bespoke SDK, no new contract to learn. Behind that one address sit GPT, Claude, Gemini, Grok and DeepSeek models, and switching between them means changing one string in the model field. Claude Code and Codex, which speak other shapes, connect with the same key through /v1/messages and /v1/responses.
Beyond chat, the same address serves embeddings for semantic search and RAG, image generation with GPT Image, FLUX and Nano Banana, video generation, speech-to-text and text-to-speech. SSE streaming, tool calling, structured output and image input are all supported and behave exactly as they do upstream. The cost of every call comes back in a response header and is recorded on the API page of your dashboard, broken down by key and by model — failed requests included, so your credit is never a black hole.
For a developer in Iran the difference that matters most is payment: credit is bought in rial through a local gateway, no international card is needed, and bought credit never expires. Each key can carry a daily and monthly credit ceiling, a per-minute request limit, allow-lists of models and endpoints, allowed IP addresses and an end date, or be switched off for a while, so a key handed to a script or a colleague cannot empty the account — and can be revoked in one click if it leaks. You are emailed before your API credit runs out.
Why the DeepFA AI API?
Built with developer needs in focus — easy to start, secure to use and scalable for growth.
OpenAI-compatible
The same paths, the same request body, the same response shape. The official OpenAI libraries and anything built on them connect to DeepFA by changing one base URL, and Claude Code and Codex through routes of their own.
One key, every vendor
GPT, Claude, Gemini, Grok and DeepSeek behind one key and one address. Switching model means changing one string, not changing libraries, accounts and invoices.
Streaming, tools and vision
Token-by-token SSE streaming, tool calling, structured output and image input — none of it needing a change to code you have already written.
A spending ceiling per key
Set a daily and monthly ceiling, a per-minute request limit, the models and endpoints allowed, IP addresses and an end date on each key. A key you hand to a script cannot empty the account.
What every call cost
The cost of each request comes back in a response header and is recorded on your usage page by key and by model — failures included. Your credit is not a black hole.
Pay in rial, no foreign card
Buy credit through a local gateway, and bought credit never expires. No international card, nothing to work around.
Thousands of requests in one file
With the Batch API, send thousands of headlines, summaries or translations in one JSONL file; they run in the background within a day and the answers come back as one file. No rate limit to pace, no retries to write: the same shape as OpenAI's Batch API.
Told when a job ends, by webhook
Instead of asking again and again whether a video, a song, a podcast, an agent run or a batch is ready, give an https address and a signed event is posted to it when each one ends (the Standard Webhooks spec OpenAI uses).
Usage labels and team credit
With the X-DeepFA-Tag header, put each request down to a project, a department or a customer and see the spending that way. A team owner can open the API to members, whose keys then spend the team's credit within each member's monthly limit.
The endpoints you can call
All under one base URL, all with the same key, all in the request and response shape you know from OpenAI — and /messages in Anthropic's.
What each endpoint takes and returns
Everything beyond the standard OpenAI shape: chat features, image and audio parameters, video jobs, the model list, the balance, and every error and limit.
Function calling (tools)
Send tools in the OpenAI shape. When the model wants one, the answer carries tool_calls instead of text; run the function yourself and send the result back with the tool role and the same tool_call_id, and the model writes its final answer. Works with every text model except Sonar, which searches the web by itself and takes no tools.
{
"model": "gpt-6-luna",
"messages": [{"role": "user", "content": "What is the weather in Tehran?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}],
"tool_choice": "auto"
}
{"role": "tool", "tool_call_id": "call_8f2...", "content": "{\"temp_c\": 21}"}
JSON output (response_format)
With {"type": "json_object"} the answer is valid JSON; with json_schema it comes back in exactly the structure you define.
{
"model": "gpt-6-luna",
"messages": [{"role": "user", "content": "Three colours, as JSON."}],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "colours",
"schema": {
"type": "object",
"properties": {"colours": {"type": "array", "items": {"type": "string"}}},
"required": ["colours"]
}
}
}
}
Image input and reasoning effort
To send a picture, make content an array with an image_url: a public https address, or a base64 data URL (data:image/png;base64,…). Reasoning models (GPT-5, GPT-6, the o-series and Gemini) take reasoning_effort as low, medium or high; left out, the model's own default applies (medium on GPT-6). GPT-6 and the o-series do not accept temperature or top_p.
{
"model": "gpt-6-luna",
"reasoning_effort": "low",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "What is in this picture?"},
{"type": "image_url", "image_url": {"url": "https://example.com/cat.png"}}
]
}]
}
Prompt caching
The part of a prompt the model has already seen (a fixed system message, say) is charged at the "cached input" rate in the price table, and its count comes back in usage.prompt_tokens_details.cached_tokens. It is automatic on GPT, Gemini and DeepSeek; on Claude, put cache_control with type ephemeral on a message or on the whole request (on /v1/messages Claude Code's own markers go through as they are).
POST /v1/messages
Anthropic's Messages API shape, for Claude models; the route Claude Code calls with ANTHROPIC_BASE_URL set to https://deepfa.ir/api. The body goes through unchanged: block-form system, cache_control, thinking and tools, with the anthropic-beta and anthropic-version headers. A stream comes back event by event in order, and errors are in Anthropic's shape. Dated ids such as claude-haiku-4-5-20251001 and the [1m] suffix are accepted.
A few things are removed, because each costs more than the token rates in the price table: speed (fast mode), inference_geo and service_tier, and the server-side web search and code execution tools that Anthropic bills per use. POST /v1/messages/count_tokens counts a request's tokens free of charge. Models other than Claude are served by /v1/chat/completions.
POST /v1/responses
OpenAI's Responses API shape, for OpenAI models; the only shape Codex speaks (wire_api = "responses"). input items, reasoning items with their encrypted content, and function, custom and shell tools pass through unchanged. A stored response (the default, unless "store": false) is kept for thirty days, and its previous_response_id works for the same account only. The conversation parameter is not supported.
Removed: service_tier, background, and the hosted tools billed per use (web and file search, code interpreter, image generation, computer use and remote MCP).
Retired model names
A request naming a model that has been replaced, such as gpt-5.6-luna, is answered by its replacement (gpt-6-luna) at its price, and the key's owner is told once by email and in the dashboard. The names are listed on the Models tab of the API page.
POST /v1/images/generations — pictures come back as b64_json (base64 PNG), and only the pictures actually made are charged.
| Field | Description |
|---|---|
model | Default gpt-image-2.5-sunburst. Also gpt-image-2.5-flare, gpt-image-1, flux-3, flux-3-klein, flux-schnell, nano-banana-2.1 and nano-banana-2-lite. |
prompt | Required; what to draw. |
n | How many, 1 to 10 (default 1). |
size | Such as 1024x1024, 1536x1024 or 1024x1536. For FLUX, GPT Image 2.5 and Nano Banana it becomes the nearest aspect ratio the model makes. |
quality, background, output_format | For gpt-image-1, as OpenAI defines them. |
{
"model": "flux-schnell",
"prompt": "A lighthouse at dawn, watercolour",
"n": 2,
"size": "1536x1024"
}
POST /v1/images/edits
Image to image, sent as multipart/form-data as with OpenAI: one to four pictures with a description, and the new picture comes back as b64_json. A picture costs the model's price; where the supplier bills every input picture, each one adds the credits_per_input_image shown by GET /v1/models.
| Field | Description |
|---|---|
image / image[] | Required; one to four PNG, JPEG or WebP pictures (up to three on nano-banana-2-lite), up to 10 MB each (made about one megapixel). |
model | Default gpt-image-2.5-sunburst. Also gpt-image-2.5-flare, nano-banana-2.1, nano-banana-2-lite, flux-3 and flux-3-klein. |
prompt | Required; what to make from the pictures. |
n | How many, 1 to 10 (default 1). |
size | Optional; such as 1024x1024, or auto for the shape of the input picture. |
curl https://deepfa.ir/api/v1/images/edits \ -H "Authorization: Bearer $DEEPFA_API_KEY" \ -F model=flux-3 \ -F "image[]=@product.png" \ -F "prompt=Place this bottle on a marble counter in soft morning light"
POST /v1/audio/speech
Returns the audio file itself, charged per character.
| Field | Description |
|---|---|
model | Default tts-1. Also tts-1-hd, gpt-4o-mini-tts, and eleven-v4 and eleven-v4-turbo (faster), which read Persian and more than ninety other languages. And gemini-3.8-flash-lite-tts, which reads Persian, English and other languages with seventy voices. |
input | Required; the text, at most 4,096 characters a request. |
voice | For the OpenAI models one of alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, verse (default alloy). For the eleven models the name of an ElevenLabs voice, such as Rachel. |
response_format | mp3 (default), opus, aac, flac, wav, pcm — the eleven models always return mp3. |
voice (Gemini) | For gemini-3.8-flash-lite-tts, one of the seventy Gemini voices, such as Fola (default), Zephyr, Kore, Puck or Charon. |
speed | Reading speed (optional). |
instructions | Tone and delivery, for gpt-4o-mini-tts and gemini-3.8-flash-lite-tts. |
language | The text's language, for the eleven models (optional). |
POST /v1/audio/transcriptions
Sent as multipart/form-data; charged per started minute.
| Field | Description |
|---|---|
file | Required; an audio or video file, at most 25 MB. |
model | Default gpt-transcribe. Also gpt-4o-transcribe, gpt-4o-mini-transcribe and whisper-1 until OpenAI shuts them down on 2027-02-26; from then on their requests are served by gpt-transcribe. |
languages[], keywords[], prompt | Optional with gpt-transcribe: the languages the audio may be in (e.g. fa), words you expect to hear, and a note on the topic. A single language is accepted too and sent as languages[]. |
language, temperature | Optional with the older models, as OpenAI defines them. |
response_format | json (default) or text; with whisper-1 (until 2027-02-26) also srt, vtt and verbose_json. |
Making a video takes minutes, so it is a job: POST /v1/videos starts it and at once returns its id with the status queued; poll GET /v1/videos/{id} every few seconds until the status moves from in_progress to completed (with the file's url) or failed; GET /v1/videos/{id}/content redirects to the finished file (302), or answers 409 if it is not ready. The credit is charged when the job is accepted, and given back in full if it fails.
| Field | Description |
|---|---|
model | Required; from the table below. |
prompt | Required (except for bytedance-upscaler). |
image_url | A public https address of a picture, to animate it. |
video_url | A public https address of a video, to edit it. Do not send both image_url and video_url. |
seconds | The clip's length, one of the model's lengths below (default 5). Not needed for an edit: the length is read from the source video itself, which must run 1 to 120 seconds. |
resolution | Such as 480p, 720p or 1080p. Left out, or not one the model makes, the model's default is used. The price changes with the resolution and length. |
aspect_ratio | 16:9 (default), 9:16, or 1:1 on the models that make it. |
audio | Sound, on the models that make it (default true). |
fps, keep_audio, audio_setting | Edits only: the frame rate for bytedance-upscaler (default 30), keeping the source video's sound (default true), and the sound setting on happy-horse-edit. |
Models and the lengths they make
| Model | Job | Seconds |
|---|---|---|
| kling-3-turbo-pro | text to video | 5, 10 |
| luma-ray-32 | text to video | 5, 10 |
| grok-imagine-15 | text to video, image to video (image_url) | 3, 5, 10, 15 |
| minimax-h3-max | text to video | 5, 10, 15 |
| wan-30 | text to video | 5, 10, 15 |
| kling-3-pro | text to video | 5, 10 |
| kling-o3 | text to video | 5, 10 |
| google-veo-31 | text to video, image to video (image_url) | 4, 6, 8 |
| google-veo-31-fast | text to video, image to video (image_url) | 4, 6, 8 |
| google-veo-31-lite | text to video, image to video (image_url) | 4, 6, 8 |
| seedance-25 | text to video, image to video (image_url) | 5, 10, 15, 20, 30 |
| kling-4 | text to video, image to video (image_url) | 3, 5, 10, 15, 20, 30 |
| kling-video-pro | image to video (image_url) | 5, 10 |
| kling-video-o3 | image to video (image_url) | 5, 10 |
| luma-dream-machine | image to video (image_url) | 5 |
| wan-video-25 | image to video (image_url) | 5, 10 |
| bytedance-upscaler | video edit (video_url) | the source video's length |
| happy-horse-edit | video edit (video_url) | the source video's length |
| kling-o3-pro-edit | video edit (video_url) | the source video's length |
| grok-imagine-edit | video edit (video_url) | the source video's length |
curl https://deepfa.ir/api/v1/videos \
-H "Authorization: Bearer $DEEPFA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-imagine-15",
"prompt": "A paper boat sailing down a rainy street",
"seconds": 5,
"resolution": "720p",
"aspect_ratio": "16:9"
}'
{
"id": "t_48213",
"object": "video",
"model": "grok-imagine-15",
"kind": "text_to_video",
"status": "queued",
"seconds": 5,
"created_at": 1790443124
}
A podcast is a job, like a video: POST /v1/podcasts takes the script and returns an id such as p_123 at once; ask GET /v1/podcasts/{id} until its status is completed, then fetch the audio from GET /v1/podcasts/{id}/content (?what=transcript for the text, ?what=srt for subtitles). The voices are made by gemini-3.8-flash-lite-tts; you pay once, after the whole podcast exists, by the characters read and at the rate of /v1/audio/speech for this model - nothing is charged if it fails. The script is yours to bring (write it with /v1/chat/completions).
| Field | Description |
|---|---|
turns | The script as a list of {speaker: 1 to 4, text, style}. style is optional and in English, such as warmly or quietly amazed. Or send script instead. |
script | The script as text with lines such as "Sara: hello". The names are the ones in names, or labels such as Speaker 1. |
voices, names | Up to four voices and the names of the hosts (default Laomedeia, Alnilam, Sulafat and Puck). The voices are the Gemini ones. With more than two hosts the voices are recorded two at a time. |
language | A language code such as fa, en, ar, tr … (default en). |
kind, natural, title | kind solo means one speaker; natural adds the little fillers and pauses of real talk; title names the episode. |
| Sound tags | Inside the text you can write <laugh>, <sigh>, <gasp>, <short pause> and <long pause>; the Persian words work too: <خنده>, <آه>, <مکث کوتاه>, <مکث بلند>. |
At most 12,000 characters a podcast (about twenty minutes) and three podcasts at once per account. A podcast made through the API also appears in the AI Podcast tool.
curl https://deepfa.ir/api/v1/podcasts \
-H "Authorization: Bearer $DEEPFA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"language":"en","voices":["Kore","Puck"],"turns":[{"speaker":1,"text":"Hi everyone, welcome! "},{"speaker":2,"text":"Glad to be here.","style":"warmly"}]}'
{"id":"p_123","object":"podcast","model":"gemini-3.8-flash-lite-tts","status":"queued","progress":0}
For thousands of requests, in the shape of OpenAI's Batch API and with the same libraries: write the requests in a JSONL file (one a line), upload it with POST /v1/files and purpose=batch, start it with POST /v1/batches, ask GET /v1/batches/{id} until its status is completed, and download the answers from GET /v1/files/{output_file_id}/content. The requests run in the background within 24 hours, without the key's rate limit, each charged exactly as the same live request would be and within the key's daily and monthly ceilings.
{"custom_id": "news-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-6-luna", "messages": [{"role": "user", "content": "..."}]}}
{"custom_id": "news-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-6-luna", "messages": [{"role": "user", "content": "..."}]}}
curl https://deepfa.ir/api/v1/files -H "Authorization: Bearer $DEEPFA_API_KEY" -F purpose=batch -F file=@requests.jsonl
curl https://deepfa.ir/api/v1/batches -H "Authorization: Bearer $DEEPFA_API_KEY" -H "Content-Type: application/json" \
-d '{"input_file_id": "file-...", "endpoint": "/v1/chat/completions", "completion_window": "24h"}'
| Point | Description |
|---|---|
endpoint | /v1/chat/completions or /v1/embeddings; every line of the file must name that url. |
custom_id | Required and unique within the file; each answer comes back with it, since the order is not guaranteed. |
| File check | If any line is invalid (bad JSON, an unknown model, a repeated custom_id), the batch comes back failed with the list in errors, and nothing is run. |
| Result | output_file_id holds the answers that succeeded and error_file_id the requests that did not; each line carries custom_id, response.status_code and response.body. request_counts, usage and credits sum up the work and its cost. |
| Cancel and expiry | POST /v1/batches/{id}/cancel drops what has not run, and what has run stays in the file. Whatever has not run within 24 hours appears in the error file as batch_expired, and costs nothing. |
| Limits | At most 50,000 requests a batch; the file up to the server's upload limit (the error names it). Files are kept for thirty days and read only with a key of the same account. |
Instead of asking again and again, give an https address on the Connect tab of the API page. When a long job ends an event is posted to it, and tried again for about a day until your server answers 2xx (after 1, 5 and 30 minutes, then 2, 6 and 15 hours). The body names the job only; fetch the result with your key.
{"id": "evt_...", "object": "event", "type": "video.completed", "created_at": 1793000000,
"data": {"id": "t_123", "object": "video", "status": "completed"}}
| Event | When |
|---|---|
video.completed, video.failed | A video is done, or failed (the credit is given back). |
music.completed, music.failed | A song is done, or failed. |
podcast.completed, podcast.failed | A podcast is done, or failed. |
agent_run.completed, agent_run.failed, agent_run.cancelled | An agent run ended. |
batch.completed, batch.failed, batch.expired, batch.cancelled | A batch ended. |
Checking the signature
Each post carries the three Standard Webhooks headers OpenAI's own webhooks use: webhook-id, webhook-timestamp and webhook-signature (v1, followed by the base64 HMAC-SHA256 of "id.timestamp.body" under the signing secret's bytes). The signing secret (whsec_...) is on the same Connect tab; the Standard Webhooks libraries and webhooks.unwrap in OpenAI's official SDK verify it.
# pip install standardwebhooks
from standardwebhooks.webhooks import Webhook
event = Webhook("whsec_...").verify(request_body, request_headers) # raises if forged
GET /v1/models
Lists only the models your plan and key allow, each with a pricing object in credits. Text models: input_per_million_tokens, output_per_million_tokens, and where they apply cached_input_per_million_tokens and cache_write_per_million_tokens. Other models: credits per credits_per (image, character, minute, video or second); for a video, seconds and resolution name the clip that price is for. Always the price actually charged.
GET /v1/balance
What this key can spend, at no charge. available is the account credit the API can draw on, and pockets splits it in the order it is spent: API credit, plan credit, prepaid credit. key shows this key's daily and monthly ceilings with what has gone against them, and spendable is what the key can spend right now: the balance narrowed by the nearest ceiling. On an unlimited account, unlimited is true and available is null. For a team member whose owner opened the API to them, pockets.team is their share of the team's credit (within their monthly limit), counted in available.
curl https://deepfa.ir/api/v1/balance -H "Authorization: Bearer $DEEPFA_API_KEY"
{
"object": "balance",
"unit": "credits",
"unlimited": false,
"available": 6500,
"pockets": {"api": 5000, "plan": 1200, "prepaid": 300},
"key": {
"name": "production",
"rpm_limit": 60,
"daily": {"limit": 100, "spent": 30, "remaining": 70},
"monthly": {"limit": null, "spent": 30, "remaining": null}
},
"spendable": 70
}
Every error comes back in the standard OpenAI shape, with code the same as type; param names the field at fault. On /v1/messages it comes back in Anthropic's shape instead.
{
"error": {
"message": "The model \"gpt-9\" is not available.",
"type": "model_not_found",
"param": "model",
"code": "model_not_found"
}
}
| HTTP | type | Meaning |
|---|---|---|
400 | invalid_request_error | A field is missing or wrong; param names it. |
401 | invalid_api_key | The key is wrong, revoked, or not sent at all (invalid_request_error). |
401 | key_expired | The end date you set on this key has passed. |
403 | account_inactive | The account is not verified or not active. |
403 | key_disabled | You switched this key off on the API page. |
403 | ip_not_allowed | The request came from an address that is not on the list allowed for this key. |
403 | endpoint_not_allowed | This key is not allowed to call this endpoint. |
403 | permission_denied | Your plan does not include this agent. |
404 | model_not_found | The model does not exist, or your plan or key does not allow it. |
404 | not_found | No video or run with that id. |
404 | invalid_request_error | The address is not an endpoint; the message points to this reference. |
409 | invalid_request_error | The video is not ready yet, or it failed (from the content path). |
409 | idempotency_key_in_use | A request with this Idempotency-Key is still running; send it again in a few seconds. |
422 | idempotency_key_reused | This Idempotency-Key was used for a different request; send a new key with a new request. |
413 | invalid_request_error | The file to transcribe is over 25 MB. |
429 | insufficient_quota | Not enough credit; the message carries the address to top up at. |
429 | key_daily_limit_reached | The daily ceiling you set on this key is used up. |
429 | key_monthly_limit_reached | The monthly ceiling on this key is used up. |
429 | rate_limit_exceeded | Too many requests a minute for this key (Retry-After says how many seconds to wait), or three agent runs already going. |
500 | internal_error | An internal error; nothing was charged. |
502 | upstream_error | The model's provider failed or could not be reached; try again. |
503 | model_unavailable | This model is temporarily unavailable. |
Limits
- Requests a minute per key: 60 by default; set it anywhere from 1 to 6,000 when you make or edit the key in the panel. Beyond it, 429 with a
Retry-Afterheader. - An optional daily and monthly credit ceiling per key, set in the panel;
GET /v1/balanceshows what is left of it. - Optional on each key: allowed IP addresses (IPv4, IPv6 or a CIDR range), the groups of endpoints it may call, an end date, and switching it off for a while.
- At most three agent runs at once per account.
- Transcription files up to 25 MB; speech input up to 4,096 characters; up to 10 pictures a request; video edits of 1 to 120 seconds.
- Each request's cost comes back in the
x-deepfa-creditsheader and its id inx-deepfa-request-id; quote that id when you contact support.
Optional headers
X-DeepFA-Tag: a label of up to 64 characters for each request (a project, a department, one of your customers); the usage page and its Excel sheet break the spending down by it. Percent-encode a non-Latin label, since most libraries take only Latin letters in a header.Idempotency-Key: send the same request again with the same key within a day (after a dropped connection, say) and the first answer comes back withIdempotent-Replayed: true; the request is not run or charged again. A streamed answer is not played back; its key only keeps it from running twice.
For tools and monitoring
- The whole API described in OpenAPI 3.1, to load into Postman or Insomnia or generate a client from: /api/openapi.json
- Each part of the API now and over the last ninety days: the status page and, for your monitoring, /api/status.json
Quick Start in 6 Programming Languages
The same request in six languages. The only things that differ from OpenAI are the base URL and the key.
curl https://deepfa.ir/api/v1/chat/completions \
-H "Authorization: Bearer $DEEPFA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"messages": [{"role": "user", "content": "Hello"}]
}'
# pip install openai
from openai import OpenAI
client = OpenAI(
api_key="YOUR_DEEPFA_KEY",
base_url="https://deepfa.ir/api/v1",
)
completion = client.chat.completions.create(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "Hello"}],
)
print(completion.choices[0].message.content)
print(completion.usage.total_tokens, "tokens")
// Any fetch, no SDK needed.
const res = await fetch('https://deepfa.ir/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${DEEPFA_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-6.1-sol',
messages: [{ role: 'user', content: 'Hello' }],
stream: false
})
});
const data = await res.json();
console.log(data.choices[0].message.content);
// What the call cost, straight off the response header.
console.log(res.headers.get('x-deepfa-credits'), 'credits');
// npm install openai
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.DEEPFA_API_KEY,
baseURL: 'https://deepfa.ir/api/v1'
});
// Streaming works exactly as it does upstream.
const stream = await client.chat.completions.create({
model: 'gemini-3.8-flash',
messages: [{ role: 'user', content: 'Write a haiku' }],
stream: true
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
}
<?php
$ch = curl_init('https://deepfa.ir/api/v1/chat/completions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DEEPFA_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'model' => 'deepseek-flash',
'messages' => [['role' => 'user', 'content' => 'Hello']],
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $result['choices'][0]['message']['content'];
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
body, _ := json.Marshal(map[string]any{
"model": "claude-haiku-5-5",
"messages": []map[string]string{
{"role": "user", "content": "Hello"},
},
})
req, _ := http.NewRequest("POST",
"https://deepfa.ir/api/v1/chat/completions",
bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("DEEPFA_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
var out map[string]any
json.NewDecoder(res.Body).Decode(&out)
fmt.Println(out["choices"])
}
{
"id": "chatcmpl-9f2c1a",
"object": "chat.completion",
"model": "claude-sonnet-5",
"choices": [{
"index": 0,
"message": { "role": "assistant", "content": "Hello!" },
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 306,
"total_tokens": 318
}
}
data: {"id":"chatcmpl-9f2c1a","object":"chat.completion.chunk",
"choices":[{"delta":{"content":"Hel"},"index":0}]}
data: [DONE]
{
"object": "list",
"model": "text-embedding-3-small",
"data": [{ "object": "embedding", "index": 0,
"embedding": [0.0021, -0.0134, 0.0075] }],
"usage": { "prompt_tokens": 8, "total_tokens": 8 }
}
{
"created": 1788115200,
"data": [{ "b64_json": "iVBORw0KGgoAAAANSUhEUgAA..." }]
}
x-deepfa-request-id: 3f9a1c2e-... x-deepfa-credits: 0.0954 x-deepfa-credit-unit: credits
{
"error": {
"message": "You have run out of credit. Top up your balance to continue: https://deepfa.ir/app/user/pricing/plans#api_packs",
"type": "insufficient_quota",
"param": null,
"code": "insufficient_quota"
}
}
Send your first request in four simple steps
From creating a key to the first answer in under a minute. No app registration, no OAuth dance.
Create an API key
Sign in, open the API page and create a key. The key is shown once, so copy it there and then.
Point the base URL at DeepFA
In whatever tool or library you already use, set the base URL to https://deepfa.ir/api/v1 and paste the key as the API key.
Choose a model
Put the model name in the same model field — claude-sonnet-5-5, gpt-6.1-sol, gemini-3.8-flash or any other your key allows.
Watch what it costs
The cost of each call comes back in the x-deepfa-credits header and is recorded on the API page by key and by model.
A Look Inside the API Interface
Simple and practical interface — click any image to enlarge.
Frequently Asked Questions About the DeepFA AI API
Answers to common developer questions about using the API — contact support if you don't find your answer.
Get Your API Key and Start Building Today
Free sign-up, a key in seconds, and credit that never expires