# reAPI — Full Documentation > One API for top AI image, video, chat, and audio models. This file is the complete documentation set in markdown; https://reapi.ai/llms.txt is the link index. Pages: 69 # ai-essay-writer (https://reapi.ai/docs/ai-essay-writer) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > The AI Essay Writer API generates a complete, structured essay from a > **topic** plus an **academic level**, **essay type**, and **length**. One > async call returns a task id; poll until the essay is ready. An optional > `humanized` pass rewrites the result to read more human. Pricing is per > essay, scaled by the length tier — see current rates on the > [model page](https://reapi.ai/models/ai-essay-writer). ## Quick example ```bash curl https://reapi.ai/api/v1/essay \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ai-essay-writer", "type": "Descriptive", "academic_level": "HighSchool", "length": "Short", "input": "Write an essay about the ketogenic diet" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/essay", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "ai-essay-writer", "type": "Descriptive", "academic_level": "HighSchool", "length": "Short", "input": "Write an essay about the ketogenic diet", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/essay", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "ai-essay-writer", type: "Descriptive", academic_level: "HighSchool", length: "Short", input: "Write an essay about the ketogenic diet", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "ai-essay-writer", "type": "Descriptive", "academic_level": "HighSchool", "length": "Short", "input": "Write an essay about the ketogenic diet", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/essay", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "ai-essay-writer", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload carries the generated essay text in the task output. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/essay GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required `string`. Must be `"ai-essay-writer"`. ### `input` — required `string`. The essay topic or instructions the model builds the essay around. ### `type` — required `string`. The rhetorical mode of the essay. | Value | Notes | | ---------------------- | -------------------------- | | `"Descriptive"` | Descriptive essay | | `"Narrative"` | Narrative essay | | `"Persuasive"` | Persuasive / argumentative | | `"Analytical"` | Analytical essay | | `"CompareAndContrast"` | Compare-and-contrast essay | ### `academic_level` — required `string`. The writing level the essay targets (vocabulary, structure, depth). | Value | | -------------- | | `"HighSchool"` | | `"University"` | | `"Doctorate"` | ### `length` — required `string`. Output length tier. **Pricing scales with this tier.** | Value | | ---------- | | `"Short"` | | `"Medium"` | | `"Long"` | ### `humanized` — boolean, default `false` Run the finished essay through a de-AI pass so it reads more human. ### `model_version` — string, default `"v2"` Generation model version. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. The completed `output` carries the generated essay text. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "ai-essay-writer", "status": "completed", "created_at": 1735000000, "output": { "text": "The ketogenic diet, commonly referred to as the keto diet, is a high-fat, low-carbohydrate eating plan…" }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | --------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.text` is the essay | | `error` | object \| null | Populated on `failed` — `{ code, message }` | *** ## Pricing Per essay, scaled by the `length` tier. Each tier is priced at a fixed estimated output-word count × the per-word rate. **Bill formula** (1 credit = $0.001): ``` credits = ceil(per_word_usd × estimated_words(length) × 1000) ``` `length` (Short / Medium / Long) selects the estimated word count. See the current per-tier rates in the pricing table on the [model page](https://reapi.ai/models/ai-essay-writer). Failed jobs refund automatically. *** ## Validation errors All cases below return HTTP 400. Pattern-match on `code`, not `message`. | Trigger | Code | Message (illustrative) | | ---------------------------------- | ------- | ----------------------------------------------- | | `input` missing | `20002` | `input is required` | | `type` missing / invalid | `20003` | `invalid type` | | `academic_level` missing / invalid | `20003` | `invalid academic_level` | | `length` missing / invalid | `20003` | `invalid length` | | Upstream out of credits | `80003` | Upstream provider could not process the request | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors). *** ## Tips * **Length drives the bill.** A Short essay costs less than a Long one; pick the smallest tier that fits the assignment. * **Set the type and level deliberately.** `academic_level` and `type` change the vocabulary, structure, and depth more than the prompt wording does. * **Use `humanized` for a natural read.** Turn it on when the essay needs to read less like AI; leave it off for the fastest result. * **The topic can be detailed.** `input` accepts full instructions, not just a title — constraints and angles in the topic carry into the essay. *** ## Related * [AI Humanizer](/docs/humanize) * [AI Text Detector](/docs/ai-text-detector) * [Errors catalog](/docs/api/errors) * [Quickstart](/docs/api/quickstart) --- # ai-text-detector (https://reapi.ai/docs/ai-text-detector) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > `ai-text-detector` is a single async endpoint that scores text 0–100 for how likely > it is AI-generated, aggregating several third-party detection engines into one > result plus per-engine sub-scores. See current pricing on the > [model page](https://reapi.ai/models/ai-text-detector). ## Quick example ```bash curl https://reapi.ai/api/v1/detect \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ai-text-detector", "text": "Citizen science involves the public participating in scientific research. This can take many forms, from collecting data on local wildlife populations to analyzing astronomical images." }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/detect", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "ai-text-detector", "text": "Citizen science involves the public participating in scientific research. This can take many forms, from collecting data on local wildlife populations to analyzing astronomical images.", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/detect", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "ai-text-detector", text: "Citizen science involves the public participating in scientific research. This can take many forms, from collecting data on local wildlife populations to analyzing astronomical images.", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "ai-text-detector", "text": "Citizen science involves the public participating in scientific research. This can take many forms, from collecting data on local wildlife populations to analyzing astronomical images.", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/detect", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "ai-text-detector", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` until `status === "completed"`. A check usually finishes in a few seconds. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/detect GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; polling the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required Always `"ai-text-detector"`. ### `text` — required (string) The text to check for AI authorship. * **Maximum:** under **30,000 words** per request. * **Recommended:** at least \~200 words. Short snippets carry less signal, though the detector still returns a result. * Encode line breaks inside the JSON string as `\n`. *** ## Output ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "ai-text-detector", "status": "completed", "created_at": 1735000000, "output": { "detection": { "result": 12.0, "human": 88.0, "detectors": { "scoreGptZero": 50.0, "scoreOpenAI": 0.0, "scoreWriter": 0.0, "scoreCrossPlag": 0.0, "scoreCopyLeaks": 50.0, "scoreSapling": 0.0, "scoreContentAtScale": 0.0, "scoreZeroGPT": 50.0 } } }, "error": null } ``` ### Interpreting the score `result` is the headline **AI-likelihood**, 0–100: | Range | Reading | | -------- | --------------------- | | under 50 | Likely human-written. | | 50 – 60 | Possible AI. | | over 60 | Likely AI-generated. | `human` is the complementary human-likelihood. `detectors` carries each third-party engine's sub-score so you can see whether the engines agree or split. The headline `result` is the most accurate signal; treat the sub-scores as supporting detail. *** ## Pricing Billed **per word** of the `text` you submit, with a **50-word floor**. AI detection is priced at one-tenth the per-word rate of text humanization. Polling does not add any charge. Failed requests are refunded automatically. `1 credit = $0.001 USD`. See the live banner on the [model page](https://reapi.ai/models/ai-text-detector) for the current per-1,000-words rate in credits. *** ## Errors Standard envelope: ```json { "error": { "code": 20002, "message": "text is required", "request_id": "req_..." } } ``` Common cases: | Code | When | | ------- | -------------------------------------------------------------------------- | | `20002` | `text` missing. | | `20003` | `text` empty or at/over the 30,000-word cap. | | `30001` | Insufficient credits for the submitted word count. | | `80001` | Provider rejected the submission — includes insufficient upstream credits. | | `80003` | Provider failed while processing the detection. | *** ## Related * [AI Humanizer](/docs/humanize) — rewrite AI text to read human. Pair it with `ai-text-detector` for a detect → rewrite → detect QA loop. --- # claude-fable-5 (https://reapi.ai/docs/claude-fable-5) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Claude Fable 5 is Anthropic's most capable widely released model — a tier > above Opus — built for the most demanding reasoning and long-horizon > agentic work, exposed through api.reapi.ai as a drop-in OpenAI-compatible > Chat Completions endpoint (the native Anthropic `/v1/messages` surface is > also available). 1M token context, 128K max output, always-on adaptive > thinking, vision input, prompt caching, and tool use. Current rates live > on the [model page](https://reapi.ai/models/claude-fable-5) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-fable-5", "group": "default", "messages": [ { "role": "user", "content": "Hello" } ], "stream": true, "max_tokens": 4096 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="claude-fable-5", messages=[{"role": "user", "content": "Hello"}], stream=True, max_tokens=4096, extra_body={"group": "default"}, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ```python from anthropic import Anthropic client = Anthropic( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai", ) with client.messages.stream( model="claude-fable-5", max_tokens=4096, messages=[{"role": "user", "content": "Hello"}], ) as stream: for text in stream.text_stream: print(text, end="", flush=True) ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "claude-fable-5", messages: [{ role: "user", content: "Hello" }], stream: true, max_tokens: 4096, // `group` is an api.reapi.ai-specific extension; pass via extra body. // @ts-expect-error — not part of the OpenAI types group: "default", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "claude-fable-5", "group": "default", "messages": []map[string]string{ {"role": "user", "content": "Hello"}, }, "stream": true, "max_tokens": 4096, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Every request needs a Bearer token. The Claude Fable 5 chat workspace lives on the `api.reapi.ai` platform — sign in there to create a key and top up tokens. 1. Open [api.reapi.ai](https://api.reapi.ai/) and sign in (or create an account). 2. Generate an API key under **API Keys**. 3. Top up tokens under **Top Up** (pay-as-you-go, billed in USD per 1M tokens — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing)). ```http Authorization: Bearer YOUR_API_KEY ``` The chat surface (api.reapi.ai) is a **separate workspace** from the image/video/audio task gateway at `reapi.ai/api/v1/*`. Keys and balances do not cross over — a key issued on `reapi.ai/settings/apikeys` will not authenticate against `api.reapi.ai/v1/chat/completions`, and vice versa. *** ## Endpoints ```http POST https://api.reapi.ai/v1/chat/completions # OpenAI-compatible POST https://api.reapi.ai/v1/messages # Anthropic-native ``` Both surfaces accept `claude-fable-5`. Pick whichever matches your SDK of record: * **`/v1/chat/completions`** — drop-in for the OpenAI SDKs. Same request shape, same SSE wire format. Set `base_url` to `https://api.reapi.ai/v1`. * **`/v1/messages`** — native Anthropic Messages format. Set `base_url` to `https://api.reapi.ai` for the Anthropic Python / TypeScript SDKs. Required for callers that need Anthropic-specific features (`cache_control` blocks for prompt caching, the `effort` parameter, summarized thinking display, native multi-block content, the full tool-use spec). *** ## Request body — `/v1/chat/completions` ### `model` — string, required Must be `"claude-fable-5"`. The value is echoed back in the response envelope. ### `messages` — array, required Conversation history as an array of message objects. Same shape as the OpenAI Chat Completions spec, plus content-parts for vision: ```json { "role": "system" | "user" | "assistant" | "tool", "content": "string OR content-parts array (text + image_url parts)" } ``` Multi-turn history is sent in chronological order — the last message is the one Claude responds to. ### `max_tokens` — integer, default `4096` Upper bound on output tokens. **Anthropic's API requires `max_tokens` on every call, including streamed ones** — even though the OpenAI SDKs treat it as optional. Set it generously (`128000` is the hard cap on the synchronous API) for long-form outputs; the model still stops at the natural end of its response. ### `stream` — boolean, default `false` When `true`, the response is streamed as server-sent events (SSE) with `Content-Type: text/event-stream`. Each event is a JSON delta in the OpenAI format, terminated by a `data: [DONE]` line. ### `tools` / `tool_choice` — optional Standard OpenAI tool-calling parameters. Claude Fable 5 supports the full OpenAI tool-use spec via this surface. For Anthropic's native tool-use schema (with `cache_control`, server-side tools, etc.) call `/v1/messages` directly. ### `group` — string, default `"default"` api.reapi.ai-specific extension. Selects a token group on the gateway, which routes the request to a specific upstream channel pool. Omit if default routing is fine. **No sampling parameters.** Claude Fable 5 does not accept `temperature`, `top_p`, or `top_k` — Anthropic removed them on this model generation and requests that include them are rejected upstream. Steer style and variance through prompting instead. *** ## Adaptive thinking — always on Adaptive thinking is the **only** thinking mode on Claude Fable 5. It applies on every call — there is no way to disable it — and the model decides per request how much reasoning the task needs. Two consequences for integrators: * **Raw chain-of-thought is never returned.** Thinking blocks arrive with empty content by default. On the native `/v1/messages` surface, set `thinking: type adaptive, display summarized` (see Anthropic's adaptive-thinking docs for the exact field shape) to receive readable summarized thinking. * **Depth is tuned with `effort`, not a token budget.** On the native surface, `output_config.effort` accepts `low` through `max`. Higher effort means deeper reasoning and more output tokens; lower effort means faster, cheaper calls. *** ## Vision input (multimodal) Send images alongside text via OpenAI content-parts: ```json { "model": "claude-fable-5", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "What does this chart show?" }, { "type": "image_url", "image_url": { "url": "https://example.com/chart.png" } } ] } ] } ``` Supported image formats: PNG, JPEG, GIF, WebP. Each image counts toward the input token budget based on its resolution. *** ## Prompt caching Anthropic's prompt caching pays off on stable system prompts, recurring RAG context, and long multi-turn agent histories. The first call pays the cache-write rate on the cacheable region; subsequent calls within the cache window pay only the (much lower) cache-read rate on those tokens. To enable caching, call `/v1/messages` natively and add a `cache_control` block. Example: ```json { "model": "claude-fable-5", "max_tokens": 4096, "system": [ { "type": "text", "text": "", "cache_control": { "type": "ephemeral" } } ], "messages": [ { "role": "user", "content": "Question for the assistant" } ] } ``` The cache key is the hash of the cacheable content. See [api.reapi.ai/pricing](https://api.reapi.ai/pricing) for cache-read and cache-write rates. *** ## Refusals and fallback Claude Fable 5 includes safety classifiers that can decline certain requests. On the native `/v1/messages` surface a refusal is returned as a **successful response** with `stop_reason: "refusal"` — not an HTTP error — and the response reports which classifier declined the request. Two things follow: * **A request refused before any output is generated is not billed.** * **A refused request can usually be served by another Claude model.** Retry it with a different `model` value on the same key — Claude Opus 4.8 covers most workloads the classifier declines on Fable 5. Handle `stop_reason: "refusal"` (native surface) or an empty completion with a refusal marker (OpenAI surface) explicitly in your integration rather than treating it as a transport failure: it is deterministic for a given prompt, so a verbatim retry on the same model will refuse again. *** ## Response shape — `/v1/chat/completions` ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "object": "chat.completion", "created": 1749600000, "model": "claude-fable-5", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21, "prompt_tokens_details": { "cached_tokens": 0 } } } ``` `usage.prompt_tokens_details.cached_tokens` reports how many input tokens were served from cache — the part billed at the cache-read rate rather than the standard input rate. ### Streaming (`stream: true`) `Content-Type: text/event-stream`. Each `data:` line is a JSON delta in the OpenAI chunk format; the final event before `[DONE]` carries the `finish_reason` (`stop` / `length` / `tool_calls` / `content_filter`). *** ## Pricing Claude Fable 5 is billed **pay-as-you-go in USD** against your api.reapi.ai token balance. It bills along several dimensions — input tokens, output tokens, cache-read tokens, and per-request web search. The full 1M context window is billed at standard per-token rates with no long-context premium, and requests refused before any output is generated are not billed. Current rates live on [api.reapi.ai/pricing](https://api.reapi.ai/pricing) and in the pricing card at the top of the [model page](https://reapi.ai/models/claude-fable-5). Per-call bill: ``` billable_input = (prompt_tokens - cached_tokens) × input_rate / 1,000,000 cache_read_bill = cached_tokens × cache_read_rate / 1,000,000 output_bill = completion_tokens × output_rate / 1,000,000 ``` Cache-write rate applies on the first call that writes a cache block; subsequent hits pay only the cache-read rate. Web search, when used, is billed per request. Failed requests are not charged. *** ## Limits | Limit | Value | | ------------------- | ----------- | | Context window | 1M tokens | | Max output per call | 128K tokens | Streams that hit the output cap finish with `finish_reason: "length"`; call again with a continuation message if you need more text. *** ## Errors The error envelope follows the OpenAI shape — HTTP status, plus a JSON body: ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "..." } } ``` Common cases: | Status | When | Notes | | ------ | ----------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `400` | Missing `max_tokens`, sampling params sent, bad shape | Anthropic requires `max_tokens`; `temperature` / `top_p` / `top_k` are rejected on this model | | `401` | Missing / invalid API key | Re-issue a key at api.reapi.ai | | `402` | Insufficient balance | Top up at api.reapi.ai | | `429` | Per-group rate limit hit | Back off, or move to a different `group` | | `500` | Upstream / gateway error | Safe to retry — failed calls are not charged | api.reapi.ai does **not** internally retry chat requests. Every customer call maps to exactly one upstream POST. If a network error reaches you, that's a one-for-one wire failure and a retry from your side is safe; the upstream provider may have already produced output, but the gateway will not double-bill. *** ## Recipes ### Minimum request ```json { "model": "claude-fable-5", "max_tokens": 4096, "messages": [ { "role": "user", "content": "Summarise this in three sentences." } ] } ``` ### Tool use (function calling, OpenAI surface) ```json { "model": "claude-fable-5", "max_tokens": 4096, "messages": [ { "role": "user", "content": "What's the weather in Tokyo today?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Look up the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ], "tool_choice": "auto" } ``` ### Vision ```json { "model": "claude-fable-5", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Read the error in this screenshot and suggest a fix." }, { "type": "image_url", "image_url": { "url": "https://your-cdn.com/screenshot.png" } } ] } ] } ``` ### Long context with prompt caching (native Anthropic surface) ```json { "model": "claude-fable-5", "max_tokens": 4096, "system": [ { "type": "text", "text": "<800K-token reference document>", "cache_control": { "type": "ephemeral" } } ], "messages": [ { "role": "user", "content": "Find every mention of the constraint X and list them with line numbers." } ] } ``` *** ## When to pick Claude Fable 5 Pick Claude Fable 5 when the task sits past what Opus-tier models handle cleanly: * **Frontier long-horizon agentic work** — week-long refactors, codebase-scale migrations, autonomous runs that must stay coherent across hundreds of steps. * **The most demanding reasoning** — deep multi-step problems, ambiguous specifications, analysis where the answer quality justifies the top capability tier. * **Large-context analysis** — full codebases, long research packs, multi-document review, audit work across the 1M window. Route everyday premium coding to Claude Opus 4.8 and lighter traffic (classification, short replies, tight loops) to cheaper Claude or GPT models on the same key. *** ## Tips * **Set `max_tokens` generously.** Anthropic enforces it strictly — the model still stops at the natural end of its response, but a low cap will truncate before the real ending. * **Stream by default for chat UX.** Streaming cuts perceived latency dramatically — especially relevant here, since always-on adaptive thinking can add a pause before the first visible token. * **Don't send sampling parameters.** `temperature`, `top_p`, and `top_k` are rejected on Claude Fable 5. Steer variance and style through prompting. * **Cache the stable parts of long prompts.** A 500K-token RAG context on top of a 1KB user question can pay the cache-read rate on every subsequent call instead of the standard input rate — a big saving on multi-turn agents replaying long histories. * **Handle refusals as a first-class outcome.** Detect the refusal stop reason and retry on another Claude model instead of retrying verbatim. * **Use the native `/v1/messages` surface for Anthropic-only features.** `cache_control`, `effort`, summarized thinking display, native multi-block content, the full tool-use spec — all of those work through `/v1/messages` without needing translation. *** ## Related * [claude-opus-4-8](/docs/claude-opus-4-8) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Errors catalog](/docs/api/errors) --- # claude-opus-4-7 (https://reapi.ai/docs/claude-opus-4-7) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Claude Opus 4.7 is Anthropic's flagship model, exposed through > api.reapi.ai as a drop-in OpenAI-compatible Chat Completions endpoint > (the native Anthropic `/v1/messages` surface is also available). 1M > token context, 128K max output, vision input, prompt caching, and > tool use. Current rates live on the > [model page](https://reapi.ai/models/claude-opus-4-7) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-4-7", "group": "default", "messages": [ { "role": "user", "content": "Hello" } ], "stream": true, "max_tokens": 4096, "temperature": 0.7 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="claude-opus-4-7", messages=[{"role": "user", "content": "Hello"}], stream=True, max_tokens=4096, temperature=0.7, extra_body={"group": "default"}, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ```python from anthropic import Anthropic client = Anthropic( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai", ) with client.messages.stream( model="claude-opus-4-7", max_tokens=4096, messages=[{"role": "user", "content": "Hello"}], ) as stream: for text in stream.text_stream: print(text, end="", flush=True) ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "claude-opus-4-7", messages: [{ role: "user", content: "Hello" }], stream: true, max_tokens: 4096, temperature: 0.7, // `group` is an api.reapi.ai-specific extension; pass via extra body. // @ts-expect-error — not part of the OpenAI types group: "default", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "claude-opus-4-7", "group": "default", "messages": []map[string]string{ {"role": "user", "content": "Hello"}, }, "stream": true, "max_tokens": 4096, "temperature": 0.7, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Every request needs a Bearer token. The Claude Opus 4.7 chat workspace lives on the `api.reapi.ai` platform — sign in there to create a key and top up tokens. 1. Open [api.reapi.ai](https://api.reapi.ai/) and sign in (or create an account). 2. Generate an API key under **API Keys**. 3. Top up tokens under **Top Up** (pay-as-you-go, billed in USD per 1M tokens — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing)). ```http Authorization: Bearer YOUR_API_KEY ``` The chat surface (api.reapi.ai) is a **separate workspace** from the image/video/audio task gateway at `reapi.ai/api/v1/*`. Keys and balances do not cross over — a key issued on `reapi.ai/settings/apikeys` will not authenticate against `api.reapi.ai/v1/chat/completions`, and vice versa. *** ## Endpoints ```http POST https://api.reapi.ai/v1/chat/completions # OpenAI-compatible POST https://api.reapi.ai/v1/messages # Anthropic-native ``` Both surfaces accept `claude-opus-4-7`. Pick whichever matches your SDK of record: * **`/v1/chat/completions`** — drop-in for the OpenAI SDKs. Same request shape, same SSE wire format. Set `base_url` to `https://api.reapi.ai/v1`. * **`/v1/messages`** — native Anthropic Messages format. Set `base_url` to `https://api.reapi.ai` for the Anthropic Python / TypeScript SDKs. Required for callers that need Anthropic-specific features (`cache_control` blocks for prompt caching, native multi-block content, the full tool-use spec). *** ## Request body — `/v1/chat/completions` ### `model` — string, required Must be `"claude-opus-4-7"`. The value is echoed back in the response envelope. ### `messages` — array, required Conversation history as an array of message objects. Same shape as the OpenAI Chat Completions spec, plus content-parts for vision: ```json { "role": "system" | "user" | "assistant" | "tool", "content": "string OR content-parts array (text + image_url parts)" } ``` Multi-turn history is sent in chronological order — the last message is the one Claude responds to. ### `max_tokens` — integer, default `4096` Upper bound on output tokens. **Anthropic's API requires `max_tokens` on every call, including streamed ones** — even though the OpenAI SDKs treat it as optional. Set it generously (`128000` is the hard cap) for long-form outputs; the model still stops at the natural end of its response. ### `stream` — boolean, default `false` When `true`, the response is streamed as server-sent events (SSE) with `Content-Type: text/event-stream`. Each event is a JSON delta in the OpenAI format, terminated by a `data: [DONE]` line. ### `temperature` — number, default `1` Range `0.0` – `1.0`. Sampling temperature. Anthropic recommends **either** `temperature` or `top_p`, not both. Lower values produce more deterministic output. ### `top_p` — number, default `1` Range `0.0` – `1.0`. Nucleus sampling cutoff. ### `tools` / `tool_choice` — optional Standard OpenAI tool-calling parameters. Claude Opus 4.7 supports the full OpenAI tool-use spec via this surface; for Anthropic's native tool-use schema (with `cache_control`, `tool_choice_type`, etc.) call `/v1/messages` directly. ### `group` — string, default `"default"` api.reapi.ai-specific extension. Selects a token group on the gateway, which routes the request to a specific upstream channel pool. Omit if default routing is fine. *** ## Vision input (multimodal) Send images alongside text via OpenAI content-parts: ```json { "model": "claude-opus-4-7", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "What does this chart show?" }, { "type": "image_url", "image_url": { "url": "https://example.com/chart.png" } } ] } ] } ``` Supported image formats: PNG, JPEG, GIF, WebP. Base64 URLs work too — prefix `data:image/png;base64,...`. Each image counts toward the input token budget based on its resolution. *** ## Prompt caching Anthropic's prompt caching pays off on stable system prompts, recurring RAG context, and long multi-turn agent histories. The first call pays the cache-write rate on the cacheable region; subsequent calls within the cache window pay only the (much lower) cache-read rate on those tokens. To enable caching, call `/v1/messages` natively and add a `cache_control` block. Example: ```json { "model": "claude-opus-4-7", "max_tokens": 4096, "system": [ { "type": "text", "text": "", "cache_control": { "type": "ephemeral" } } ], "messages": [ { "role": "user", "content": "Question for the assistant" } ] } ``` The cache key is the hash of the cacheable content; the cache TTL is 5 minutes (default ephemeral) or 1 hour (extended ephemeral) depending on how the cache\_control block is configured. See [api.reapi.ai/pricing](https://api.reapi.ai/pricing) for cache-read and cache-write rates. *** ## Response shape — `/v1/chat/completions` ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "object": "chat.completion", "created": 1735000000, "model": "claude-opus-4-7", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21, "prompt_tokens_details": { "cached_tokens": 0 } } } ``` `usage.prompt_tokens_details.cached_tokens` reports how many input tokens were served from cache — the part billed at the cache-read rate rather than the standard input rate. ### Streaming (`stream: true`) `Content-Type: text/event-stream`. Each `data:` line is a JSON delta in the OpenAI chunk format; the final event before `[DONE]` carries the `finish_reason` (`stop` / `length` / `tool_calls` / `content_filter`). *** ## Pricing Claude Opus 4.7 is billed **pay-as-you-go in USD** against your api.reapi.ai token balance. Current rates (input, output, cache-read, cache-write) live on [api.reapi.ai/pricing](https://api.reapi.ai/pricing) and in the pricing card at the top of the [model page](https://reapi.ai/models/claude-opus-4-7). Per-call bill: ``` billable_input = (prompt_tokens - cached_tokens) × input_rate / 1,000,000 cache_read_bill = cached_tokens × cache_read_rate / 1,000,000 output_bill = completion_tokens × output_rate / 1,000,000 ``` Cache-write rate applies on the first call that writes a cache block; subsequent hits within the cache TTL pay only the cache-read rate. Failed requests are not charged. *** ## Limits | Limit | Value | | --------------------- | ----------- | | Context window | 1M tokens | | Max output per call | 128K tokens | | Cache TTL (ephemeral) | 5 minutes | | Cache TTL (extended) | 1 hour | Streams that hit the output cap finish with `finish_reason: "length"`; call again with a continuation message if you need more text. *** ## Errors The error envelope follows the OpenAI shape — HTTP status, plus a JSON body: ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "..." } } ``` Common cases: | Status | When | Notes | | ------ | ------------------------------------- | ----------------------------------------------------------------------- | | `400` | Missing `max_tokens`, bad shape, etc. | Anthropic requires `max_tokens`; OpenAI SDKs that omit it will 400 here | | `401` | Missing / invalid API key | Re-issue a key at api.reapi.ai | | `402` | Insufficient balance | Top up at api.reapi.ai | | `429` | Per-group rate limit hit | Back off, or move to a different `group` | | `500` | Upstream / gateway error | Safe to retry — failed calls are not charged | api.reapi.ai does **not** internally retry chat requests. Every customer call maps to exactly one upstream POST. If a network error reaches you, that's a one-for-one wire failure and a retry from your side is safe; the upstream provider may have already produced output, but the gateway will not double-bill. *** ## Recipes ### Minimum request ```json { "model": "claude-opus-4-7", "max_tokens": 4096, "messages": [ { "role": "user", "content": "Summarise this in three sentences." } ] } ``` ### Tool use (function calling, OpenAI surface) ```json { "model": "claude-opus-4-7", "max_tokens": 4096, "messages": [ { "role": "user", "content": "What's the weather in Tokyo today?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Look up the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ], "tool_choice": "auto" } ``` ### Vision ```json { "model": "claude-opus-4-7", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Read the error in this screenshot and suggest a fix." }, { "type": "image_url", "image_url": { "url": "https://your-cdn.com/screenshot.png" } } ] } ] } ``` ### Long context with prompt caching (native Anthropic surface) ```json { "model": "claude-opus-4-7", "max_tokens": 4096, "system": [ { "type": "text", "text": "<800K-token reference document>", "cache_control": { "type": "ephemeral" } } ], "messages": [ { "role": "user", "content": "Find every mention of the constraint X and list them with line numbers." } ] } ``` *** ## When to pick Claude Opus 4.7 Pick Claude Opus 4.7 when **output quality** dominates the decision: * **High-stakes coding and refactors** — architecture, multi-file refactor, migration planning, long-form engineering deliverables. * **Agent workflows that must hold state** — multi-step planning, reliable tool use, long agent runs where context drift kills the workflow. * **Large-context analysis** — full codebases, long research packs, multi-document review, audit work. Route lighter traffic (classification, short replies, tight loops) to cheaper Claude or GPT models on the same key. *** ## Tips * **Set `max_tokens` generously.** Anthropic enforces it strictly — the model still stops at the natural end of its response, but a low cap will truncate before the real ending. * **Stream by default for chat UX.** Streaming cuts perceived latency dramatically. * **Cache the stable parts of long prompts.** A 500K-token RAG context on top of a 1KB user question can pay the cache-read rate on every subsequent call instead of the standard input rate. Big savings on multi-turn agents. * **Tune `temperature` *or* `top_p`, not both.** Mixing them produces results that are hard to reason about. * **Use the native `/v1/messages` surface for Anthropic-only features.** `cache_control`, native multi-block content, full tool-use spec — all of those work through `/v1/messages` without needing translation. *** ## Related * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Errors catalog](/docs/api/errors) --- # claude-opus-4-8 (https://reapi.ai/docs/claude-opus-4-8) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Claude Opus 4.8 is Anthropic's most capable model for complex reasoning > and long-horizon agentic coding, exposed through api.reapi.ai as a > drop-in OpenAI-compatible Chat Completions endpoint (the native > Anthropic `/v1/messages` surface is also available). 1M token context, > 128K max output, vision input, prompt caching, and tool use. Current > rates live on the > [model page](https://reapi.ai/models/claude-opus-4-8) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-4-8", "group": "default", "messages": [ { "role": "user", "content": "Hello" } ], "stream": true, "max_tokens": 4096, "temperature": 0.7 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="claude-opus-4-8", messages=[{"role": "user", "content": "Hello"}], stream=True, max_tokens=4096, temperature=0.7, extra_body={"group": "default"}, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ```python from anthropic import Anthropic client = Anthropic( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai", ) with client.messages.stream( model="claude-opus-4-8", max_tokens=4096, messages=[{"role": "user", "content": "Hello"}], ) as stream: for text in stream.text_stream: print(text, end="", flush=True) ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "claude-opus-4-8", messages: [{ role: "user", content: "Hello" }], stream: true, max_tokens: 4096, temperature: 0.7, // `group` is an api.reapi.ai-specific extension; pass via extra body. // @ts-expect-error — not part of the OpenAI types group: "default", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "claude-opus-4-8", "group": "default", "messages": []map[string]string{ {"role": "user", "content": "Hello"}, }, "stream": true, "max_tokens": 4096, "temperature": 0.7, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Every request needs a Bearer token. The Claude Opus 4.8 chat workspace lives on the `api.reapi.ai` platform — sign in there to create a key and top up tokens. 1. Open [api.reapi.ai](https://api.reapi.ai/) and sign in (or create an account). 2. Generate an API key under **API Keys**. 3. Top up tokens under **Top Up** (pay-as-you-go, billed in USD per 1M tokens — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing)). ```http Authorization: Bearer YOUR_API_KEY ``` The chat surface (api.reapi.ai) is a **separate workspace** from the image/video/audio task gateway at `reapi.ai/api/v1/*`. Keys and balances do not cross over — a key issued on `reapi.ai/settings/apikeys` will not authenticate against `api.reapi.ai/v1/chat/completions`, and vice versa. *** ## Endpoints ```http POST https://api.reapi.ai/v1/chat/completions # OpenAI-compatible POST https://api.reapi.ai/v1/messages # Anthropic-native ``` Both surfaces accept `claude-opus-4-8`. Pick whichever matches your SDK of record: * **`/v1/chat/completions`** — drop-in for the OpenAI SDKs. Same request shape, same SSE wire format. Set `base_url` to `https://api.reapi.ai/v1`. * **`/v1/messages`** — native Anthropic Messages format. Set `base_url` to `https://api.reapi.ai` for the Anthropic Python / TypeScript SDKs. Required for callers that need Anthropic-specific features (`cache_control` blocks for prompt caching, native multi-block content, the full tool-use spec). *** ## Request body — `/v1/chat/completions` ### `model` — string, required Must be `"claude-opus-4-8"`. The value is echoed back in the response envelope. ### `messages` — array, required Conversation history as an array of message objects. Same shape as the OpenAI Chat Completions spec, plus content-parts for vision: ```json { "role": "system" | "user" | "assistant" | "tool", "content": "string OR content-parts array (text + image_url parts)" } ``` Multi-turn history is sent in chronological order — the last message is the one Claude responds to. ### `max_tokens` — integer, default `4096` Upper bound on output tokens. **Anthropic's API requires `max_tokens` on every call, including streamed ones** — even though the OpenAI SDKs treat it as optional. Set it generously (`128000` is the hard cap on the synchronous API) for long-form outputs; the model still stops at the natural end of its response. ### `stream` — boolean, default `false` When `true`, the response is streamed as server-sent events (SSE) with `Content-Type: text/event-stream`. Each event is a JSON delta in the OpenAI format, terminated by a `data: [DONE]` line. ### `temperature` — number, default `1` Range `0.0` – `1.0`. Sampling temperature. Anthropic recommends **either** `temperature` or `top_p`, not both. Lower values produce more deterministic output. ### `top_p` — number, default `1` Range `0.0` – `1.0`. Nucleus sampling cutoff. ### `tools` / `tool_choice` — optional Standard OpenAI tool-calling parameters. Claude Opus 4.8 supports the full OpenAI tool-use spec via this surface and uses tools more efficiently than prior Opus models — fewer steps for the same result. For Anthropic's native tool-use schema (with `cache_control`, `tool_choice_type`, etc.) call `/v1/messages` directly. ### `group` — string, default `"default"` api.reapi.ai-specific extension. Selects a token group on the gateway, which routes the request to a specific upstream channel pool. Omit if default routing is fine. *** ## Vision input (multimodal) Send images alongside text via OpenAI content-parts: ```json { "model": "claude-opus-4-8", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "What does this chart show?" }, { "type": "image_url", "image_url": { "url": "https://example.com/chart.png" } } ] } ] } ``` Supported image formats: PNG, JPEG, GIF, WebP. Base64 URLs work too — prefix `data:image/png;base64,...`. Each image counts toward the input token budget based on its resolution. *** ## Prompt caching Anthropic's prompt caching pays off on stable system prompts, recurring RAG context, and long multi-turn agent histories. The first call pays the cache-write rate on the cacheable region; subsequent calls within the cache window pay only the (much lower) cache-read rate on those tokens. To enable caching, call `/v1/messages` natively and add a `cache_control` block. Example: ```json { "model": "claude-opus-4-8", "max_tokens": 4096, "system": [ { "type": "text", "text": "", "cache_control": { "type": "ephemeral" } } ], "messages": [ { "role": "user", "content": "Question for the assistant" } ] } ``` The cache key is the hash of the cacheable content. See [api.reapi.ai/pricing](https://api.reapi.ai/pricing) for cache-read and cache-write rates. *** ## Response shape — `/v1/chat/completions` ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "object": "chat.completion", "created": 1735000000, "model": "claude-opus-4-8", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21, "prompt_tokens_details": { "cached_tokens": 0 } } } ``` `usage.prompt_tokens_details.cached_tokens` reports how many input tokens were served from cache — the part billed at the cache-read rate rather than the standard input rate. ### Streaming (`stream: true`) `Content-Type: text/event-stream`. Each `data:` line is a JSON delta in the OpenAI chunk format; the final event before `[DONE]` carries the `finish_reason` (`stop` / `length` / `tool_calls` / `content_filter`). *** ## Pricing Claude Opus 4.8 is billed **pay-as-you-go in USD** against your api.reapi.ai token balance. It bills along several dimensions — input tokens, output tokens, cache-read tokens, and per-request web search. Current rates live on [api.reapi.ai/pricing](https://api.reapi.ai/pricing) and in the pricing card at the top of the [model page](https://reapi.ai/models/claude-opus-4-8). Per-call bill: ``` billable_input = (prompt_tokens - cached_tokens) × input_rate / 1,000,000 cache_read_bill = cached_tokens × cache_read_rate / 1,000,000 output_bill = completion_tokens × output_rate / 1,000,000 ``` Cache-write rate applies on the first call that writes a cache block; subsequent hits pay only the cache-read rate. Web search, when used, is billed per request. Failed requests are not charged. *** ## Limits | Limit | Value | | ------------------- | ----------- | | Context window | 1M tokens | | Max output per call | 128K tokens | Streams that hit the output cap finish with `finish_reason: "length"`; call again with a continuation message if you need more text. *** ## Errors The error envelope follows the OpenAI shape — HTTP status, plus a JSON body: ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "..." } } ``` Common cases: | Status | When | Notes | | ------ | ------------------------------------- | ----------------------------------------------------------------------- | | `400` | Missing `max_tokens`, bad shape, etc. | Anthropic requires `max_tokens`; OpenAI SDKs that omit it will 400 here | | `401` | Missing / invalid API key | Re-issue a key at api.reapi.ai | | `402` | Insufficient balance | Top up at api.reapi.ai | | `429` | Per-group rate limit hit | Back off, or move to a different `group` | | `500` | Upstream / gateway error | Safe to retry — failed calls are not charged | api.reapi.ai does **not** internally retry chat requests. Every customer call maps to exactly one upstream POST. If a network error reaches you, that's a one-for-one wire failure and a retry from your side is safe; the upstream provider may have already produced output, but the gateway will not double-bill. *** ## Recipes ### Minimum request ```json { "model": "claude-opus-4-8", "max_tokens": 4096, "messages": [ { "role": "user", "content": "Summarise this in three sentences." } ] } ``` ### Tool use (function calling, OpenAI surface) ```json { "model": "claude-opus-4-8", "max_tokens": 4096, "messages": [ { "role": "user", "content": "What's the weather in Tokyo today?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Look up the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ], "tool_choice": "auto" } ``` ### Vision ```json { "model": "claude-opus-4-8", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Read the error in this screenshot and suggest a fix." }, { "type": "image_url", "image_url": { "url": "https://your-cdn.com/screenshot.png" } } ] } ] } ``` ### Long context with prompt caching (native Anthropic surface) ```json { "model": "claude-opus-4-8", "max_tokens": 4096, "system": [ { "type": "text", "text": "<800K-token reference document>", "cache_control": { "type": "ephemeral" } } ], "messages": [ { "role": "user", "content": "Find every mention of the constraint X and list them with line numbers." } ] } ``` *** ## When to pick Claude Opus 4.8 Pick Claude Opus 4.8 when **output quality and reliability** dominate the decision: * **Long-horizon agentic coding** — multi-service refactors, codebase-scale migrations, and agent runs that must stay on-task across many steps. * **High-stakes reasoning** — work where a confident-but-wrong answer has real downstream cost. Opus 4.8 is more likely to flag uncertainty than to overclaim. * **Large-context analysis** — full codebases, long research packs, multi-document review, audit work. Route lighter traffic (classification, short replies, tight loops) to cheaper Claude or GPT models on the same key. *** ## Tips * **Set `max_tokens` generously.** Anthropic enforces it strictly — the model still stops at the natural end of its response, but a low cap will truncate before the real ending. * **Stream by default for chat UX.** Streaming cuts perceived latency dramatically. * **Cache the stable parts of long prompts.** A 500K-token RAG context on top of a 1KB user question can pay the cache-read rate on every subsequent call instead of the standard input rate — a big saving on multi-turn agents replaying long histories. * **Tune `temperature` *or* `top_p`, not both.** Mixing them produces results that are hard to reason about. * **Use the native `/v1/messages` surface for Anthropic-only features.** `cache_control`, native multi-block content, full tool-use spec — all of those work through `/v1/messages` without needing translation. *** ## Related * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Errors catalog](/docs/api/errors) --- # claude-opus-5 (https://reapi.ai/docs/claude-opus-5) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Anthropic's Claude Opus 5 — "for complex agentic coding and enterprise work" — > exposed through api.reapi.ai as a drop-in OpenAI-compatible Chat Completions > endpoint. A **1M-token** context window, **128k** max output, **adaptive > thinking on by default**, an effort dial from `low` through `max`, plus tool > use, structured outputs, code execution, vision and PDF input. The wire `model` > id is `claude-opus-5` — Anthropic's alias carries no date suffix. Current rates > live on the [model page](https://reapi.ai/models/claude-opus-5) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-5", "messages": [ { "role": "user", "content": "Refactor this module and add tests." } ], "stream": true, "max_tokens": 16000 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="claude-opus-5", messages=[{"role": "user", "content": "Refactor this module and add tests."}], max_tokens=16000, stream=True, ) for chunk in stream: delta = chunk.choices[0].delta.content if delta: print(delta, end="") ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "claude-opus-5", messages: [{ role: "user", content: "Refactor this module and add tests." }], max_tokens: 16000, stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "claude-opus-5", "messages": []map[string]string{ {"role": "user", "content": "Refactor this module and add tests."}, }, "max_tokens": 16000, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Chat models are served from the `api.reapi.ai` gateway, which has its own console and its own key. Create the key there, then send it as a bearer token: ```http Authorization: Bearer YOUR_API_KEY ``` The gateway key is **not** the same credential as a media-generation key used against `reapi.ai/api/v1`. Sign in at [api.reapi.ai](https://api.reapi.ai/) to create one. *** ## Endpoint ```http POST /v1/chat/completions ``` Base URL `https://api.reapi.ai`. The wire format is OpenAI-compatible, so the same SDKs (`openai-python`, `openai-node`, `openai-go`, …) work once you swap the base URL, the key and the model string. *** ## Request body ### `model` — string, required Must be `claude-opus-5` exactly. Anthropic's alias carries no date suffix, so there is nothing to append. ### `messages` — array, required Conversation history, each entry an object with `role` and `content`. Roles are `system`, `user` and `assistant`. Text, image and PDF parts are supported — see [Multimodal input](#multimodal-input). ### `max_tokens` — integer Upper bound on output tokens for this response, **thinking tokens included**. Anthropic documents a **128k**-token output ceiling for this model. **Thinking is on by default on this model**, and `max_tokens` caps thinking plus response text together. A budget carried over from a model that ran without thinking can truncate mid-answer. Raise it, or turn thinking off — subject to the effort cap below. ### `stream` — boolean, default `false` When `true`, tokens arrive as server-sent events terminated by `data: [DONE]`. Recommended for anything a person watches, and effectively required for large `max_tokens` values — a non-streamed request with a big budget can hit an HTTP timeout. ### `thinking` — object, optional Omit it and the model runs **adaptive thinking**. See [Thinking](#thinking) for the two rules that differ from the previous Opus generation. ### `output_config` — object, optional Carries `effort` and the structured-output format. See [Effort](#effort). ### `tools` / `tool_choice` — optional Tool definitions and the strategy for picking among them. ### `group` — string, default `"default"` Token group on the gateway. Leave it at `default` unless your account has been given another group to route through. *** ## Thinking Two things differ from the previous Opus generation, and both bite code that was carried straight over. **1. Thinking runs when you omit the parameter.** On the previous generation, omitting `thinking` meant no thinking. Here it runs adaptive. That is a silent cost and truncation change on any route that never set the field. **2. Turning thinking off is capped at `high` effort.** `thinking` disabled is accepted only at effort `high` or lower; pairing it with `xhigh` or `max` is rejected. The check runs **per request**, so a later call that raises effort while thinking is still disabled fails even though earlier calls in the same conversation succeeded. **The raw chain of thought is never returned on this model.** The default is omitted; ask for a summary if you surface reasoning to users. Fixed thinking-token budgets are not accepted. Given how well this model performs at `low` and `medium` effort, a latency-sensitive route is usually better served by lowering effort than by disabling thinking. *** ## Effort `output_config.effort` takes five levels — `low`, `medium`, `high`, `xhigh`, `max` — and **defaults to `high`** on the Claude API. | Level | Use it for | | -------- | ------------------------------------------------------------------------------------ | | `max` | The hardest reasoning, where correctness outweighs cost. Can overthink routine work. | | `xhigh` | Coding and agentic workloads — the recommended starting point for those. | | `high` | The default; intelligence-sensitive work generally. | | `medium` | A cost step-down that holds up unusually well on this model. | | `low` | Short, scoped, latency-sensitive tasks. | Effort is the primary cost and latency lever here — start at `xhigh` for coding/agentic work and `high` elsewhere, then sweep downward against your own evals. Defaults carried over from an older model rarely transfer. At `xhigh` or `max`, set a large `max_tokens` so there is room to think and act across tool calls. *** ## Parameters that are no longer accepted These are rejected on this generation. Remove them rather than working around them: | Parameter | Do this instead | | ------------------------------- | ------------------------------------------------------ | | `temperature`, `top_p`, `top_k` | Steer with prompting and the `effort` level | | Fixed thinking-token budget | Use `effort` | | Last-assistant-turn prefill | Use structured outputs, or a system-prompt instruction | *** ## Multimodal input | Modality | Supported | | -------- | :-------: | | Text | ✅ | | Image | ✅ | | PDF | ✅ | Output is **text only**. Vision is strong on charts, diagrams and dense documents — and on this model, giving it tools to crop and re-examine an image is a more cost-effective lever than raising thinking depth alone. *** ## Pricing dimensions Billing is **per token**, in USD, against your `api.reapi.ai` balance, with separate **input** and **output** rates. Three things to keep in mind: * **Thinking tokens bill as output.** Since thinking is on by default here, that is the usual reason a bill exceeds an estimate built from visible response length alone. * **Output dominates.** For most generative workloads the output rate decides the invoice. * **Effort moves the bill.** It changes how much the model thinks and how many tool calls it makes, so it is the lever to tune before anything else. Both token rates sit at **less than half Anthropic's published per-token rate**. Current numbers are on the [model page](https://reapi.ai/models/claude-opus-5) and [api.reapi.ai/pricing](https://api.reapi.ai/pricing) — those tables are the canonical source, not this page. Chat models bill in USD on the gateway balance. They do **not** draw down the integer credits used by the media-generation endpoints on `reapi.ai/api/v1`. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1785000000, "model": "claude-opus-5", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 1204, "completion_tokens": 860, "total_tokens": 2064 } } ``` `usage.completion_tokens` includes thinking tokens, so it is the number to reconcile a bill against. ### Streaming (`stream: true`) Server-sent events, each `data:` line carrying a `chat.completion.chunk` with the incremental text in `choices[0].delta.content`, terminated by `data: [DONE]`. *** ## Errors Failures use the gateway's standard envelope. See the [errors catalog](/docs/api/errors) for the full code list. Common cases: | Trigger | What to do | | ------------------------------------------- | ----------------------------------------------------- | | Missing or invalid bearer token | Create a key in the api.reapi.ai console | | Unknown `model` value | Send `claude-opus-5` exactly — no date suffix | | `temperature` / `top_p` / `top_k` present | Remove them; they are not accepted on this generation | | Thinking disabled at `xhigh` / `max` effort | Lower effort to `high`, or leave thinking on | | `max_tokens` above the model ceiling | Lower it; the documented ceiling is 128k | | Insufficient balance | Top up on the gateway | | Upstream rate limit | Retry with backoff, or route through another model | Anthropic runs elevated safety classifiers on this generation. A declined request can come back as a **successful response whose stop reason is a refusal**, with an empty or partial body rather than an error. Check the stop reason before reading the content — code that indexes the first content block unconditionally will break on a refusal. *** ## Tips * **Give the whole task up front.** This model is built for long-horizon autonomous work; a complete specification in one turn outperforms revealing the task across many short interactive turns. * **Stream anything interactive**, and stream anything with a large `max_tokens`. * **Budget for thinking.** If responses truncate mid-sentence on hard prompts, the reasoning pass consumed the allowance — raise `max_tokens`. * **Sweep effort, don't inherit it.** `low` and `medium` are unusually strong here; the right level is workload-specific. * **Delete "double-check your work" instructions.** This model verifies its own output without being told, and telling it to verify causes redundant work. * **Ask for coverage in code review, then filter.** Instructions like "only report high-severity issues" are followed literally, which depresses measured recall. Have it report everything with confidence and severity, and filter in a separate pass. * **Short prompts cache now.** The minimum cacheable prefix is 512 tokens, half the previous generation's floor — prompts you had written off as uncacheable may qualify. *** ## Related * [Claude Opus 5 model page](https://reapi.ai/models/claude-opus-5) — current rates * [Claude Opus 4.8](/docs/claude-opus-4-8) — the previous generation * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # claude-sonnet-4-6 (https://reapi.ai/docs/claude-sonnet-4-6) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Claude Sonnet 4.6 is Anthropic's balanced everyday chat model, exposed > through api.reapi.ai as a drop-in OpenAI-compatible Chat Completions > endpoint (native Anthropic `/v1/messages` also available). 1M token > context, 128K max output, vision input, tool use, and fast production > latency. Current rates live on the > [model page](https://reapi.ai/models/claude-sonnet-4-6) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-6", "group": "default", "messages": [ { "role": "user", "content": "Hello" } ], "stream": true, "max_tokens": 4096, "temperature": 0.7 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="claude-sonnet-4-6", messages=[{"role": "user", "content": "Hello"}], stream=True, max_tokens=4096, temperature=0.7, extra_body={"group": "default"}, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ```python from anthropic import Anthropic client = Anthropic( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai", ) with client.messages.stream( model="claude-sonnet-4-6", max_tokens=4096, messages=[{"role": "user", "content": "Hello"}], ) as stream: for text in stream.text_stream: print(text, end="", flush=True) ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "claude-sonnet-4-6", messages: [{ role: "user", content: "Hello" }], stream: true, max_tokens: 4096, temperature: 0.7, // @ts-expect-error — `group` is an api.reapi.ai-specific extension group: "default", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "claude-sonnet-4-6", "group": "default", "messages": []map[string]string{ {"role": "user", "content": "Hello"}, }, "stream": true, "max_tokens": 4096, "temperature": 0.7, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Every request needs a Bearer token. The Claude Sonnet 4.6 chat workspace lives on the `api.reapi.ai` platform — sign in there to create a key and top up tokens. 1. Open [api.reapi.ai](https://api.reapi.ai/) and sign in (or create an account). 2. Generate an API key under **API Keys**. 3. Top up tokens under **Top Up** (pay-as-you-go, billed in USD per 1M tokens — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing)). ```http Authorization: Bearer YOUR_API_KEY ``` The chat surface (api.reapi.ai) is a **separate workspace** from the image/video/audio task gateway at `reapi.ai/api/v1/*`. Keys and balances do not cross over — a key issued on `reapi.ai/settings/apikeys` will not authenticate against `api.reapi.ai/v1/chat/completions`, and vice versa. *** ## Endpoints ```http POST https://api.reapi.ai/v1/chat/completions # OpenAI-compatible POST https://api.reapi.ai/v1/messages # Anthropic-native ``` Both surfaces accept `claude-sonnet-4-6`. Pick whichever matches your SDK of record: * **`/v1/chat/completions`** — drop-in for the OpenAI SDKs. Same request shape, same SSE wire format. Set `base_url` to `https://api.reapi.ai/v1`. * **`/v1/messages`** — native Anthropic Messages format. Set `base_url` to `https://api.reapi.ai` for the Anthropic Python / TypeScript SDKs. Use this when you want the full Anthropic tool-use spec or native content blocks. *** ## Request body — `/v1/chat/completions` ### `model` — string, required Must be `"claude-sonnet-4-6"`. The value is echoed back in the response envelope. ### `messages` — array, required Conversation history as an array of message objects. Same shape as the OpenAI Chat Completions spec, plus content-parts for vision: ```json { "role": "system" | "user" | "assistant" | "tool", "content": "string OR content-parts array (text + image_url parts)" } ``` ### `max_tokens` — integer, default `4096` Upper bound on output tokens. **Anthropic's API requires `max_tokens` on every call, including streamed ones** — even though the OpenAI SDKs treat it as optional. Set it generously (`128000` is the hard cap); the model still stops at the natural end of its response. ### `stream` — boolean, default `false` When `true`, the response is streamed as server-sent events (SSE) with `Content-Type: text/event-stream`. Each event is a JSON delta in the OpenAI format, terminated by a `data: [DONE]` line. ### `temperature` — number, default `1` Range `0.0` – `1.0`. Sampling temperature. Anthropic recommends tuning **either** `temperature` or `top_p`, not both. ### `top_p` — number, default `1` Range `0.0` – `1.0`. Nucleus sampling cutoff. ### `tools` / `tool_choice` — optional Standard OpenAI tool-calling parameters. For Anthropic's native tool-use schema, call `/v1/messages` directly. ### `group` — string, default `"default"` api.reapi.ai-specific extension. Selects a token group on the gateway. Omit if default routing is fine. *** ## Vision input Send images alongside text via OpenAI content-parts: ```json { "model": "claude-sonnet-4-6", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Summarise the error in this screenshot." }, { "type": "image_url", "image_url": { "url": "https://example.com/screenshot.png" } } ] } ] } ``` Supported formats: PNG, JPEG, GIF, WebP. Base64 URLs work too (`data:image/png;base64,...`). Each image counts toward the input token budget based on its resolution. *** ## Response shape — `/v1/chat/completions` ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "object": "chat.completion", "created": 1735000000, "model": "claude-sonnet-4-6", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21 } } ``` ### Streaming (`stream: true`) `Content-Type: text/event-stream`. Each `data:` line is a JSON delta in the OpenAI chunk format; the final event before `[DONE]` carries the `finish_reason` (`stop` / `length` / `tool_calls` / `content_filter`). *** ## Pricing Claude Sonnet 4.6 is billed **pay-as-you-go in USD** against your api.reapi.ai token balance. Current rates live on [api.reapi.ai/pricing](https://api.reapi.ai/pricing) and in the pricing card at the top of the [model page](https://reapi.ai/models/claude-sonnet-4-6). Per-call bill: ``` input_cost = prompt_tokens × input_rate / 1,000,000 output_cost = completion_tokens × output_rate / 1,000,000 ``` Failed requests are not charged. *** ## Limits | Limit | Value | | ------------------- | ----------- | | Context window | 1M tokens | | Max output per call | 128K tokens | Streams that hit the output cap finish with `finish_reason: "length"`; call again with a continuation message if you need more text. *** ## Errors The error envelope follows the OpenAI shape: ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "..." } } ``` | Status | When | Notes | | ------ | ------------------------------------- | ----------------------------------------------------------------------- | | `400` | Missing `max_tokens`, bad shape, etc. | Anthropic requires `max_tokens`; OpenAI SDKs that omit it will 400 here | | `401` | Missing / invalid API key | Re-issue a key at api.reapi.ai | | `402` | Insufficient balance | Top up at api.reapi.ai | | `429` | Per-group rate limit hit | Back off, or move to a different `group` | | `500` | Upstream / gateway error | Safe to retry — failed calls are not charged | api.reapi.ai does **not** internally retry chat requests. Every customer call maps to exactly one upstream POST. If a network error reaches you, that's a one-for-one wire failure and a retry from your side is safe; the upstream provider may have already produced output, but the gateway will not double-bill. *** ## Recipes ### Minimum request ```json { "model": "claude-sonnet-4-6", "max_tokens": 4096, "messages": [ { "role": "user", "content": "Summarise this in three sentences." } ] } ``` ### Tool use (function calling) ```json { "model": "claude-sonnet-4-6", "max_tokens": 4096, "messages": [ { "role": "user", "content": "What's the weather in Tokyo?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Look up the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ], "tool_choice": "auto" } ``` ### Vision ```json { "model": "claude-sonnet-4-6", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Read the error in this screenshot and suggest a fix." }, { "type": "image_url", "image_url": { "url": "https://your-cdn.com/screenshot.png" } } ] } ] } ``` *** ## When to pick Claude Sonnet 4.6 over Claude Opus 4.7 Both share the same endpoint, the same context window, and the same OpenAI-compatible wire format — switching is a one-line change in the `model` field. Pick Claude Sonnet 4.6 when: * **Production chat traffic** where time-to-first-token shows up in user-experience metrics. * **Code review and PR triage** that runs across high volume. * **Mid-complexity agents** where Claude-grade reasoning is enough and Opus-tier reasoning would be overkill. * **Default routing** — use Sonnet as the everyday model and escalate to Opus for the genuinely hard turns. Pick Claude Opus 4.7 for high-stakes coding, large refactors, complex multi-step agents, and long-context analysis where output quality dominates the decision. *** ## Tips * **Set `max_tokens` generously.** Anthropic enforces it strictly; the model still stops at the natural end of its response, but a low cap will truncate before the real ending. * **Stream by default for chat UX.** Sonnet's lower time-to-first-token makes the perceived latency advantage especially visible in streamed responses. * **Tune `temperature` *or* `top_p`, not both.** Mixing them produces results that are hard to reason about. * **Use Sonnet as the default and escalate to Opus.** The cleanest production pattern: route everything to Sonnet, switch to Opus on the calls where quality matters most. *** ## Related * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Errors catalog](/docs/api/errors) --- # deepseek-v4 (https://reapi.ai/docs/deepseek-v4) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > The DeepSeek V4 API ships two open-weight models — **`deepseek-v4-flash`** > (fast, low-cost) and **`deepseek-v4-pro`** (frontier reasoning and agentic > coding) — exposed through api.reapi.ai as a drop-in OpenAI-compatible Chat > Completions endpoint. Both bring a 1M-token context window, 384K max output, > thinking mode on by default, vision input, tool use, and context caching. > Current rates live on the > [model page](https://reapi.ai/models/deepseek-v4) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-v4-flash", "group": "default", "messages": [ { "role": "user", "content": "Hello" } ], "stream": true, "max_tokens": 4096, "temperature": 0.7 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="deepseek-v4-flash", # or "deepseek-v4-pro" messages=[{"role": "user", "content": "Hello"}], stream=True, max_tokens=4096, temperature=0.7, extra_body={"group": "default"}, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "deepseek-v4-flash", // or "deepseek-v4-pro" messages: [{ role: "user", content: "Hello" }], stream: true, max_tokens: 4096, temperature: 0.7, // `group` is an api.reapi.ai-specific extension; pass via extra body. // @ts-expect-error — not part of the OpenAI types group: "default", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "deepseek-v4-flash", // or "deepseek-v4-pro" "group": "default", "messages": []map[string]string{ {"role": "user", "content": "Hello"}, }, "stream": true, "max_tokens": 4096, "temperature": 0.7, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Every request needs a Bearer token. The DeepSeek V4 chat workspace lives on the `api.reapi.ai` platform — sign in there to create a key and top up tokens. 1. Open [api.reapi.ai](https://api.reapi.ai/) and sign in (or create an account). 2. Generate an API key under **API Keys**. 3. Top up tokens under **Top Up** (pay-as-you-go, billed in USD per 1M tokens — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing)). ```http Authorization: Bearer YOUR_API_KEY ``` The chat surface (api.reapi.ai) is a **separate workspace** from the image/video/audio task gateway at `reapi.ai/api/v1/*`. Keys and balances do not cross over — a key issued on `reapi.ai/settings/apikeys` will not authenticate against `api.reapi.ai/v1/chat/completions`, and vice versa. *** ## Models The DeepSeek V4 family ships two variants. Both share the same endpoint, request shape, 1M context window, and 384K max output — pick the variant with the `model` field. | `model` | Best for | Architecture | | ------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------- | | `deepseek-v4-flash` | Fast, low-cost everyday work — autocomplete, batch analysis, chat backends. Reasoning closely approaches Pro. | 284B total / 13B active (MoE) | | `deepseek-v4-pro` | Frontier reasoning, complex debugging, and agentic coding. Rivals top closed-source models. | 1.6T total / 49B active (MoE) | The legacy ids `deepseek-chat` and `deepseek-reasoner` map to `deepseek-v4-flash` in non-thinking and thinking mode respectively. New integrations should use the explicit `deepseek-v4-flash` / `deepseek-v4-pro` ids. *** ## Endpoint ```http POST https://api.reapi.ai/v1/chat/completions ``` Drop-in for the OpenAI SDKs — same request shape, same SSE wire format. Set `base_url` to `https://api.reapi.ai/v1`. DeepSeek V4 also supports the Anthropic API format natively; this guide documents the OpenAI-compatible Chat Completions surface. *** ## Request body ### `model` — string, required `"deepseek-v4-flash"` or `"deepseek-v4-pro"`. Echoed back in the response envelope. ### `messages` — array, required Conversation history as an array of message objects. Same shape as the OpenAI Chat Completions spec, plus content-parts for vision: ```json { "role": "system" | "user" | "assistant" | "tool", "content": "string OR content-parts array (text + image_url parts)" } ``` Multi-turn history is sent in chronological order — the last message is the one the model responds to. Do **not** echo a prior turn's `reasoning_content` back into `messages`; strip it before the next request. ### `max_tokens` — integer, default `4096` Upper bound on output tokens for this response, **including the chain-of-thought when thinking mode is on**. The synchronous API supports up to 384K output tokens — set it generously for long-form or reasoning-heavy outputs. ### `stream` — boolean, default `false` When `true`, the response is streamed as server-sent events (SSE) with `Content-Type: text/event-stream`. Each event is a JSON delta in the OpenAI format, terminated by a `data: [DONE]` line. ### `temperature` — number, default `1` Sampling temperature. Lower values produce more deterministic output. **Ignored while the model is in thinking mode.** ### `top_p` — number, default `1` Nucleus sampling cutoff. Ignored in thinking mode. ### `frequency_penalty` / `presence_penalty` — number, default `0` Standard OpenAI repetition controls. Ignored in thinking mode. ### `tools` / `tool_choice` — optional Standard OpenAI tool-calling parameters. DeepSeek V4 ships dedicated agentic optimizations with reliable function calling and JSON output. ### `group` — string, default `"default"` api.reapi.ai-specific extension. Selects a token group on the gateway, which routes the request to a specific upstream channel pool. Omit if default routing is fine. *** ## Thinking mode DeepSeek V4 runs in **thinking mode by default**: before the final answer it produces a chain of thought, returned in a `reasoning_content` field at the same level as `content`. ```json { "choices": [ { "index": 0, "message": { "role": "assistant", "reasoning_content": "Let me work through this step by step...", "content": "The final answer." }, "finish_reason": "stop" } ] } ``` For latency-sensitive or simple calls, switch to **non-thinking mode** for faster, cheaper responses. When thinking is on, the sampling parameters (`temperature`, `top_p`, `frequency_penalty`, `presence_penalty`) have no effect. Strip `reasoning_content` from assistant messages before sending them back in a follow-up request — the chain-of-thought from a previous turn is not meant to be re-fed as input. *** ## Vision input (beta) Send images alongside text via OpenAI content-parts: ```json { "model": "deepseek-v4-pro", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "What does this chart show?" }, { "type": "image_url", "image_url": { "url": "https://example.com/chart.png" } } ] } ] } ``` Each image counts toward the input token budget based on its resolution. *** ## Context caching DeepSeek V4 caches stable prompt prefixes automatically. When a request hits the cache, the cached input tokens bill at a small fraction of the standard input rate — a big saving for agent loops and chatbots that replay long system prompts and tool schemas. No configuration is required; reuse the same prefix across calls and the discount applies. The `usage.prompt_tokens_details.cached_tokens` field reports how many input tokens were served from cache. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "object": "chat.completion", "created": 1735000000, "model": "deepseek-v4-flash", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21, "prompt_tokens_details": { "cached_tokens": 0 } } } ``` When thinking mode is on, `message.reasoning_content` carries the chain-of-thought alongside `content`. ### Streaming (`stream: true`) `Content-Type: text/event-stream`. Each `data:` line is a JSON delta in the OpenAI chunk format; the final event before `[DONE]` carries the `finish_reason` (`stop` / `length` / `tool_calls` / `content_filter`). *** ## Pricing DeepSeek V4 is billed **pay-as-you-go in USD** against your api.reapi.ai token balance. It bills along three dimensions — input tokens (cache miss), input tokens (cache hit), and output tokens — and `deepseek-v4-pro` costs more per token than `deepseek-v4-flash`. Current rates live on [api.reapi.ai/pricing](https://api.reapi.ai/pricing) and in the pricing card at the top of the [model page](https://reapi.ai/models/deepseek-v4). Per-call bill: ``` billable_input = (prompt_tokens - cached_tokens) × input_rate / 1,000,000 cache_read_bill = cached_tokens × cache_hit_rate / 1,000,000 output_bill = completion_tokens × output_rate / 1,000,000 ``` Output tokens include the chain-of-thought when thinking mode is on. Failed requests are not charged. *** ## Limits | Limit | Value | | ------------------- | ----------- | | Context window | 1M tokens | | Max output per call | 384K tokens | Streams that hit the output cap finish with `finish_reason: "length"`; call again with a continuation message if you need more text. *** ## Errors The error envelope follows the OpenAI shape — HTTP status, plus a JSON body: ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "..." } } ``` Common cases: | Status | When | Notes | | ------ | ------------------------------------------ | -------------------------------------------- | | `400` | Bad request shape, unsupported param combo | Check the `messages` array and `model` id | | `401` | Missing / invalid API key | Re-issue a key at api.reapi.ai | | `402` | Insufficient balance | Top up at api.reapi.ai | | `429` | Per-group rate limit hit | Back off, or move to a different `group` | | `500` | Upstream / gateway error | Safe to retry — failed calls are not charged | api.reapi.ai does **not** internally retry chat requests. Every customer call maps to exactly one upstream POST. If a network error reaches you, that is a one-for-one wire failure and a retry from your side is safe; the gateway will not double-bill. *** ## Recipes ### Minimum request ```json { "model": "deepseek-v4-flash", "max_tokens": 4096, "messages": [ { "role": "user", "content": "Summarise this in three sentences." } ] } ``` ### Tool use (function calling) ```json { "model": "deepseek-v4-pro", "max_tokens": 4096, "messages": [ { "role": "user", "content": "What's the weather in Tokyo today?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Look up the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ], "tool_choice": "auto" } ``` ### Long-context analysis ```json { "model": "deepseek-v4-pro", "max_tokens": 8192, "messages": [ { "role": "system", "content": "" }, { "role": "user", "content": "List every mention of constraint X with line numbers." } ] } ``` Keep the long reference block stable across calls so the cache-hit rate applies on subsequent requests. *** ## When to pick Flash vs Pro * **`deepseek-v4-flash`** — latency-sensitive, high-throughput, cost-sensitive work: in-IDE autocomplete, inline suggestions, CI code review, bulk summarization, chat backends. Reasoning closely approaches Pro at a fraction of the price. * **`deepseek-v4-pro`** — work where reasoning depth dominates: complex debugging, architecture planning, math/STEM, and long-horizon agentic coding. Both share one key — route per request. *** ## Tips * **Set `max_tokens` generously when thinking is on.** The chain-of-thought counts toward the output budget; a low cap can truncate before the final answer. * **Strip `reasoning_content` before the next turn.** Re-feeding a prior turn's chain-of-thought as input is not supported. * **Stream by default for chat UX.** Streaming cuts perceived latency. * **Cache stable prefixes.** Reuse the same system prompt and tool schemas across calls to bill repeated input at the low cache-hit rate. * **Route by difficulty.** Send simple, high-volume calls to Flash and reserve Pro for the hardest reasoning, all on one key. *** ## Related * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Errors catalog](/docs/api/errors) --- # enhance-video-1.0 (https://reapi.ai/docs/enhance-video-1-0) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > `enhance-video-1.0` is a single async endpoint that takes a source video URL and > returns a higher-quality MP4 — upscaled, denoised, smart-interpolated, with > optional scene-aware restoration. Two quality tiers (**standard** / > **professional**) and five scene presets cover everything from AI-generated > footage to old-film restoration. See current pricing on the > [model page](https://reapi.ai/models/enhance-video-1-0). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "enhance-video-1.0", "video_url": "https://cdn.example.com/source_720p.mp4", "tool_version": "standard", "scene": "aigc", "resolution": "1080p" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "enhance-video-1.0", "video_url": "https://cdn.example.com/source_720p.mp4", "tool_version": "standard", "scene": "aigc", "resolution": "1080p", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "enhance-video-1.0", video_url: "https://cdn.example.com/source_720p.mp4", tool_version: "standard", scene: "aigc", resolution: "1080p", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "enhance-video-1.0", "video_url": "https://cdn.example.com/source_720p.mp4", "tool_version": "standard", "scene": "aigc", "resolution": "1080p", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "enhance-video-1.0", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` until `status === "completed"`. The completed payload's `output.video_urls` holds the enhanced MP4 URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; polling the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required Always `"enhance-video-1.0"`. ### `video_url` — required (string) Public HTTP/HTTPS URL of the source video. * **Allowed schemes:** `http://`, `https://` only. Base64 / `data:` URIs are rejected. * **Formats:** mp4, flv, ts, avi, mov, wmv, mkv (and most other mainstream containers). * **Size:** up to **10 GB** per file. * **Duration:** up to **2 hours**. * **Input resolution:** up to **2K** (short side ≤ 1440 px). Use `resolution: "4k"` to upscale beyond the source. ### `tool_version` — optional (`"standard"` | `"professional"`) Default: `"standard"`. * **`standard`** — balanced quality / speed. Internally runs \~10 frequently used algorithms; covers what most distribution platforms expect. Roughly 6 – 10× the source duration to process. * **`professional`** — maximum quality. Runs 30+ deep AI algorithms for shot-level enhancement. Roughly 30+× the source duration to process and \~10× the credits of `standard`. ### `scene` — optional (string) Selects a scene-tuned preset. Default: `"common"`. | Value | Recommended for | | -------------- | -------------------------------------------------------------------------------- | | `common` | General-purpose enhancement (no scene-specific tuning). | | `ugc` | Compressed UGC clips — fixes blocking, color banding, blur. | | `short_series` | Short-drama footage — face / detail enhancement, stylized contrast. | | `aigc` | Low-res AI-generated video — super-resolution + detail repaint. | | `old_film` | Aged film — temporal denoise, scratch removal, deflicker, color cast correction. | ### `resolution` — optional (string) Target output resolution. Mutually exclusive with `resolution_limit`. Allowed values: `240p`, `360p`, `480p`, `540p`, `720p`, `1080p`, `2k`, `4k`. If unset, the output keeps the source resolution. ### `resolution_limit` — optional (integer) Lock the output **short-side** to this exact pixel count, then scale the long side to preserve the source ratio. Range `[64, 2160]`. Mutually exclusive with `resolution`. Use this when you need precise output dimensions (e.g. `resolution_limit: 720` with a 640×480 source produces 960×720). ### `fps` — optional (number) Target output frame rate, max 120. If unset, the output matches the source frame rate. Setting a value higher than the source triggers AI frame interpolation; staying within 4× the source is recommended for natural-looking motion. ### `client_token` — optional (string) Client-supplied idempotency token. Up to 64 ASCII printable characters. The same token within a short window returns the same `task_id`. ### `callback_args` — optional (string) Opaque blob (≤ 512 bytes) you supply at submit time and receive back when the task completes (via the standard task envelope). Useful for stitching results back to your business records without storing the `task_id`. *** ## Output ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "enhance-video-1.0", "status": "completed", "created_at": 1735000000, "output": { "video_urls": [ "https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4" ] }, "error": null } ``` The MP4 lives on our CDN — copy it to your own storage if you need long-term retention. *** ## Pricing Billed by **output duration × tier × resolution × fps tier**. The output duration always matches the source video duration (`enhance-video-1.0` does not change clip length). When you submit, the gateway probes your `video_url` server-side to determine the exact billable seconds and resolution bucket. If the URL is unreachable or returns no metadata, you receive a `400 Could not determine source video metadata for billing` and **no credits are charged**. The bill scales with three knobs: * **`tool_version`** — `professional` is roughly 10× the cost of `standard`. * **Output resolution bucket** — `720p` \< `1080p` \< `2k` \< `4k`. Each step doubles the cost. * **Output fps tier** — `> 30 fps` doubles the cost vs `≤ 30 fps`. If you don't pass `fps`, the output keeps the source frame rate; billing assumes the **`≤ 30 fps`** tier, which matches the vast majority of user-uploaded video. To opt into the `> 30 fps` tier, set `fps` explicitly. See the live banner on the [model page](https://reapi.ai/models/enhance-video-1-0) for the current rate range in credits. *** ## Errors Standard envelope: ```json { "error": { "code": 20003, "message": "resolution and resolution_limit are mutually exclusive", "request_id": "req_..." } } ``` Common cases: | Code | When | | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `20002` | `video_url` missing. | | `20003` | Invalid enum (`tool_version`, `scene`, `resolution`), `resolution` + `resolution_limit` both set, `resolution_limit` outside `[64, 2160]`, or `video_url` not a public http(s) URL. | | `30002` | Source video metadata couldn't be probed (used for billing). | | `30001` | Insufficient credits for the probed source duration. | | `80003` | Provider rejected or failed the task (e.g. unsupported codec). | --- # flux-2 (https://reapi.ai/docs/flux-2) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Black Forest Labs' FLUX.2 on reAPI — photoreal **text-to-image** and > **multi-reference editing** (up to 8 images), with accurate in-image text. > Two tiers: `flux-2` (Pro) and `flux-2-flex` (Flex). Submit returns a > `task_id`; poll until ready. See current pricing on the > [model page](https://reapi.ai/models/flux-2). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "flux-2", "prompt": "an infographic poster titled OPENING SOON, clean layout", "aspect_ratio": "3:4", "resolution": "2K" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "flux-2", "prompt": "an infographic poster titled OPENING SOON, clean layout", "aspect_ratio": "3:4", "resolution": "2K", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "flux-2", prompt: "an infographic poster titled OPENING SOON, clean layout", aspect_ratio: "3:4", resolution: "2K", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "flux-2", "prompt": "an infographic poster titled OPENING SOON, clean layout", "aspect_ratio": "3:4", "resolution": "2K", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "flux-2", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.image_urls` holds the generated image URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/images/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Tiers Two customer model ids share one parameter shape: | Model id | Tier | Notes | | ------------- | ---- | ------------------------------------------------------ | | `flux-2` | Pro | Production-ready, fast, lower price. The default tier. | | `flux-2-flex` | Flex | Maximum quality / detail, higher price. | ## Modes There is no `mode` field — the modality is implicit in the request shape: * **Text-to-image** — no `input_urls`. * **Image-to-image / multi-reference editing** — pass `input_urls` (1–8 reference images). FLUX.2 keeps characters, products, and styles consistent across the result. *** ## Request body ### `model` — string, required One of `flux-2` (Pro) or `flux-2-flex` (Flex). ### `prompt` — string, required **3–5,000 characters.** Put any text you want rendered in the image in quotes. ### `input_urls` — array, optional 1–8 reference images for image-to-image / multi-reference editing. **Public HTTPS URLs only** — base64 / `data:` URIs are rejected at the gateway. Passing any image switches the request to editing mode. ### `aspect_ratio` — string, default `1:1` One of `1:1`, `4:3`, `3:4`, `16:9`, `9:16`, `3:2`, `2:3`. The value `auto` (match the first reference image) is available **only for image-to-image**. `aspect_ratio: "auto"` requires `input_urls`. Using it without reference images (text-to-image) is rejected with `400`. ### `resolution` — string, default `1K` `1K` or `2K`. The `2K` tier renders up to 4MP. ### `nsfw_checker` — boolean, optional, default `false` Enables upstream content moderation. Off by default. *** ## Pricing FLUX.2 bills a flat rate **per generated image**, by tier (`flux-2` / `flux-2-flex`) and resolution (`1K` / `2K`). Text-to-image and image-to-image cost the same within a tier: ``` credits = ceil(per_image_usd × 1000) ``` where `1 credit = $0.001 USD`. Each request produces one image. Failed and rejected requests are not charged. The exact per-image credit cost for each tier/resolution surfaces on the [model page](https://reapi.ai/models/flux-2) and through the playground estimator before submit. *** ## Response The poll envelope returns the image URL in `output.image_urls`: ```json { "id": "task_019dfd44b7fd74168541552a3260a623", "model": "flux-2", "status": "completed", "output": { "image_urls": [ "https://cdn.reapi.ai/...jpg" ] } } ``` Generated URLs expire — mirror them to your own storage if you need long-term retention. *** ## Errors Failures return the standard reAPI envelope `{ error: { code, message, request_id } }`. Common cases: * Invalid input (prompt outside 3–5000 chars, more than 8 `input_urls`, `auto` aspect without reference images, a non-HTTPS URL) → `400`. * Insufficient credits → `402`. * Rate limited → `429`. See the full catalog at [/docs/api/errors](/docs/api/errors). *** ## Tips * Put the literal text you want rendered **in the prompt, in quotes** — FLUX.2 is tuned for legible typography, ad headlines, and infographics. * For consistency across a campaign, pass the same reference image(s) in `input_urls` and let FLUX.2 keep the character/style on-model. * Use `flux-2` (Pro) for fast, cost-efficient production and `flux-2-flex` (Flex) when a hero shot needs maximum quality. * Reach for `resolution: "2K"` (up to 4MP) only when the asset needs the detail. *** ## Related * [Image generation models](/docs/gpt-image-2) * [Qwen Image 2](/docs/qwen-image-2) * [Tasks API](/docs/api/tasks) * [Error codes](/docs/api/errors) --- # FLUX 3 (https://reapi.ai/docs/flux-3) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; **Coming soon.** FLUX 3 has no public API yet. Black Forest Labs announced the model on 2026-07-23 and is rolling it out in phases, starting with Early Access for FLUX 3 Video. Official model ids, parameters, limits and pricing have **not** been published. Everything below marked *(preview)* is the shape reAPI expects to expose — treat it as provisional and watch the [model page](https://reapi.ai/models/flux-3) for launch. > FLUX 3 is Black Forest Labs' multimodal foundation model: images, video and > audio learned jointly inside one architecture built on Self-Flow. It > generates video with native audio — up to 20 seconds in a single generation — > follows keyframes, reference images, reference clips and existing > video-audio, speaks multilingual dialogue, and synthesizes and edits images > from the same backbone. ## Status FLUX 3 is **not callable on reAPI yet**. Black Forest Labs' published rollout order is: | Stage | Capability | Access | | ----- | --------------------------------------------------- | ---------------------------------------------- | | 1 | FLUX 3 Video — video + audio generation and editing | Early Access started | | 2 | FLUX 3 Action / FLUX-mimic — action prediction | Selected research + commercial partners | | 3 | FLUX 3 Image — image synthesis and editing | Early Access announced for the following weeks | | 4 | FLUX 3 Dev — open-weight multimodal backbone | After the phases above | When the public API lands: * The `model` ids, full parameter set, constraints and rates are finalized here. * The playground on the [model page](https://reapi.ai/models/flux-3) goes live. * This banner is removed. ## Capabilities Published by Black Forest Labs for FLUX 3 Video. All outputs carry native audio generation. * **Text-to-video** — prompt in, video with sound out. * **Image-to-video** — continue from a starting frame ("animation"), or use images as visual references. * **Video-to-video** — carry central elements of a source clip, such as the same character, into a new scene or context. * **Video-audio continuation** — extend an existing video *and* its audio. * **Keyframe-to-video** — controlled transitions between defined moments. * **Multilingual dialogue** — spoken dialogue across languages. * **Typography** — strong text rendering and animated designs inside the frame. * **Agentic chaining** — individual clips chained into multi-shot sequences that run for minutes, with visual references holding characters consistent. Single-generation ceiling: **20 seconds**. Longer pieces come from chaining. FLUX 3 Image adds synthesis and editing across styles, aspect ratios and resolutions, with high-accuracy text in multiple languages. ## Quick example (preview) ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "flux-3", "prompt": "A rain-soaked cafe terrace at dusk, a tram rolls past", "duration": 10 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "flux-3", "prompt": "A rain-soaked cafe terrace at dusk, a tram rolls past", "duration": 10, }, timeout=30, ) task = resp.json() print(task["id"]) ``` ```js const resp = await fetch('https://reapi.ai/api/v1/videos/generations', { method: 'POST', headers: { Authorization: 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'flux-3', prompt: 'A rain-soaked cafe terrace at dusk, a tram rolls past', duration: 10, }), }); const task = await resp.json(); console.log(task.id); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "flux-3", "prompt": "A rain-soaked cafe terrace at dusk, a tram rolls past", "duration": 10, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var task map[string]any json.NewDecoder(resp.Body).Decode(&task) fmt.Println(task["id"]) } ``` ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. ## Endpoint (preview) ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. ## Request body (preview) Black Forest Labs has not published FLUX 3's parameter surface. The field names below are reAPI's provisional mapping of the **input types BFL named** in its announcement — they are how the model will be wired in, not a quoted vendor spec. Expect names, defaults and enums to change at launch. Mode is implicit: which media fields you set decides text-to-video, image-to-video, video-to-video, continuation, or keyframe transition. | Field | Type | Default | Notes | | ------------ | --------- | ------- | ------------------------------------------------------------------------------- | | `model` | string | — | `flux-3`. **Required.** | | `prompt` | string | — | Scene, motion and sound to generate. **Required.** | | `duration` | integer | — | Output length in seconds. Published ceiling: `20`. | | `image_urls` | string\[] | — | Starting frame to animate, or images as visual references. Public HTTP(S) URLs. | | `video_urls` | string\[] | — | Reference clip for video-to-video, or the video to continue. | | `audio_urls` | string\[] | — | Reference audio for video-audio continuation. | **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — every URL field must be a public HTTP(S) URL. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. ## Response envelope (preview) Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "flux-3", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/.../0.mp4"] }, "error": null } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. `output.video_urls` holds the generated MP4 URL — audio is muxed into that file, not returned separately. ## Pricing Black Forest Labs has **not announced FLUX 3 pricing**, and reAPI does not publish speculative rates. Once the API ships, the rate appears on the [model page](https://reapi.ai/models/flux-3) — that table is dynamic and always reflects the current price. Video models on reAPI bill per second of output: ``` credits = ceil(per_second_usd × billable_seconds × 1000) ``` where `1 credit = $0.001`. Failed jobs are refunded automatically. ## Errors FLUX 3 will return the platform's standard envelope: ```json { "error": { "code": "INVALID_REQUEST", "message": "duration must be at most 20", "request_id": "req_01hq2k..." } } ``` See the [errors catalog](/docs/api/errors) for the full code list and retry guidance. ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [FLUX.2 — available now](/docs/flux-2) * [Seedance 2.0 — available now](/docs/seedance-2-0) --- # gemini-2.5-flash-image-preview (https://reapi.ai/docs/gemini-2-5-flash-image-preview) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Async image generation tuned for speed. One endpoint covers > text-to-image and image-to-image with up to 14 reference images. > Two channels share the same parameter shape: > > * `gemini-2.5-flash-image-preview` — default channel. > * `gemini-2.5-flash-image-preview-official` — Google's official endpoint. * Async processing — `POST` returns a `task_id`, poll `GET /api/v1/tasks/{id}` for the result. * standard `/api/v1/images/generations` envelope (text-to-image / image-to-image). * 10 ratios via `size`; only **1K** resolution on this model. * Up to **14** reference images via `image_urls` — public HTTP(S) URLs only. * Up to **4** images per request via `n`. * Failed / moderated requests are not charged. *** ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-2.5-flash-image-preview", "prompt": "moonlight on a bamboo path, ink wash painting", "size": "16:9" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "gemini-2.5-flash-image-preview", "prompt": "moonlight on a bamboo path, ink wash painting", "size": "16:9", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "gemini-2.5-flash-image-preview", prompt: "moonlight on a bamboo path, ink wash painting", size: "16:9", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gemini-2.5-flash-image-preview", "prompt": "moonlight on a bamboo path, ink wash painting", "size": "16:9", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-2.5-flash-image-preview", "status": "processing", "created_at": 1735000000 } ``` Hold onto `id` and poll `GET /api/v1/tasks/{id}` until completion. *** ## Endpoint ```http POST /api/v1/images/generations # submit a job GET /api/v1/tasks/{id} # poll for the result ``` Async — submit returns a `task_id` immediately; the actual image arrives via the polling endpoint. Polling is free. *** ## Authentication Bearer token, minted at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer rk_live_xxx ``` *** ## Body ### `model` `string` · **required** One of: * `"gemini-2.5-flash-image-preview"` — default channel. * `"gemini-2.5-flash-image-preview-official"` — Google's official endpoint. ### `prompt` `string` · **required** 1 – 2000 characters. English and Chinese both supported. Don't restate the ratio in the prompt — pass it via `size`. Image-to-image is no exception — the prompt describes what to do with the reference. Sending `image_urls` without a `prompt` returns `400`. ### `size` `string` · default `"1:1"` (text-to-image) / inherited (image-to-image) Output ratio. One of these 10 values: ``` 1:1 2:3 3:2 3:4 4:3 4:5 5:4 9:16 16:9 21:9 ``` Anything outside the list is rejected with `400`. When `image_urls` is provided **without** `size`, the output inherits the first reference image's resolution (image-to-image mode). Pass `size` to force a specific ratio. ### `resolution` `string` · default `"1K"` Only `1K` is supported on this model. Sending `2K` / `4K` returns `400`. Switch to [`gemini-3-pro-image-preview`](/docs/gemini-3-pro-image-preview) or [`gemini-3.1-flash-image-preview`](/docs/gemini-3-1-flash-image-preview) when you need higher resolutions. ### `n` `integer` · default `1` 1 – 4 images per request. Must be a number, not a string. ### `image_urls` `string[]` · optional Reference images for image-to-image. Up to **14** entries. Each entry must be a public HTTP(S) URL — `data:` / base64 payloads are rejected at the gateway. Upload to your own object storage (S3 / R2 / OSS) and pass the URL. *** ## Use cases ### 1. Text-to-image (minimal) ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-2.5-flash-image-preview", "prompt": "moonlight on a bamboo path, ink wash painting" }' ``` ### 2. Text-to-image, widescreen ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-2.5-flash-image-preview", "prompt": "a corgi astronaut on the moon, cinematic", "size": "16:9" }' ``` ### 3. Multiple variations in one call ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-2.5-flash-image-preview", "prompt": "vintage botanical illustration, hibiscus", "size": "4:5", "n": 4 }' ``` ### 4. Image-to-image (single reference) ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-2.5-flash-image-preview", "prompt": "turn this photo into a watercolor painting", "image_urls": ["https://your-cdn.com/photo.jpg"] }' ``` ### 5. Multi-reference fusion ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-2.5-flash-image-preview", "prompt": "blend these two photos into a poster", "size": "4:3", "image_urls": [ "https://your-cdn.com/photo-a.jpg", "https://your-cdn.com/photo-b.jpg" ] }' ``` ### 6. Force the official channel ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-2.5-flash-image-preview-official", "prompt": "studio portrait of a tabby cat, soft light", "size": "1:1" }' ``` *** ## Response `POST` returns immediately with `status: "processing"`; poll `GET /api/v1/tasks/{id}` until `status` is `completed` or `failed`. Both responses share the same envelope — the `output` field is `null` until the task finishes. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-2.5-flash-image-preview", "status": "processing", "created_at": 1735000000 } ``` ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-2.5-flash-image-preview", "status": "completed", "created_at": 1735000000, "output": { "image_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png"] }, "error": null } ``` URLs are stable for **7 days**. Download to your own storage if you need them longer. ```json { "error": { "code": 20003, "message": "gemini-2.5-flash-image-preview: only resolution=1K is supported", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 10003, "message": "API key invalid", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 30001, "message": "Insufficient credits", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 50001, "message": "Rate limit exceeded", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 60099, "message": "Internal error — please retry", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ### Upstream errors (502 / 503) reAPI does not surface raw upstream `5xx` codes to the caller. When the upstream provider returns `502 Bad Gateway`, `503 Service Unavailable`, or a connection failure, the worker retries up to 5 attempts with exponential backoff (\~30s total budget). If all retries fail, the task ends with one of these reapi-specific error codes (returned via `GET /api/v1/tasks/{id}` as `error.code`): | reapi code | Meaning | Origin | | ---------- | -------------------------- | ------------------------------------ | | `80001` | `provider_submit_failed` | Upstream `5xx` / network on submit | | `80002` | `provider_polling_timeout` | Wall-clock cap reached while polling | | `80003` | `provider_failed` | Upstream returned a terminal failure | See [Errors catalog](/docs/api/errors) for the full code list. *** ## Polling | `status` | Meaning | | ------------ | ----------------------------- | | `processing` | Submitted, still generating | | `completed` | `output.image_urls` is ready | | `failed` | See `error.code`; not charged | Recommended cadence: ``` 0–10s: wait before the first poll 10s–60s: poll every 2–3s 60s+: back off to 5s; cap at 15s ``` A 1K image typically completes in 5 – 20 seconds. *** ## Related * [`gemini-3-pro-image-preview`](/docs/gemini-3-pro-image-preview) — higher-quality variant with 1K / 2K / 4K resolutions. * [`gemini-3.1-flash-image-preview`](/docs/gemini-3-1-flash-image-preview) — newer variant with extreme ratios and Google search grounding. * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Pricing — gemini-2.5-flash-image-preview](https://reapi.ai/models/gemini-2-5-flash-image-preview#pricing) --- # gemini-3.1-flash-image-preview (https://reapi.ai/docs/gemini-3-1-flash-image-preview) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Async image generation with a wide ratio surface (down to > 1:8 / 8:1) and optional Google search grounding. One endpoint covers > text-to-image and image-to-image with up to 14 reference images. Two > channels share the same parameter shape: > > * `gemini-3.1-flash-image-preview` — default channel. > * `gemini-3.1-flash-image-preview-official` — Google's official endpoint. * Async processing — `POST` returns a `task_id`, poll `GET /api/v1/tasks/{id}` for the result. * standard `/api/v1/images/generations` envelope (text-to-image / image-to-image). * 14 ratios via `size`, including extreme `1:4` / `4:1` / `1:8` / `8:1`. * Four resolution tiers via `resolution`: `0.5K` / `1K` / `2K` / `4K`. * Up to **14** reference images via `image_urls` — public HTTP(S) URLs only. * Up to **4** images per request via `n`. * Optional Google search grounding via `google_search` and `google_image_search`. *** ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3.1-flash-image-preview", "prompt": "neon-lit cyberpunk skyline at midnight", "size": "16:9", "resolution": "2K" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "gemini-3.1-flash-image-preview", "prompt": "neon-lit cyberpunk skyline at midnight", "size": "16:9", "resolution": "2K", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "gemini-3.1-flash-image-preview", prompt: "neon-lit cyberpunk skyline at midnight", size: "16:9", resolution: "2K", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gemini-3.1-flash-image-preview", "prompt": "neon-lit cyberpunk skyline at midnight", "size": "16:9", "resolution": "2K", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-3.1-flash-image-preview", "status": "processing", "created_at": 1735000000 } ``` Hold onto `id` and poll `GET /api/v1/tasks/{id}` until completion. *** ## Endpoint ```http POST /api/v1/images/generations # submit a job GET /api/v1/tasks/{id} # poll for the result ``` Async — submit returns a `task_id` immediately; the actual image arrives via the polling endpoint. Polling is free. *** ## Authentication Bearer token, minted at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer rk_live_xxx ``` *** ## Body ### `model` `string` · **required** One of: * `"gemini-3.1-flash-image-preview"` — default channel. * `"gemini-3.1-flash-image-preview-official"` — Google's official endpoint. ### `prompt` `string` · **required** Detailed prompts produce better results. English and Chinese both supported. Don't restate the ratio in the prompt — pass it via `size`. Image-to-image is no exception — the prompt describes what to do with the reference. Sending `image_urls` without a `prompt` returns `400`. ### `size` `string` · default `"1:1"` (text-to-image) / inherited (image-to-image) Output ratio. One of these 14 values: ``` 1:1 2:3 3:2 3:4 4:3 4:5 5:4 9:16 16:9 21:9 1:4 4:1 1:8 8:1 ``` `1:4` / `4:1` / `1:8` / `8:1` are useful for tall posters, banner ads, and long-strip social formats. Anything outside the list is rejected with `400`. ### `resolution` `string` · default `"1K"` `0.5K` / `1K` / `2K` / `4K`. Case-insensitive — `"2K"` and `"2k"` are equivalent. ### `n` `integer` · default `1` 1 – 4 images per request. Must be a number, not a string. ### `image_urls` `string[]` · optional Reference images for image-to-image. Up to **14** entries. Each entry must be a public HTTP(S) URL — `data:` / base64 payloads are rejected at the gateway. Recommended split: ≤ 10 object references + ≤ 4 character references for best consistency. ### `google_search` `boolean` · default `false` When `true`, the model first searches the web for textual context to ground the generated image in real-world facts. Useful for prompts that reference recent events, named entities, or specific places. Adds an extra search round-trip — budget extra polling time. ### `google_image_search` `boolean` · default `false` When `true`, the model also searches the web for **image** references in addition to text. **Requires `google_search: true`** — sending `google_image_search: true` with `google_search: false` (or omitted) returns `400`. *** ## Use cases ### 1. Text-to-image (minimal) ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3.1-flash-image-preview", "prompt": "neon-lit cyberpunk skyline at midnight" }' ``` ### 2. Long-banner poster (extreme ratio) ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3.1-flash-image-preview", "prompt": "long horizontal banner of a serene lakeside at sunrise", "size": "8:1", "resolution": "2K" }' ``` ### 3. Tall mobile-first poster ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3.1-flash-image-preview", "prompt": "vertical movie poster, lone astronaut on a frozen moon", "size": "1:4", "resolution": "2K" }' ``` ### 4. Search-grounded generation ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3.1-flash-image-preview", "prompt": "the Eiffel Tower lit up for Bastille Day fireworks", "size": "16:9", "resolution": "2K", "google_search": true, "google_image_search": true }' ``` ### 5. Image-to-image with reference ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3.1-flash-image-preview", "prompt": "stylize this product photo as a vintage magazine cover", "image_urls": ["https://your-cdn.com/product.jpg"], "size": "4:5", "resolution": "2K" }' ``` ### 6. Multi-reference fusion ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3.1-flash-image-preview", "prompt": "place subject from reference 1 into the scene of reference 2", "size": "16:9", "resolution": "4K", "image_urls": [ "https://your-cdn.com/subject.jpg", "https://your-cdn.com/scene.jpg" ] }' ``` ### 7. Low-cost preview at 0.5K ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3.1-flash-image-preview", "prompt": "concept thumbnail of a forest temple", "size": "1:1", "resolution": "0.5K", "n": 4 }' ``` *** ## Response `POST` returns immediately with `status: "processing"`; poll `GET /api/v1/tasks/{id}` until `status` is `completed` or `failed`. Both responses share the same envelope — the `output` field is `null` until the task finishes. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-3.1-flash-image-preview", "status": "processing", "created_at": 1735000000 } ``` ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-3.1-flash-image-preview", "status": "completed", "created_at": 1735000000, "output": { "image_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png"] }, "error": null } ``` URLs are stable for **7 days**. Download to your own storage if you need them longer. ```json { "error": { "code": 20003, "message": "gemini-3.1-flash-image-preview: google_image_search requires google_search:true", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 10003, "message": "API key invalid", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 30001, "message": "Insufficient credits", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 50001, "message": "Rate limit exceeded", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 60099, "message": "Internal error — please retry", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ### Upstream errors (502 / 503) reAPI does not surface raw upstream `5xx` codes to the caller. When the upstream provider returns `502 Bad Gateway`, `503 Service Unavailable`, or a connection failure, the worker retries up to 5 attempts with exponential backoff (\~30s total budget). If all retries fail, the task ends with one of these reapi-specific error codes (returned via `GET /api/v1/tasks/{id}` as `error.code`): | reapi code | Meaning | Origin | | ---------- | -------------------------- | ------------------------------------ | | `80001` | `provider_submit_failed` | Upstream `5xx` / network on submit | | `80002` | `provider_polling_timeout` | Wall-clock cap reached while polling | | `80003` | `provider_failed` | Upstream returned a terminal failure | See [Errors catalog](/docs/api/errors) for the full code list. *** ## Polling | `status` | Meaning | | ------------ | ----------------------------- | | `processing` | Submitted, still generating | | `completed` | `output.image_urls` is ready | | `failed` | See `error.code`; not charged | Recommended cadence: ``` 0–15s: wait before the first poll 15s–2m: poll every 3–5s 2m+: back off to 10s; cap at 30s ``` A 1K image typically completes in 10 – 30 seconds; 4K and Google search grounding both add latency. *** ## Related * [`gemini-2.5-flash-image-preview`](/docs/gemini-2-5-flash-image-preview) — earlier variant (1K only). * [`gemini-3-pro-image-preview`](/docs/gemini-3-pro-image-preview) — higher-fidelity variant without search grounding. * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Pricing — gemini-3.1-flash-image-preview](https://reapi.ai/models/gemini-3-1-flash-image-preview#pricing) --- # gemini-3-6-flash (https://reapi.ai/docs/gemini-3-6-flash) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Google's Gemini 3.6 Flash, exposed through api.reapi.ai as a drop-in > OpenAI-compatible Chat Completions endpoint. A **1,048,576-token** input window, > **65,536-token** max output, inputs across **text, image, video, audio and > PDF** with text output, plus **thinking**, **function calling**, **code > execution**, **structured outputs**, **context caching**, **file search**, > **URL context** and **Search / Maps grounding**. The wire `model` id is > `gemini-3.6-flash`. Current rates live on the > [model page](https://reapi.ai/models/gemini-3-6-flash) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3.6-flash", "messages": [ { "role": "user", "content": "Summarise the attached contract in five bullets." } ], "stream": true, "max_tokens": 8192 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="gemini-3.6-flash", messages=[{"role": "user", "content": "Summarise the attached contract in five bullets."}], max_tokens=8192, stream=True, ) for chunk in stream: delta = chunk.choices[0].delta.content if delta: print(delta, end="") ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "gemini-3.6-flash", messages: [ { role: "user", content: "Summarise the attached contract in five bullets." }, ], max_tokens: 8192, stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gemini-3.6-flash", "messages": []map[string]string{ {"role": "user", "content": "Summarise the attached contract in five bullets."}, }, "max_tokens": 8192, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Chat models are served from the `api.reapi.ai` gateway, which has its own console and its own key. Create the key there, then send it as a bearer token: ```http Authorization: Bearer YOUR_API_KEY ``` The gateway key is **not** the same credential as a media-generation key used against `reapi.ai/api/v1`. Sign in at [api.reapi.ai](https://api.reapi.ai/) to create one. *** ## Endpoint ```http POST /v1/chat/completions ``` Base URL `https://api.reapi.ai`. The wire format is OpenAI-compatible, so the same SDKs (`openai-python`, `openai-node`, `openai-go`, …) work once you swap the base URL, the key and the model string. The gateway also lists a native Gemini endpoint type for this model if you prefer Google's own request format. *** ## Request body ### `model` — string, required Must be `gemini-3.6-flash` exactly. The dotted form is the wire id; the `/models/gemini-3-6-flash` landing page uses a hyphenated slug for the URL. ### `messages` — array, required Conversation history, each entry an object with `role` and `content`. Roles are `system`, `user` and `assistant`. Multimodal parts are supported — see [Multimodal input](#multimodal-input). ### `max_tokens` — integer Upper bound on output tokens for this response, **thinking tokens included**. Google documents a **65,536**-token output ceiling for this model, so higher values are clamped to it. ### `stream` — boolean, default `false` When `true`, tokens arrive as server-sent events terminated by `data: [DONE]`. Recommended for anything a person watches. ### `temperature` — number, default `1` Sampling temperature. Lower is more deterministic. ### `top_p` — number, default `0.95` Nucleus sampling cutoff. Tune either `temperature` or `top_p`, not both. ### `tools` / `tool_choice` — optional Function declarations for tool calling, and the strategy for picking among them. See [Tools and grounding](#tools-and-grounding). ### `group` — string, default `"default"` Token group on the gateway. Leave it at `default` unless your account has been given another group to route through. *** ## Multimodal input Google documents the following supported inputs for this model: | Modality | Supported | | -------- | :-------: | | Text | ✅ | | Image | ✅ | | Video | ✅ | | Audio | ✅ | | PDF | ✅ | Output is **text only**. Audio generation, image generation and the Live API are **not** supported on this model — use a dedicated model for those. PDF being a first-class input matters for document workloads: a contract set or a research bundle goes in whole, without a chunking layer of your own. *** ## Thinking Thinking is a supported capability. The reasoning pass is what carries a multi-step plan across tool calls instead of restarting on each turn. **Thinking tokens are billed as output tokens** and count toward `max_tokens`. A long reasoning pass therefore competes with the visible answer for the same budget — raise `max_tokens` when you ask for both deep reasoning and long output. *** ## Tools and grounding | Capability | Status | | -------------------------- | ------------------- | | Function calling | Supported | | Code execution | Supported | | File search | Supported | | Structured outputs | Supported | | Context caching | Supported | | URL context | Supported | | Search grounding | Supported | | Grounding with Google Maps | Supported | | Computer use | Supported (preview) | Google meters grounded search queries separately from tokens, and a single request may fan out into more than one search query. *** ## Pricing dimensions Billing is **per token**, in USD, against your `api.reapi.ai` balance, with separate **input** and **output** rates. Three things to keep in mind: * **Thinking tokens bill as output.** They are the usual reason a bill exceeds an estimate built from visible response length alone. * **Output dominates.** For most generative workloads the output rate, not the input rate, decides the invoice. * **Grounded search is metered by Google separately** from tokens. Both token rates sit **20% below Google's published Standard rate**. Current numbers are on the [model page](https://reapi.ai/models/gemini-3-6-flash) and [api.reapi.ai/pricing](https://api.reapi.ai/pricing) — those tables are the canonical source, not this page. Chat models bill in USD on the gateway balance. They do **not** draw down the integer credits used by the media-generation endpoints on `reapi.ai/api/v1`. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1785000000, "model": "gemini-3.6-flash", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 812, "completion_tokens": 240, "total_tokens": 1052 } } ``` `usage.completion_tokens` includes thinking tokens, so it is the number to reconcile a bill against. ### Streaming (`stream: true`) Server-sent events, each `data:` line carrying a `chat.completion.chunk` with the incremental text in `choices[0].delta.content`, terminated by `data: [DONE]`. *** ## Errors Failures use the gateway's standard envelope. See the [errors catalog](/docs/api/errors) for the full code list. Common cases: | Trigger | What to do | | ------------------------------------ | -------------------------------------------------- | | Missing or invalid bearer token | Create a key in the api.reapi.ai console | | Unknown `model` value | Send `gemini-3.6-flash` exactly, dots included | | `max_tokens` above the model ceiling | Lower it; the documented ceiling is 65,536 | | Insufficient balance | Top up on the gateway | | Upstream rate limit | Retry with backoff, or route through another model | *** ## Tips * **Stream anything interactive.** Time-to-first-token is what users perceive; a non-streamed long answer reads as a hang. * **Budget for thinking.** If responses truncate mid-sentence on hard prompts, the reasoning pass consumed the `max_tokens` allowance — raise it. * **Put the whole document in.** With a 1,048,576-token window, a retrieval layer whose only purpose was working around a small context is usually worth deleting. * **Use structured outputs for tool arguments.** Schema-constrained output removes a whole class of parse-and-retry logic. * **Reach for grounding rather than a stale answer.** Search grounding and URL context exist precisely for facts newer than the training data. * **Pin the Stable string.** `gemini-3.6-flash` is Google's Stable channel id; `latest`-style aliases can be hot-swapped underneath you. *** ## Related * [Gemini 3.6 Flash model page](https://reapi.ai/models/gemini-3-6-flash) — current rates * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # gemini-3-pro-image-preview (https://reapi.ai/docs/gemini-3-pro-image-preview) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Async high-quality image generation. One endpoint covers > text-to-image and image-to-image with up to 14 reference images. > Two channels share the same parameter shape: > > * `gemini-3-pro-image-preview` — default channel. > * `gemini-3-pro-image-preview-official` — Google's official endpoint. * Async processing — `POST` returns a `task_id`, poll `GET /api/v1/tasks/{id}` for the result. * standard `/api/v1/images/generations` envelope (text-to-image / image-to-image). * 10 ratios via `size`; three resolution tiers (`1K` / `2K` / `4K`) via `resolution`. * Up to **14** reference images via `image_urls` — public HTTP(S) URLs only. * Up to **4** images per request via `n`. * Failed / moderated requests are not charged. *** ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-pro-image-preview", "prompt": "ancient castle beneath a starry sky, cinematic", "size": "16:9", "resolution": "2K" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "gemini-3-pro-image-preview", "prompt": "ancient castle beneath a starry sky, cinematic", "size": "16:9", "resolution": "2K", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "gemini-3-pro-image-preview", prompt: "ancient castle beneath a starry sky, cinematic", size: "16:9", resolution: "2K", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gemini-3-pro-image-preview", "prompt": "ancient castle beneath a starry sky, cinematic", "size": "16:9", "resolution": "2K", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-3-pro-image-preview", "status": "processing", "created_at": 1735000000 } ``` Hold onto `id` and poll `GET /api/v1/tasks/{id}` until completion. *** ## Endpoint ```http POST /api/v1/images/generations # submit a job GET /api/v1/tasks/{id} # poll for the result ``` Async — submit returns a `task_id` immediately; the actual image arrives via the polling endpoint. Polling is free. *** ## Authentication Bearer token, minted at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer rk_live_xxx ``` *** ## Body ### `model` `string` · **required** One of: * `"gemini-3-pro-image-preview"` — default channel. * `"gemini-3-pro-image-preview-official"` — Google's official endpoint. ### `prompt` `string` · **required** Detailed prompts produce better results. English and Chinese both supported. Don't restate the ratio in the prompt — pass it via `size`. Image-to-image is no exception — the prompt describes what to do with the reference. Sending `image_urls` without a `prompt` returns `400`. ### `size` `string` · default `"1:1"` (text-to-image) / inherited (image-to-image) Output ratio. One of these 10 values: ``` 1:1 2:3 3:2 3:4 4:3 4:5 5:4 9:16 16:9 21:9 ``` Anything outside the list is rejected with `400`. When `image_urls` is provided **without** `size`, the output inherits the first reference image's resolution (image-to-image mode). Pass `size` to force a specific ratio. ### `resolution` `string` · default `"1K"` `1K` / `2K` / `4K`. Case-insensitive — `"2K"` and `"2k"` are equivalent. ### `n` `integer` · default `1` 1 – 4 images per request. Must be a number, not a string. ### `image_urls` `string[]` · optional Reference images for image-to-image. Up to **14** entries. Each entry must be a public HTTP(S) URL — `data:` / base64 payloads are rejected at the gateway. Upload to your own object storage (S3 / R2 / OSS) and pass the URL. *** ## Use cases ### 1. Text-to-image (minimal) ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3-pro-image-preview", "prompt": "ancient castle beneath a starry sky, cinematic" }' ``` ### 2. Text-to-image at 2K ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3-pro-image-preview", "prompt": "neon-lit Tokyo street in the rain, cyberpunk", "size": "16:9", "resolution": "2K" }' ``` ### 3. Text-to-image at 4K ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3-pro-image-preview", "prompt": "cinematic mountain valley at golden hour", "size": "21:9", "resolution": "4K" }' ``` ### 4. Image-to-image (single reference) ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3-pro-image-preview", "prompt": "convert this snapshot into a film-grain editorial shot", "image_urls": ["https://your-cdn.com/photo.jpg"], "resolution": "2K" }' ``` ### 5. Multi-reference fusion ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3-pro-image-preview", "prompt": "blend the subject from photo A with the lighting of photo B", "size": "4:3", "resolution": "2K", "image_urls": [ "https://your-cdn.com/photo-a.jpg", "https://your-cdn.com/photo-b.jpg" ] }' ``` ### 6. Force the official channel ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gemini-3-pro-image-preview-official", "prompt": "marble bust of a philosopher, dramatic side lighting", "size": "1:1", "resolution": "2K" }' ``` *** ## Response `POST` returns immediately with `status: "processing"`; poll `GET /api/v1/tasks/{id}` until `status` is `completed` or `failed`. Both responses share the same envelope — the `output` field is `null` until the task finishes. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-3-pro-image-preview", "status": "processing", "created_at": 1735000000 } ``` ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-3-pro-image-preview", "status": "completed", "created_at": 1735000000, "output": { "image_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png"] }, "error": null } ``` URLs are stable for **7 days**. Download to your own storage if you need them longer. ```json { "error": { "code": 20003, "message": "gemini-3-pro-image-preview: invalid resolution \"8K\"", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 10003, "message": "API key invalid", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 30001, "message": "Insufficient credits", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 50001, "message": "Rate limit exceeded", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 60099, "message": "Internal error — please retry", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ### Upstream errors (502 / 503) reAPI does not surface raw upstream `5xx` codes to the caller. When the upstream provider returns `502 Bad Gateway`, `503 Service Unavailable`, or a connection failure, the worker retries up to 5 attempts with exponential backoff (\~30s total budget). If all retries fail, the task ends with one of these reapi-specific error codes (returned via `GET /api/v1/tasks/{id}` as `error.code`): | reapi code | Meaning | Origin | | ---------- | -------------------------- | ------------------------------------ | | `80001` | `provider_submit_failed` | Upstream `5xx` / network on submit | | `80002` | `provider_polling_timeout` | Wall-clock cap reached while polling | | `80003` | `provider_failed` | Upstream returned a terminal failure | See [Errors catalog](/docs/api/errors) for the full code list. *** ## Polling | `status` | Meaning | | ------------ | ----------------------------- | | `processing` | Submitted, still generating | | `completed` | `output.image_urls` is ready | | `failed` | See `error.code`; not charged | Recommended cadence: ``` 0–30s: wait before the first poll 30s–3m: poll every 3–5s 3m+: back off to 10s; cap at 30s ``` A 1K image typically completes in 30 – 60 seconds; 2K adds \~30s; 4K can take 90 – 120 seconds. *** ## Related * [`gemini-2.5-flash-image-preview`](/docs/gemini-2-5-flash-image-preview) — faster, cheaper variant (1K only). * [`gemini-3.1-flash-image-preview`](/docs/gemini-3-1-flash-image-preview) — newer variant with extreme ratios and Google search grounding. * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Pricing — gemini-3-pro-image-preview](https://reapi.ai/models/gemini-3-pro-image-preview#pricing) --- # gemini-omni (https://reapi.ai/docs/gemini-omni) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Gemini Omni — Google's any-to-any video model, exposed through reapi as > a single async endpoint. Mode is implicit: the counts of `image_urls` / > `video_urls` pick **text-to-video**, **image-to-video**, > **three-image fusion**, or **reference-to-video**. 4 to 10 second outputs > at 720p, 1080p, or 4K. Flat per-generation pricing across every mode — see > the [model page](https://reapi.ai/models/gemini-omni). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-omni", "prompt": "A kitten playing piano, slow camera push-in", "duration": 6, "resolution": "1080p", "aspect_ratio": "16:9" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "gemini-omni", "prompt": "A kitten playing piano, slow camera push-in", "duration": 6, "resolution": "1080p", "aspect_ratio": "16:9", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "gemini-omni", prompt: "A kitten playing piano, slow camera push-in", duration: 6, resolution: "1080p", aspect_ratio: "16:9", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gemini-omni", "prompt": "A kitten playing piano, slow camera push-in", "duration": 6, "resolution": "1080p", "aspect_ratio": "16:9", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-omni", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URL, valid for 7 days. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Mode routing `gemini-omni` picks its mode from the **counts of `image_urls` and `video_urls`** you send — there is no `mode` parameter: | `image_urls` | `video_urls` | Mode | What it does | | ------------ | ------------ | ---------------------- | ------------------------------------------------------------------------ | | `0` | `0` | **Text-to-video** | Generate from a prompt. | | `1` | `0` | **Image-to-video** | Animate from a single starting frame. | | `3` | `0` | **Three-image fusion** | Combine three references into one motion shot. | | `0` / `1` | `1` | **Reference-to-video** | Reference a source clip (≤ 30s) for motion / style. Flat per generation. | **Unsupported counts.** * `image_urls = 2` is **rejected** with `400 image_urls cardinality 2 is not supported`. Submit 0, 1, or 3 — there is no first/last-frame mode on `gemini-omni`. * `image_urls = 4` or more is also rejected. * `video_urls = 2` or more is **rejected** with `400 video_urls accepts at most 1 entry`. * `duration` and `video_urls` cannot both be set. Reference-to-video mode reads the source clip's length; passing `duration` alongside is rejected with `400 duration and video_urls cannot both be set`. *** ## Request body ### `model` — required `string`. Must be `"gemini-omni"`. ### `prompt` — string, required Up to **2,000 characters**. Required in every mode (text-to-video, image-to-video, three-image fusion, reference-to-video). Empty / whitespace-only prompts are treated as missing. **Failure modes.** * Empty / missing → `400 prompt is required` (code `20002`). * Longer than 2,000 chars → `400 prompt exceeds 2000 characters (got N)` (code `20007`). ### `duration` — integer, default `6` One of `4`, `6`, `8`, `10` seconds. Other values are rejected with `400 duration must be 4, 6, 8, or 10 seconds, got N`. **Reference-to-video mode ignores `duration`.** When `video_urls` is set, the vendor reads the source clip's length to drive the output, and `duration` must be omitted. Passing both is rejected with `400 duration and video_urls cannot both be set`. ### `resolution` — string, default `"720p"` `720p` / `1080p` / `4k`. Lowercase is canonical; uppercase forms (`"4K"`) are accepted and normalized. Drives the per-generation rate — 720p and 1080p share the same price; only 4K is uplifted. ### `aspect_ratio` — string, default `"16:9"` Output framing. One of: | Value | Shape | | ------ | --------- | | `16:9` | Landscape | | `9:16` | Portrait | Unknown ratios are rejected with `400 invalid aspect_ratio`. ### `size` — string, alias for `aspect_ratio` The same value the supplier doc lists as a separate field. If both are sent, they must match; otherwise `400 aspect_ratio and size disagree`. The reapi playground does not surface `size`; the JSON body still accepts it for parity. ### `image_urls` — string\[] Array of public HTTP(S) URLs. **Allowed counts: 0, 1, or 3**. * **0 entries** — text-to-video. * **1 entry** — image-to-video; the image is treated as the starting frame. * **3 entries** — three-image fusion. The model combines all three references into one motion shot. ### `video_urls` — string\[] Array of public HTTP(S) URLs. **Allowed counts: 0 or 1**. * **0 entries** — non-reference modes (text / image / fusion). * **1 entry** — reference-to-video. The source clip drives the output; it must be **≤ 30 seconds** (longer is rejected with `400`), and the first ≤ 10 seconds are used as the reference. Billed at a **flat per-generation rate** (not per second). `duration` MUST be omitted in this mode. **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — every URL field on this endpoint must be a public HTTP(S) URL. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gemini-omni", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Always `"gemini-omni"` (echo of the submitted `model`) | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | `output.video_urls` URLs are valid for **7 days**. Re-host to your own storage if you need them longer. *** ## Validation errors All cases below return HTTP 400 with code `20003` unless noted. Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed values, etc.) and are not a stable contract. | Trigger | Code | Message (illustrative) | | -------------------------------------------------- | ------- | -------------------------------------------------------------------------------- | | `prompt` missing or blank | `20002` | `gemini-omni: prompt is required` | | `prompt` longer than 2,000 chars | `20007` | `gemini-omni: prompt exceeds 2000 characters (got N)` | | `image_urls` length `2` | `20003` | `gemini-omni: image_urls cardinality 2 is not supported` | | `image_urls` length > `3` | `20003` | `gemini-omni: image_urls accepts at most 3 entries, got N` | | `duration` not one of 4/6/8/10 | `20003` | `gemini-omni: duration must be 4, 6, 8, or 10 seconds, got N` | | Unknown `resolution` | `20003` | `gemini-omni: invalid resolution "X" (allowed: 720p / 1080p / 4k)` | | Unknown `aspect_ratio` | `20003` | `gemini-omni: invalid aspect_ratio "X" (allowed: 16:9 / 9:16)` | | `aspect_ratio` and `size` disagree | `20003` | `gemini-omni: aspect_ratio "X" and size "Y" disagree` | | `image_urls` carrying a `data:` URI or non-http(s) | `20003` | `gemini-omni: image_urls entries must be public http(s) URLs` | | `video_urls` source clip longer than 30 seconds | `20003` | `Reference video must be at most 30s (got Ns); trim the clip before submitting.` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### Text-to-video — minimum request ```json { "model": "gemini-omni", "prompt": "A little girl walking down a sunset coastal road" } ``` ### Text-to-video — full parameters ```json { "model": "gemini-omni", "prompt": "A kitten playing piano, slow camera push-in, cinematic warm tones", "duration": 8, "resolution": "1080p", "aspect_ratio": "16:9" } ``` ### Image-to-video — animate a single frame ```json { "model": "gemini-omni", "prompt": "Bring the scene to life with a gentle camera dolly forward", "image_urls": ["https://your-cdn.com/first_frame.jpg"], "duration": 6, "resolution": "1080p" } ``` ### Three-image fusion ```json { "model": "gemini-omni", "prompt": "Compose a 10-second product spot mixing scene, character, and product", "image_urls": [ "https://your-cdn.com/scene.jpg", "https://your-cdn.com/character.jpg", "https://your-cdn.com/product.jpg" ], "duration": 10, "resolution": "1080p", "aspect_ratio": "9:16" } ``` ### 4K hero shot ```json { "model": "gemini-omni", "prompt": "A neon city street in the rain, slow camera pan, reflections on the asphalt", "duration": 4, "resolution": "4k", "aspect_ratio": "16:9" } ``` ### Reference-to-video — match a source clip ```json { "model": "gemini-omni", "prompt": "the same scene but at night with neon lights", "resolution": "720p", "aspect_ratio": "16:9", "video_urls": ["https://your-cdn.com/source.mp4"] } ``` The output tracks the source clip (which must be **≤ 30s**; the first ≤ 10s are used as the reference); **omit `duration`**. Billing is a flat per-generation rate (see [Pricing](#pricing) below). *** ## Choosing a mode | Need | Send | | ---------------------------------------- | ------------------------------------------------- | | Generate from text | `prompt` only | | Animate a still | `prompt + image_urls` (1 entry) | | Compose scene + character + product | `prompt + image_urls` (3 entries) | | Match an existing clip's motion / length | `prompt + video_urls` (1 entry, no `duration`) | | Cut spend | Drop `resolution` to `720p` and `duration` to `4` | | Hero shot | Pick `4k` at `4-10s` | *** ## Polling pattern The task endpoint behaves identically to other video tasks — the only difference is the completed `output` shape (`video_urls` instead of `image_urls`). A pragmatic schedule: ``` 0–5 minutes: poll every 5s 5 min – 1 h: back off gradually toward 1 min ≥ 1 h: cap at 3 min between polls ``` A typical task completes in a few minutes. The worker's wall-clock cap is **48 hours**, comfortably above any realistic queue. *** ## Pricing Two billing modes — picked by request shape. ### Per generation — text / image / fusion Charged once per submitted job. 720p and 1080p share the same rate at every duration; only 4K is uplifted. Duration tiers are `4s` / `6s` / `8s` / `10s`. See current per-tier rates on the [Gemini Omni model page](https://reapi.ai/models/gemini-omni). ### Flat per generation — reference-to-video Triggered when `video_urls` is set. Charged once per job at a flat rate by resolution — independent of clip length. 720p and 1080p share the same rate; 4K is uplifted. The source clip must be **≤ 30 seconds**: the gateway probes its decoded length server-side and rejects longer clips with `400`; the first ≤ 10 seconds are used as the reference. See current rates on the [Gemini Omni model page](https://reapi.ai/models/gemini-omni). ### Bill formula `1 credit = $0.001`. Integer credits = `ceil(usd × 1000)`. Failed jobs refund automatically. *** ## Tips * **Prompt motion, not just scene.** "Slow push-in, warm tones, shallow depth of field" outperforms a pure noun-list of what's on screen. * **Pick 720p first if you're iterating.** It's the same per-generation price as 1080p, but renders faster and lets you change your mind on the final tier without re-doing the bill math. * **Three-image fusion needs cohesive references.** Pick three images that share lighting and composition cues — the model fuses them more cleanly than three random shots. * **Pick 4K only when shipping.** A 4K render is roughly 2× the cost of 720p / 1080p; reserve it for the final keeper. * **Keep reference clips ≤ 30s.** Reference-to-video requires a source clip of **≤ 30 seconds** (the server probes its length via ffmpeg and rejects anything longer with `400`); only the first ≤ 10 seconds are used as the reference. Billing is a flat per-generation rate regardless of length. Omit `duration` — the server rejects requests that pass both. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # glm-5.2 (https://reapi.ai/docs/glm-5-2) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Z.AI's GLM-5.2 — a flagship foundation model built for long-horizon tasks — > exposed through api.reapi.ai as a drop-in OpenAI-compatible Chat Completions > endpoint. A **1M-token** context window Z.AI describes as *solid and lossless*, > **128K** max output, thinking **on by default but switchable off**, a > `reasoning_effort` dial that no other model in the GLM family accepts, genuinely > tunable `temperature` / `top_p`, function calling with streamed tool arguments, > JSON mode and context caching. Text in, text out. The wire `model` id is > **`glm-5.2`** — with the dot. Current rates live on the > [model page](https://reapi.ai/models/glm-5-2) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). **The URL and the model id differ.** This page and the model page spell the slug `glm-5-2` because a URL cannot carry the dot. The string your request body needs is `glm-5.2`. Sending `glm-5-2` as the model is the first thing to check on an unknown-model error. ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-5.2", "messages": [ { "role": "user", "content": "Refactor this module and add tests." } ], "thinking": { "type": "enabled" }, "reasoning_effort": "max", "max_tokens": 8192, "stream": true }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="glm-5.2", messages=[{"role": "user", "content": "Refactor this module and add tests."}], max_tokens=8192, stream=True, extra_body={ "thinking": {"type": "enabled"}, "reasoning_effort": "max", }, ) for chunk in stream: delta = chunk.choices[0].delta reasoning = getattr(delta, "reasoning_content", None) if reasoning: print(reasoning, end="") if delta.content: print(delta.content, end="") ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "glm-5.2", messages: [{ role: "user", content: "Refactor this module and add tests." }], max_tokens: 8192, stream: true, // @ts-expect-error vendor-specific fields pass through thinking: { type: "enabled" }, reasoning_effort: "max", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "glm-5.2", "messages": []map[string]string{ {"role": "user", "content": "Refactor this module and add tests."}, }, "thinking": map[string]string{"type": "enabled"}, "reasoning_effort": "max", "max_tokens": 8192, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Chat models are served from the `api.reapi.ai` gateway, which has its own console and its own key. Create the key there, then send it as a bearer token: ```http Authorization: Bearer YOUR_API_KEY ``` The gateway key is **not** the same credential as a media-generation key used against `reapi.ai/api/v1`. Sign in at [api.reapi.ai](https://api.reapi.ai/) to create one. *** ## Endpoint ```http POST /v1/chat/completions ``` Base URL `https://api.reapi.ai`. The wire format is OpenAI-compatible, so the same SDKs (`openai-python`, `openai-node`, `openai-go`, …) work once you swap the base URL, the key and the model string. Vendor-specific fields such as `thinking` go through the SDK's pass-through mechanism — `extra_body` in Python. *** ## Request body ### `model` — string, required Must be `glm-5.2` exactly, dot included. ### `messages` — array, required Conversation history, each entry an object with `role` and `content`. Roles are `system`, `user`, `assistant` and `tool`. **Text only** — see [Modality](#modality). ### `max_tokens` — integer Upper bound on output tokens for this response. This model supports a **128K** maximum output and the schema accepts values up to **131,072**. Reasoning is generated before the answer and draws on the same allowance. ### `stream` — boolean, default `false` When `true`, tokens arrive as server-sent events terminated by `data: [DONE]`. Reasoning and answer arrive as **separate deltas** — `reasoning_content` and `content`. ### `thinking` — object, default `{"type": "enabled"}` Chain-of-thought control. See [Reasoning](#reasoning). ### `reasoning_effort` — string, default `"max"` How hard the model thinks; applies only while thinking is enabled. See [Reasoning](#reasoning) for the value-collapsing behaviour, which is the one surprise on this model. ### `temperature` / `top_p` — numbers Actually tunable here. See [Sampling parameters](#sampling-parameters). ### `tools` / `tool_choice` / `tool_stream` — optional Function definitions, selection strategy and streamed arguments. See [Tool calling](#tool-calling). ### `response_format` — object, optional `{"type": "text"}` (default) or `{"type": "json_object"}`. See [Structured output](#structured-output). ### `stop` — array, optional Stop words. **Only one is supported** despite the array shape. ### `group` — string, default `"default"` Token group on the gateway. Leave it at `default` unless your account has been given another group to route through. *** ## Reasoning Two things are unusual here, and both cut in the developer's favour. **1. Thinking is on by default, and can be turned off.** `thinking` defaults to `{"type": "enabled"}`, and `{"type": "disabled"}` is accepted — a switch several models in this class no longer offer. **2. With thinking on, the model decides per request whether to think.** Z.AI contrasts this explicitly with the previous generation, which reasoned unconditionally. Leaving thinking enabled therefore does not mean paying for reasoning on every trivial turn. ### The effort ladder collapses `reasoning_effort` accepts seven values for cross-provider compatibility, but they map onto **three** behaviours: | You send | What actually happens | | --------- | --------------------------------------------- | | `max` | **Default.** Deep reasoning. | | `xhigh` | Mapped to `max`. | | `high` | Enhanced reasoning — the real middle setting. | | `medium` | Mapped to `high`. | | `low` | Mapped to `high`. | | `minimal` | Skips thinking. | | `none` | Skips thinking. | **A middling value does not buy a middling cost.** `low` and `medium` both behave as `high`, so a client that drops to `low` expecting a cheap pass gets the same work as `high`. The only ways down are `high`, or skipping thinking entirely with `minimal` / `none`. ### Prior-turn reasoning is dropped by default `thinking.clear_thinking` defaults to **`true`**: the model ignores `reasoning_content` from earlier turns and keeps only visible text, tool calls and tool results. That keeps multi-turn context short and cheap, and it is why this model needs no special history handling out of the box. Set it to `false` for Preserved Thinking — and then the full, unmodified, correctly ordered `reasoning_content` history must be forwarded. Missing, truncated, rewritten or reordered blocks degrade the result. *** ## Sampling parameters Unlike several open-weight peers that pin these, both work: | Parameter | Range | Default | | ------------- | ----------------- | ------- | | `temperature` | `0.0` – **`1.0`** | `1.0` | | `top_p` | `0.01` – `1.0` | `0.95` | **`temperature` is capped at 1.0.** Code carried over from a provider that allows up to 2.0 will be rejected. Z.AI also advises tuning **one** of the two rather than both — `temperature` for creative latitude, `top_p` for convergence. A separate `do_sample` flag defaults to `true`; setting it `false` makes both sampling parameters stop taking effect. *** ## Tool calling * `tools` accepts up to **128** functions. * `tool_choice` accepts **`auto` only** — the model decides when a call is warranted. There is no `required` or per-function forcing on this model. * `tool_stream: true` streams tool-call arguments as they are generated instead of delivering the complete call at once. Concatenate `delta.tool_calls[*].function.arguments` across chunks. After executing calls, append one `tool` message per call with the matching `tool_call_id` before asking for the next completion. *** ## Structured output ```json { "response_format": { "type": "json_object" } } ``` This is **JSON mode, not JSON Schema** — you do not supply a schema and the model does not validate against one. Ask for the shape you want in the prompt as well, which Z.AI recommends explicitly. If you need schema-guaranteed fields, validate on your side after parsing. *** ## Modality | Modality | Supported | | -------- | :-------: | | Text in | ✅ | | Text out | ✅ | | Image in | ❌ | | Video in | ❌ | Z.AI's model card lists input and output modalities for this model as **text**. Vision is a different model in their lineup. If a step in your workflow needs a screenshot read, route that step elsewhere — this model is a strong choice for the code around it, not for looking at it. *** ## Context caching Caching is part of this model's capability set and rewards the obvious shape: keep a long stable prefix — system prompt, knowledge document, tool definitions — in front of a changing question, and let repeat requests reuse it. No cache id and no TTL to manage. Z.AI prices cached input as its own dimension. **reAPI does not publish a separate cached-input rate for this model**, so treat caching as a latency and context-length benefit here, and bill against the input and output rates in the pricing table. *** ## Pricing dimensions Billing is **per token**, in USD, against your `api.reapi.ai` balance, with separate **input** and **output** rates. Three things to keep in mind: * **Reasoning tokens bill as output.** Thinking is on by default at the deepest effort setting, which is the usual reason a bill exceeds an estimate built from visible answer length. * **Effort is the first lever.** Because the ladder collapses, the meaningful choices are deep (`max`), enhanced (`high`) or none at all. * **Output dominates.** For most generative workloads the output rate decides the invoice. Both token rates sit at **about a third below Z.AI's published per-token rate**. Current numbers are on the [model page](https://reapi.ai/models/glm-5-2) and [api.reapi.ai/pricing](https://api.reapi.ai/pricing) — those tables are the canonical source, not this page. Chat models bill in USD on the gateway balance. They do **not** draw down the integer credits used by the media-generation endpoints on `reapi.ai/api/v1`. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1785000000, "model": "glm-5.2", "choices": [ { "index": 0, "message": { "role": "assistant", "reasoning_content": "...", "content": "..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 1204, "completion_tokens": 860, "total_tokens": 2064 } } ``` `reasoning_content` is a sibling of `content`. Unless you have turned off `clear_thinking`, you do not need to send it back. ### Streaming (`stream: true`) Server-sent events, each `data:` line carrying a `chat.completion.chunk`. Reasoning arrives in `choices[0].delta.reasoning_content` and the answer in `choices[0].delta.content`, terminated by `data: [DONE]`. *** ## Errors Failures use the gateway's standard envelope. See the [errors catalog](/docs/api/errors) for the full code list. Common cases: | Trigger | What to do | | --------------------------------------------------- | ----------------------------------------------------- | | Missing or invalid bearer token | Create a key in the api.reapi.ai console | | Unknown `model` value | Send `glm-5.2` with the dot — not the hyphenated slug | | `temperature` above `1.0` | Lower it; the ceiling is 1.0 on this model | | `tool_choice` set to `required` or a named function | Only `auto` is supported | | An image part in `messages` | Not a multimodal model — route vision elsewhere | | More than one entry in `stop` | Only one stop word is supported | | `max_tokens` above the ceiling | Lower it; the documented ceiling is 131,072 | | `reasoning_effort` sent with thinking disabled | It only takes effect while thinking is enabled | | Insufficient balance | Top up on the gateway | | Upstream rate limit | Retry with backoff, or route through another model | *** ## Tips * **Send the whole project, then ask for the audit first.** Z.AI's own recommended opening move is an architecture map, module responsibilities, API contracts, data flows and technical debt — before any edit. * **Bound long tasks explicitly.** State what must not change (business logic, API signatures, runtime behaviour) and ask for the plan, impact scope, risk boundaries and verification method up front. * **Give it your real engineering standards.** Lint rules, build commands, test requirements, commit conventions and prohibited actions belong in the prompt; adherence under long context is what this generation improved. * **Pick an effort behaviour, not a number.** Deep, enhanced, or none — the values in between are aliases. * **Mind the `temperature` ceiling** of 1.0, and tune one sampling parameter rather than both. * **Stream anything interactive**, and render `reasoning_content` separately from the answer rather than concatenating them. * **Front-load the stable bulk** of your prompt so caching can do its job. *** ## Related * [GLM-5.2 model page](https://reapi.ai/models/glm-5-2) — current rates * [Kimi K3](/docs/kimi-k3) — the other open-weight 1M-context coding flagship * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # gpt-5.4 (https://reapi.ai/docs/gpt-5-4) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > GPT-5.4 is OpenAI's established reasoning model, exposed through > api.reapi.ai as a drop-in OpenAI-compatible Chat Completions endpoint. > 1M token context, 128K max output, function calling, and JSON-mode > responses. The cost-efficient route in the GPT family — current rates > live on the [model page](https://reapi.ai/models/gpt-5-4) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.4", "group": "default", "messages": [ { "role": "user", "content": "Hello" } ], "stream": true, "temperature": 0.7, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="gpt-5.4", messages=[{"role": "user", "content": "Hello"}], stream=True, temperature=0.7, top_p=1, frequency_penalty=0, presence_penalty=0, extra_body={"group": "default"}, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "gpt-5.4", messages: [{ role: "user", content: "Hello" }], stream: true, temperature: 0.7, top_p: 1, frequency_penalty: 0, presence_penalty: 0, // `group` is an api.reapi.ai-specific extension; pass it via extra body. // @ts-expect-error — not part of the OpenAI types group: "default", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gpt-5.4", "group": "default", "messages": []map[string]string{ {"role": "user", "content": "Hello"}, }, "stream": true, "temperature": 0.7, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Every request needs a Bearer token. The GPT-5.4 chat workspace lives on the `api.reapi.ai` platform — sign in there to create a key and top up tokens. 1. Open [api.reapi.ai](https://api.reapi.ai/) and sign in (or create an account). 2. Generate an API key under **API Keys**. 3. Top up tokens under **Top Up** (pay-as-you-go, billed in USD per 1M tokens — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing)). ```http Authorization: Bearer YOUR_API_KEY ``` The chat surface (api.reapi.ai) is a **separate workspace** from the image/video/audio task gateway at `reapi.ai/api/v1/*`. Keys and balances do not cross over — a key issued on `reapi.ai/settings/apikeys` will not authenticate against `api.reapi.ai/v1/chat/completions`, and vice versa. *** ## Endpoint ```http POST https://api.reapi.ai/v1/chat/completions ``` OpenAI-compatible. The same SDKs (`openai-python`, `openai-node`, `openai-go`, …) work once the base URL is set to `https://api.reapi.ai/v1`. *** ## Request body ### `model` — string, required Must be `"gpt-5.4"`. The value is echoed back in the response envelope. ### `messages` — array, required Conversation history as an array of message objects. Same shape as the OpenAI Chat Completions spec: ```json { "role": "system" | "user" | "assistant" | "tool", "content": "string or content-parts array" } ``` Multi-turn history is sent in chronological order — the last message is the one the model responds to. ### `stream` — boolean, default `false` When `true`, the response is streamed as server-sent events (SSE) with `Content-Type: text/event-stream`. Each event is a JSON delta in the OpenAI format, terminated by a `data: [DONE]` line. When `false`, the full response body is returned in one HTTP response. ### `temperature` — number, default `1` Range `0.0` – `2.0`. Sampling temperature. Lower values make output more deterministic; higher values increase randomness. OpenAI recommends tuning either `temperature` or `top_p`, not both. ### `top_p` — number, default `1` Range `0.0` – `1.0`. Nucleus sampling cutoff — restricts sampling to the smallest set of tokens whose cumulative probability mass exceeds `top_p`. ### `frequency_penalty` — number, default `0` Range `-2.0` – `2.0`. Penalises tokens by how often they've already appeared in the response so far. Positive values discourage literal repetition. ### `presence_penalty` — number, default `0` Range `-2.0` – `2.0`. Penalises tokens that have appeared at all, regardless of frequency. Positive values encourage the model to talk about new topics. ### `group` — string, default `"default"` api.reapi.ai-specific extension. Selects a token group on the gateway, which routes the request to a specific upstream channel pool. `"default"` is the standard pool and covers nearly every workload — omit the field if you don't need custom routing. ### Other OpenAI parameters Every other field on the OpenAI Chat Completions spec — `max_tokens`, `stop`, `n`, `seed`, `tools`, `tool_choice`, `response_format`, `logprobs`, `top_logprobs`, `user`, `parallel_tool_calls` — passes through unchanged. The OpenAI SDKs do not need a reAPI-specific shim. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "object": "chat.completion", "created": 1735000000, "model": "gpt-5.4", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21 } } ``` `usage.prompt_tokens` and `usage.completion_tokens` are the inputs to the bill — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing) for the live rate card. ### Streaming (`stream: true`) `Content-Type: text/event-stream`. Each `data:` line is a JSON delta: ``` data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1735000000,"model":"gpt-5.4","choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null}]} data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1735000000,"model":"gpt-5.4","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]} data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1735000000,"model":"gpt-5.4","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: [DONE] ``` The final event before `[DONE]` carries the `finish_reason` (`stop` / `length` / `tool_calls` / `content_filter`). Usage stats are omitted from the stream — call again with `stream: false` if you need exact token counts per turn. *** ## Pricing GPT-5.4 is billed **pay-as-you-go in USD** against your api.reapi.ai token balance. Current rates live on the model page and on [api.reapi.ai/pricing](https://api.reapi.ai/pricing); the table at the top of the [model page](https://reapi.ai/models/gpt-5-4) is the authoritative number for what you'll be charged today. Long-context billing: when the input portion of a single request exceeds **272K tokens**, the whole call is billed at **2× input and 1.5× output**. Requests at or below 272K input use the standard rate. Failed requests are not charged. *** ## Limits | Limit | Value | | ------------------- | ------------- | | Context window | 1M tokens | | Max output per call | 128K tokens | | Standard-rate input | ≤ 272K tokens | Streams that hit the output cap finish with `finish_reason: "length"`; call again with a continuation message if you need more text. *** ## Errors The error envelope follows the OpenAI shape — HTTP status, plus a JSON body: ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "..." } } ``` Common cases: | Status | When | Notes | | ------ | -------------------------------------- | -------------------------------------------- | | `400` | Bad request shape, unknown field, etc. | Same shape OpenAI returns | | `401` | Missing / invalid API key | Re-issue a key at api.reapi.ai | | `402` | Insufficient balance | Top up at api.reapi.ai | | `429` | Per-group rate limit hit | Back off, or move to a different `group` | | `500` | Upstream / gateway error | Safe to retry — failed calls are not charged | api.reapi.ai does **not** internally retry chat requests. Every customer call maps to exactly one upstream POST. If a network error reaches you, that's a one-for-one wire failure and a retry from your side is safe; the upstream provider may have already produced output, but the gateway will not double-bill. *** ## Recipes ### Minimum request ```json { "model": "gpt-5.4", "messages": [ { "role": "user", "content": "Summarise the OpenAI Chat Completions spec in three sentences." } ] } ``` ### Full parameter set ```json { "model": "gpt-5.4", "group": "default", "messages": [ { "role": "system", "content": "You are a senior staff engineer." }, { "role": "user", "content": "Walk me through a 1M-token codebase review strategy." } ], "stream": true, "temperature": 0.7, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0 } ``` ### Tool use (function calling) ```json { "model": "gpt-5.4", "messages": [ { "role": "user", "content": "What's the weather in Tokyo today?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Look up the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ], "tool_choice": "auto" } ``` ### JSON mode ```json { "model": "gpt-5.4", "response_format": { "type": "json_object" }, "messages": [ { "role": "system", "content": "Return a JSON object with keys: title, summary, tags." }, { "role": "user", "content": "Article: ..." } ] } ``` *** ## When to pick GPT-5.4 over GPT-5.5 GPT-5.4 and GPT-5.5 share the same endpoint, the same context window, and the same OpenAI-compatible wire format — switching between them is a one-line change in the `model` field. Pick GPT-5.4 when: * **High-volume production traffic** where per-call cost dominates the decision. * **Established workflows** (classification, extraction, summarisation, routine support replies) that don't benefit from GPT-5.5's newest reasoning gains or Tool Search. * **Latency-sensitive surfaces** where a slightly less expensive model also tends to respond faster on identical inputs. Pick GPT-5.5 when you need its strongest reasoning, Tool Search for large agent ecosystems, or `reasoning_effort` controls. *** ## Tips * **Stream by default for chat UX.** Streaming responses cut perceived latency dramatically and let your UI render tokens as they're produced. * **Watch the long-context boundary.** Splitting a 300K-token prompt into a 270K turn and a follow-up keeps you on the standard rate rather than the long-context tier. * **Tune `temperature` *or* `top_p`, not both.** Mixing them tends to produce results that are hard to reason about. * **Use `response_format: { type: "json_object" }` for structured output.** Much more reliable than parsing free-text JSON that the model writes inside backticks. * **Drop `frequency_penalty` and `presence_penalty` first when debugging weird output.** Non-zero values can introduce artefacts that look like model bugs. *** ## Related * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Errors catalog](/docs/api/errors) --- # gpt-5.5 (https://reapi.ai/docs/gpt-5-5) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > GPT-5.5 is OpenAI's frontier reasoning model, exposed through reAPI as a > drop-in OpenAI-compatible Chat Completions endpoint. 1M token context, > 128K max output, advanced reasoning with adjustable effort, and Tool > Search for large agent workflows. Current rates live on the > [model page](https://reapi.ai/models/gpt-5-5) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.5", "group": "default", "messages": [ { "role": "user", "content": "Hello" } ], "stream": true, "temperature": 0.7, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="gpt-5.5", messages=[{"role": "user", "content": "Hello"}], stream=True, temperature=0.7, top_p=1, frequency_penalty=0, presence_penalty=0, extra_body={"group": "default"}, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "gpt-5.5", messages: [{ role: "user", content: "Hello" }], stream: true, temperature: 0.7, top_p: 1, frequency_penalty: 0, presence_penalty: 0, // `group` is a reAPI-specific extension; pass it via extra body. // @ts-expect-error — not part of the OpenAI types group: "default", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gpt-5.5", "group": "default", "messages": []map[string]string{ {"role": "user", "content": "Hello"}, }, "stream": true, "temperature": 0.7, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Every request needs a Bearer token. The GPT-5.5 chat workspace lives on the `api.reapi.ai` platform — sign in there to create a key and top up tokens. 1. Open [api.reapi.ai](https://api.reapi.ai/) and sign in (or create an account). 2. Generate an API key under **API Keys**. 3. Top up tokens under **Top Up** (pay-as-you-go, billed in USD per 1M tokens — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing)). ```http Authorization: Bearer YOUR_API_KEY ``` The chat surface (api.reapi.ai) is a **separate workspace** from the image/video/audio task gateway at `reapi.ai/api/v1/*`. Keys and balances do not cross over — a key issued on `reapi.ai/settings/apikeys` will not authenticate against `api.reapi.ai/v1/chat/completions`, and vice versa. *** ## Endpoint ```http POST https://api.reapi.ai/v1/chat/completions ``` OpenAI-compatible. The same SDKs (`openai-python`, `openai-node`, `openai-go`, …) work once the base URL is set to `https://api.reapi.ai/v1`. *** ## Request body ### `model` — string, required Must be `"gpt-5.5"`. The value is echoed back in the response envelope. ### `messages` — array, required Conversation history as an array of message objects. Same shape as the OpenAI Chat Completions spec: ```json { "role": "system" | "user" | "assistant" | "tool", "content": "string or content-parts array" } ``` Multi-turn history is sent in chronological order — the last message is the one the model responds to. ### `stream` — boolean, default `false` When `true`, the response is streamed as server-sent events (SSE) with `Content-Type: text/event-stream`. Each event is a JSON delta in the OpenAI format, terminated by a `data: [DONE]` line. When `false`, the full response body is returned in one HTTP response. ### `temperature` — number, default `1` Range `0.0` – `2.0`. Sampling temperature. Lower values make output more deterministic; higher values increase randomness. OpenAI recommends tuning either `temperature` or `top_p`, not both. ### `top_p` — number, default `1` Range `0.0` – `1.0`. Nucleus sampling cutoff — restricts sampling to the smallest set of tokens whose cumulative probability mass exceeds `top_p`. ### `frequency_penalty` — number, default `0` Range `-2.0` – `2.0`. Penalises tokens by how often they've already appeared in the response so far. Positive values discourage literal repetition. ### `presence_penalty` — number, default `0` Range `-2.0` – `2.0`. Penalises tokens that have appeared at all, regardless of frequency. Positive values encourage the model to talk about new topics. ### `group` — string, default `"default"` reAPI-specific extension. Selects a token group on the gateway, which routes the request to a specific upstream channel pool. `"default"` is the standard pool and covers nearly every workload — you can omit the field if you don't need custom routing. ### Other OpenAI parameters Every other field on the OpenAI Chat Completions spec — `max_tokens`, `stop`, `n`, `seed`, `tools`, `tool_choice`, `response_format`, `logprobs`, `top_logprobs`, `user`, `parallel_tool_calls`, `reasoning_effort` (`none` / `low` / `medium` / `high` / `xhigh`) — passes through unchanged. The OpenAI SDKs do not need a reAPI-specific shim. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "object": "chat.completion", "created": 1735000000, "model": "gpt-5.5", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21 } } ``` `usage.prompt_tokens` and `usage.completion_tokens` are the inputs to the bill — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing) for the live rate card. ### Streaming (`stream: true`) `Content-Type: text/event-stream`. Each `data:` line is a JSON delta: ``` data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1735000000,"model":"gpt-5.5","choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null}]} data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1735000000,"model":"gpt-5.5","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]} data: {"id":"chatcmpl-…","object":"chat.completion.chunk","created":1735000000,"model":"gpt-5.5","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: [DONE] ``` The final event before `[DONE]` carries the `finish_reason` (`stop` / `length` / `tool_calls` / `content_filter`). Usage stats are omitted from the stream — call again with `stream: false` if you need exact token counts per turn. *** ## Pricing GPT-5.5 is billed **pay-as-you-go in USD** against your api.reapi.ai token balance. The live per-1M-token rate card lives on [api.reapi.ai/pricing](https://api.reapi.ai/pricing); top up tokens at [api.reapi.ai](https://api.reapi.ai/). The bill for a single call is: ``` input_cost = prompt_tokens × input_rate / 1,000,000 output_cost = completion_tokens × output_rate / 1,000,000 ``` Failed requests are not charged. ### Long-context tier (>272K input tokens) When the input portion of a single request exceeds 272K tokens, the entire request is billed at **2× the input rate** and **1.5× the output rate**. A request with 270K input tokens stays at the standard rate; a request with 280K input tokens shifts the whole call (input *and* output) to the long-context rate. See [api.reapi.ai/pricing](https://api.reapi.ai/pricing) for the resolved per-1M-token numbers in both tiers. *** ## Limits | Limit | Value | | ------------------- | ------------- | | Context window | 1M tokens | | Max output per call | 128K tokens | | Standard-rate input | ≤ 272K tokens | Streams that hit the output cap finish with `finish_reason: "length"`; call again with a continuation message if you need more text. *** ## Errors The error envelope follows the OpenAI shape — HTTP status, plus a JSON body: ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "..." } } ``` Common cases: | Status | When | Notes | | ------ | -------------------------------------- | -------------------------------------------- | | `400` | Bad request shape, unknown field, etc. | Same shape OpenAI returns | | `401` | Missing / invalid API key | Re-issue a key at api.reapi.ai | | `402` | Insufficient balance | Top up at api.reapi.ai | | `429` | Per-group rate limit hit | Back off, or move to a different `group` | | `500` | Upstream / gateway error | Safe to retry — failed calls are not charged | api.reapi.ai does **not** internally retry chat requests. Every customer call maps to exactly one upstream POST. If a network error reaches you, that's a one-for-one wire failure and a retry from your side is safe; the upstream provider may have already produced output, but the gateway will not double-bill. *** ## Recipes ### Minimum request ```json { "model": "gpt-5.5", "messages": [ { "role": "user", "content": "Summarise the OpenAI Chat Completions spec in three sentences." } ] } ``` ### Full parameter set ```json { "model": "gpt-5.5", "group": "default", "messages": [ { "role": "system", "content": "You are a senior staff engineer." }, { "role": "user", "content": "Walk me through a 1M-token codebase review strategy." } ], "stream": true, "temperature": 0.7, "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0 } ``` ### Tool use (function calling) ```json { "model": "gpt-5.5", "messages": [ { "role": "user", "content": "What's the weather in Tokyo today?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Look up the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ], "tool_choice": "auto" } ``` ### Reasoning effort ```json { "model": "gpt-5.5", "reasoning_effort": "high", "messages": [ { "role": "user", "content": "Prove that the sum of the first n odd numbers is n^2." } ] } ``` `reasoning_effort` accepts `none` / `low` / `medium` / `high` / `xhigh` — pick the lowest level that still produces correct output for the workload to keep latency and token spend down. *** ## Tips * **Stream by default for chat UX.** Streaming responses cut perceived latency dramatically and let your UI render tokens as they're produced. * **Watch the long-context boundary.** Splitting a 300K-token prompt into a 270K turn and a follow-up keeps you on the standard rate rather than paying the 2× / 1.5× long-context premium. * **Tune `temperature` *or* `top_p`, not both.** Mixing them tends to produce results that are hard to reason about. * **`reasoning_effort: high` is the right default for agents.** Reserve `xhigh` for the genuinely hard turns — it adds latency and token spend. * **Drop `frequency_penalty` and `presence_penalty` first when debugging weird output.** Non-zero values can introduce artefacts that look like model bugs. *** ## Related * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Errors catalog](/docs/api/errors) --- # gpt-5.6-luna (https://reapi.ai/docs/gpt-5-6-luna) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > OpenAI's GPT-5.6 Luna — the tier optimised for cost-sensitive, high-volume workloads — exposed through api.reapi.ai as a drop-in > OpenAI-compatible Chat Completions endpoint. A **1,050,000-token** context > window, **128,000** max output tokens, six `reasoning_effort` rungs from > `none` to `max` defaulting to **`medium`**, text and image input, and > functions, web search, file search and computer use. OpenAI rates its reasoning **High** and its speed Fast. The wire > `model` id is **`gpt-5.6-luna`**. Current rates live on the > [model page](https://reapi.ai/models/gpt-5-6-luna) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). **The URL and the model id differ.** This page and the model page spell the slug `gpt-5-6-luna` because a URL cannot carry dots. The string your request body needs is `gpt-5.6-luna`. ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.6-luna", "messages": [ { "role": "user", "content": "Classify this ticket. Return only the category id." } ], "reasoning_effort": "none", "max_completion_tokens": 4096, "stream": true }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="gpt-5.6-luna", messages=[{"role": "user", "content": "Classify this ticket. Return only the category id."}], reasoning_effort="none", max_completion_tokens=4096, stream=True, ) for chunk in stream: delta = chunk.choices[0].delta.content if delta: print(delta, end="") ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "gpt-5.6-luna", messages: [{ role: "user", content: "Classify this ticket. Return only the category id." }], reasoning_effort: "none", max_completion_tokens: 4096, stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gpt-5.6-luna", "messages": []map[string]string{ {"role": "user", "content": "Classify this ticket. Return only the category id."}, }, "reasoning_effort": "none", "max_completion_tokens": 4096, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Chat models are served from the `api.reapi.ai` gateway, which has its own console and its own key. Create the key there, then send it as a bearer token: ```http Authorization: Bearer YOUR_API_KEY ``` The gateway key is **not** the same credential as a media-generation key used against `reapi.ai/api/v1`. Sign in at [api.reapi.ai](https://api.reapi.ai/) to create one. *** ## Endpoint ```http POST /v1/chat/completions ``` Base URL `https://api.reapi.ai`. The wire format is OpenAI-compatible, so the same SDKs work once you swap the base URL, the key and the model string. OpenAI states that its reasoning models "work better with the Responses API", and that "while the Chat Completions API is still supported, you'll get improved model intelligence and performance by using Responses." The GPT-5.6 release entry lists `v1/responses`, `v1/chat/completions` and `v1/batch` as this family's endpoints — so Chat Completions is a documented, supported surface, and this is a vendor preference rather than a restriction. *** ## Request body ### `model` — string, required Must be `gpt-5.6-luna` exactly. There is no alias for this tier — the bare `gpt-5.6` id routes to the frontier model instead. ### `messages` — array, required Conversation history, each entry an object with `role` and `content`. Roles are `system`, `user`, `assistant` and `tool`. Text and image parts are supported — see [Image input](#image-input). ### `max_completion_tokens` — integer Upper bound on generated tokens for this response, **reasoning tokens included**. The documented maximum output is **128,000** tokens. Reasoning tokens bill as **output** tokens and occupy the context window. A budget sized only for the visible answer can truncate on a harder prompt, and it is the usual reason an invoice exceeds an estimate built from answer length. ### `reasoning_effort` — string, default `"medium"` How much the model thinks before answering. See [Reasoning effort](#reasoning-effort). ### `stream` — boolean, default `false` When `true`, tokens arrive as server-sent events terminated by `data: [DONE]`. On a volume route the useful reason to stream is early cancellation: you can abandon a response that has already gone wrong instead of paying for the rest of it. ### `tools` / `tool_choice` — optional Function definitions and the selection strategy. Functions, web search, file search and computer use are all available on this family, and this generation adds programmatic tool calling. ### `response_format` — object, optional Constrains the answer's shape, including a JSON schema for machine-consumed output. ### `group` — string, default `"default"` Token group on the gateway. Leave it at `default` unless your account has been given another group to route through. *** ## Reasoning effort Six rungs, and unlike some families these do not collapse into one another — each is a distinct behaviour. The default is **`medium`**: OpenAI's docs state that "if you omit reasoning.effort, GPT-5.6 defaults to medium in both modes." | Effort | OpenAI's stated best-for | | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `none` | Latency-critical tasks that do not benefit from reasoning or multi-chained tool calls — voice, fast retrieval, classification | | `low` | Efficient reasoning with modest added latency: tool use, planning, search, multi-step decisions | | `medium` | **Default.** Quality and reliability where the task involves planning and judgement — agentic coding, research, spreadsheets and slides, delegated long-horizon work | | `high` | Hard reasoning, complex debugging, deep planning, high-value tasks where quality beats latency | | `xhigh` | Deep research and long asynchronous runs — security and code review, enterprise productivity. "Only use when your evals show a clear benefit" | | `max` | "Maximum reasoning for your most complex tasks. If you are currently using xhigh, evaluate if max results in stronger performance" | There is **no `minimal`** on this family. This is the tier the bottom of that ladder exists for. **Set effort explicitly** — the default is `medium`, so a request that omits the field is paying for a reasoning pass a classification route probably does not want. OpenAI also documents a **Pro reasoning mode** for GPT-5.6 (`reasoning.mode`, independent of effort), and **multi-agent orchestration** in beta. Both are features of OpenAI's Responses API, so neither is part of a Chat Completions request through this endpoint. *** ## Image input | Modality | Supported | | -------- | :-------: | | Text in | ✅ | | Image in | ✅ | | Text out | ✅ | This generation accepts images **at their original dimensions**, with `original` or `auto` image detail — no resizing step required before a screenshot or scan goes in. Output is text only. *** ## Pricing dimensions Billing is **per token**, in USD, against your `api.reapi.ai` balance, with separate **input** and **output** rates. Three things to keep in mind: * **Reasoning tokens bill as output.** The default effort is `medium`, so a request that omits the field is paying for a reasoning pass. * **Effort is the first lever**, and on this family every rung is real — a middle setting buys a middle cost. * **The tier is the second lever.** All three GPT-5.6 tiers share this context window, this output ceiling, this effort ladder and this endpoint, so moving between them changes reasoning depth and price, not capability surface. Both token rates sit **20% below OpenAI's published per-token rate**, on input and output alike. Current numbers are on the [model page](https://reapi.ai/models/gpt-5-6-luna) and [api.reapi.ai/pricing](https://api.reapi.ai/pricing) — those tables are the canonical source, not this page. OpenAI prices cached input as a separate dimension. **reAPI does not publish a cached-input rate for this model**, so bill against the input and output rates in the pricing table. Chat models bill in USD on the gateway balance. They do **not** draw down the integer credits used by the media-generation endpoints on `reapi.ai/api/v1`. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1785000000, "model": "gpt-5.6-luna", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 1204, "completion_tokens": 860, "total_tokens": 2064 } } ``` `usage.completion_tokens` includes reasoning tokens, so it is the number to reconcile a bill against. On OpenAI's own Responses API the split is reported under `output_tokens_details.reasoning_tokens`. ### Streaming (`stream: true`) Server-sent events, each `data:` line carrying a `chat.completion.chunk` with the incremental text in `choices[0].delta.content`, terminated by `data: [DONE]`. *** ## Errors Failures use the gateway's standard envelope. See the [errors catalog](/docs/api/errors) for the full code list. Common cases: | Trigger | What to do | | ----------------------------------------- | ---------------------------------------------------------------------------------- | | Missing or invalid bearer token | Create a key in the api.reapi.ai console | | Unknown `model` value | Send `gpt-5.6-luna` with the dots — not the hyphenated slug | | `reasoning_effort` set to `minimal` | Not a value on this family — use `none`, `low`, `medium`, `high`, `xhigh` or `max` | | `reasoning.mode` or multi-agent fields | Responses-API features; not part of a Chat Completions request | | `max_completion_tokens` above the ceiling | Lower it; the documented maximum output is 128,000 | | Truncated answer on a hard prompt | The reasoning pass consumed the allowance — raise `max_completion_tokens` | | Insufficient balance | Top up on the gateway | | Upstream rate limit | Retry with backoff, or route through another tier | *** ## Tips * **Set effort explicitly.** The default is `medium`; on this tier `none` or `low` is usually what you actually mean. * **Cap `max_completion_tokens` tight.** On volume work it is a cost ceiling, not just a length limit. * **Constrain the output with a schema.** A machine-parsed route turns a bad answer into a validation error you can see. * **Do not pair `none` with a long tool loop.** OpenAI ties the no-reasoning rung to routes without multi-chained tool calls; raise the effort instead. * **Use it as the first stage.** Cheap triage here, escalation to a dearer tier by model string, is the biggest cost lever on a chat workload. * **The window is the frontier tier's.** Dropping to this tier does not force you to split long inputs. *** ## Related * [GPT-5.6 Luna model page](https://reapi.ai/models/gpt-5-6-luna) — current rates * [GPT-5.6 Terra](/docs/gpt-5-6-terra) — the balanced tier above it * [GPT-5.6 Sol](/docs/gpt-5-6-sol) — the frontier tier * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # gpt-5.6-sol (https://reapi.ai/docs/gpt-5-6-sol) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > OpenAI's GPT-5.6 Sol — the frontier model for complex professional work — exposed through api.reapi.ai as a drop-in > OpenAI-compatible Chat Completions endpoint. A **1,050,000-token** context > window, **128,000** max output tokens, six `reasoning_effort` rungs from > `none` to `max` defaulting to **`medium`**, text and image input, and > functions, web search, file search and computer use. OpenAI rates its reasoning **Highest** in this family and its speed Fast. The wire > `model` id is **`gpt-5.6-sol`**. Current rates live on the > [model page](https://reapi.ai/models/gpt-5-6-sol) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). **The URL and the model id differ.** This page and the model page spell the slug `gpt-5-6-sol` because a URL cannot carry dots. The string your request body needs is `gpt-5.6-sol`. ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.6-sol", "messages": [ { "role": "user", "content": "Review this migration plan and identify the failure modes." } ], "reasoning_effort": "high", "max_completion_tokens": 16000, "stream": true }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="gpt-5.6-sol", messages=[{"role": "user", "content": "Review this migration plan and identify the failure modes."}], reasoning_effort="high", max_completion_tokens=16000, stream=True, ) for chunk in stream: delta = chunk.choices[0].delta.content if delta: print(delta, end="") ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "gpt-5.6-sol", messages: [{ role: "user", content: "Review this migration plan and identify the failure modes." }], reasoning_effort: "high", max_completion_tokens: 16000, stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gpt-5.6-sol", "messages": []map[string]string{ {"role": "user", "content": "Review this migration plan and identify the failure modes."}, }, "reasoning_effort": "high", "max_completion_tokens": 16000, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Chat models are served from the `api.reapi.ai` gateway, which has its own console and its own key. Create the key there, then send it as a bearer token: ```http Authorization: Bearer YOUR_API_KEY ``` The gateway key is **not** the same credential as a media-generation key used against `reapi.ai/api/v1`. Sign in at [api.reapi.ai](https://api.reapi.ai/) to create one. *** ## Endpoint ```http POST /v1/chat/completions ``` Base URL `https://api.reapi.ai`. The wire format is OpenAI-compatible, so the same SDKs work once you swap the base URL, the key and the model string. OpenAI states that its reasoning models "work better with the Responses API", and that "while the Chat Completions API is still supported, you'll get improved model intelligence and performance by using Responses." The GPT-5.6 release entry lists `v1/responses`, `v1/chat/completions` and `v1/batch` as this family's endpoints — so Chat Completions is a documented, supported surface, and this is a vendor preference rather than a restriction. *** ## Request body ### `model` — string, required Must be `gpt-5.6-sol` exactly. The bare `gpt-5.6` alias also routes here; sending the suffixed id pins the tier you are paying for. ### `messages` — array, required Conversation history, each entry an object with `role` and `content`. Roles are `system`, `user`, `assistant` and `tool`. Text and image parts are supported — see [Image input](#image-input). ### `max_completion_tokens` — integer Upper bound on generated tokens for this response, **reasoning tokens included**. The documented maximum output is **128,000** tokens. Reasoning tokens bill as **output** tokens and occupy the context window. A budget sized only for the visible answer can truncate on a harder prompt, and it is the usual reason an invoice exceeds an estimate built from answer length. ### `reasoning_effort` — string, default `"medium"` How much the model thinks before answering. See [Reasoning effort](#reasoning-effort). ### `stream` — boolean, default `false` When `true`, tokens arrive as server-sent events terminated by `data: [DONE]`. Worth enabling on this tier in particular: at high effort the model can think for a long time before the first visible token, and a non-streamed request with a large budget can reach an HTTP timeout. ### `tools` / `tool_choice` — optional Function definitions and the selection strategy. Functions, web search, file search and computer use are all available on this family, and this generation adds programmatic tool calling. ### `response_format` — object, optional Constrains the answer's shape, including a JSON schema for machine-consumed output. ### `group` — string, default `"default"` Token group on the gateway. Leave it at `default` unless your account has been given another group to route through. *** ## Reasoning effort Six rungs, and unlike some families these do not collapse into one another — each is a distinct behaviour. The default is **`medium`**: OpenAI's docs state that "if you omit reasoning.effort, GPT-5.6 defaults to medium in both modes." | Effort | OpenAI's stated best-for | | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `none` | Latency-critical tasks that do not benefit from reasoning or multi-chained tool calls — voice, fast retrieval, classification | | `low` | Efficient reasoning with modest added latency: tool use, planning, search, multi-step decisions | | `medium` | **Default.** Quality and reliability where the task involves planning and judgement — agentic coding, research, spreadsheets and slides, delegated long-horizon work | | `high` | Hard reasoning, complex debugging, deep planning, high-value tasks where quality beats latency | | `xhigh` | Deep research and long asynchronous runs — security and code review, enterprise productivity. "Only use when your evals show a clear benefit" | | `max` | "Maximum reasoning for your most complex tasks. If you are currently using xhigh, evaluate if max results in stronger performance" | There is **no `minimal`** on this family. This is the tier the top of that ladder exists for. Starting at `high` and evaluating `xhigh` and `max` against your own cases is the usual approach; the `medium` default will under-use what you are paying for. OpenAI also documents a **Pro reasoning mode** for GPT-5.6 (`reasoning.mode`, independent of effort), and **multi-agent orchestration** in beta. Both are features of OpenAI's Responses API, so neither is part of a Chat Completions request through this endpoint. *** ## Image input | Modality | Supported | | -------- | :-------: | | Text in | ✅ | | Image in | ✅ | | Text out | ✅ | This generation accepts images **at their original dimensions**, with `original` or `auto` image detail — no resizing step required before a screenshot or scan goes in. Output is text only. *** ## Pricing dimensions Billing is **per token**, in USD, against your `api.reapi.ai` balance, with separate **input** and **output** rates. Three things to keep in mind: * **Reasoning tokens bill as output.** The default effort is `medium`, so a request that omits the field is paying for a reasoning pass. * **Effort is the first lever**, and on this family every rung is real — a middle setting buys a middle cost. * **The tier is the second lever.** All three GPT-5.6 tiers share this context window, this output ceiling, this effort ladder and this endpoint, so moving between them changes reasoning depth and price, not capability surface. Both token rates sit **20% below OpenAI's published per-token rate**, on input and output alike. Current numbers are on the [model page](https://reapi.ai/models/gpt-5-6-sol) and [api.reapi.ai/pricing](https://api.reapi.ai/pricing) — those tables are the canonical source, not this page. OpenAI prices cached input as a separate dimension. **reAPI does not publish a cached-input rate for this model**, so bill against the input and output rates in the pricing table. Chat models bill in USD on the gateway balance. They do **not** draw down the integer credits used by the media-generation endpoints on `reapi.ai/api/v1`. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1785000000, "model": "gpt-5.6-sol", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 1204, "completion_tokens": 860, "total_tokens": 2064 } } ``` `usage.completion_tokens` includes reasoning tokens, so it is the number to reconcile a bill against. On OpenAI's own Responses API the split is reported under `output_tokens_details.reasoning_tokens`. ### Streaming (`stream: true`) Server-sent events, each `data:` line carrying a `chat.completion.chunk` with the incremental text in `choices[0].delta.content`, terminated by `data: [DONE]`. *** ## Errors Failures use the gateway's standard envelope. See the [errors catalog](/docs/api/errors) for the full code list. Common cases: | Trigger | What to do | | ----------------------------------------- | ---------------------------------------------------------------------------------- | | Missing or invalid bearer token | Create a key in the api.reapi.ai console | | Unknown `model` value | Send `gpt-5.6-sol` with the dots — not the hyphenated slug | | `reasoning_effort` set to `minimal` | Not a value on this family — use `none`, `low`, `medium`, `high`, `xhigh` or `max` | | `reasoning.mode` or multi-agent fields | Responses-API features; not part of a Chat Completions request | | `max_completion_tokens` above the ceiling | Lower it; the documented maximum output is 128,000 | | Truncated answer on a hard prompt | The reasoning pass consumed the allowance — raise `max_completion_tokens` | | Insufficient balance | Top up on the gateway | | Upstream rate limit | Retry with backoff, or route through another tier | *** ## Tips * **Start at `high`, not the default.** The default is `medium`; if a route is on this tier it is usually because it needs more than that. * **Evaluate `max` only against `xhigh`.** OpenAI's own framing is to compare the two rather than jump straight to the top. * **Stream, and set a generous `max_completion_tokens`** so a deep pass has room to finish. * **Send the suffixed id in production.** `gpt-5.6` works, but it follows whatever OpenAI points the alias at later. * **Keep the routine turns on a cheaper tier.** Same key, same endpoint, one model string apart — escalation is a field, not an integration. * **Give it the whole system.** A 1.05M-token window is only useful if you actually put the repository, the tests and the history in it. *** ## Related * [GPT-5.6 Sol model page](https://reapi.ai/models/gpt-5-6-sol) — current rates * [GPT-5.6 Terra](/docs/gpt-5-6-terra) — the balanced tier below it * [GPT-5.6 Luna](/docs/gpt-5-6-luna) — the volume tier * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # gpt-5.6-terra (https://reapi.ai/docs/gpt-5-6-terra) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > OpenAI's GPT-5.6 Terra — the tier that balances intelligence and cost — exposed through api.reapi.ai as a drop-in > OpenAI-compatible Chat Completions endpoint. A **1,050,000-token** context > window, **128,000** max output tokens, six `reasoning_effort` rungs from > `none` to `max` defaulting to **`medium`**, text and image input, and > functions, web search, file search and computer use. OpenAI rates its reasoning **Higher** and its speed Fast. The wire > `model` id is **`gpt-5.6-terra`**. Current rates live on the > [model page](https://reapi.ai/models/gpt-5-6-terra) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). **The URL and the model id differ.** This page and the model page spell the slug `gpt-5-6-terra` because a URL cannot carry dots. The string your request body needs is `gpt-5.6-terra`. ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.6-terra", "messages": [ { "role": "user", "content": "Implement the change in the linked issue, with tests." } ], "reasoning_effort": "medium", "max_completion_tokens": 8192, "stream": true }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="gpt-5.6-terra", messages=[{"role": "user", "content": "Implement the change in the linked issue, with tests."}], reasoning_effort="medium", max_completion_tokens=8192, stream=True, ) for chunk in stream: delta = chunk.choices[0].delta.content if delta: print(delta, end="") ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "gpt-5.6-terra", messages: [{ role: "user", content: "Implement the change in the linked issue, with tests." }], reasoning_effort: "medium", max_completion_tokens: 8192, stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gpt-5.6-terra", "messages": []map[string]string{ {"role": "user", "content": "Implement the change in the linked issue, with tests."}, }, "reasoning_effort": "medium", "max_completion_tokens": 8192, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Chat models are served from the `api.reapi.ai` gateway, which has its own console and its own key. Create the key there, then send it as a bearer token: ```http Authorization: Bearer YOUR_API_KEY ``` The gateway key is **not** the same credential as a media-generation key used against `reapi.ai/api/v1`. Sign in at [api.reapi.ai](https://api.reapi.ai/) to create one. *** ## Endpoint ```http POST /v1/chat/completions ``` Base URL `https://api.reapi.ai`. The wire format is OpenAI-compatible, so the same SDKs work once you swap the base URL, the key and the model string. OpenAI states that its reasoning models "work better with the Responses API", and that "while the Chat Completions API is still supported, you'll get improved model intelligence and performance by using Responses." The GPT-5.6 release entry lists `v1/responses`, `v1/chat/completions` and `v1/batch` as this family's endpoints — so Chat Completions is a documented, supported surface, and this is a vendor preference rather than a restriction. *** ## Request body ### `model` — string, required Must be `gpt-5.6-terra` exactly. There is no alias for this tier — the bare `gpt-5.6` id routes to the frontier model instead. ### `messages` — array, required Conversation history, each entry an object with `role` and `content`. Roles are `system`, `user`, `assistant` and `tool`. Text and image parts are supported — see [Image input](#image-input). ### `max_completion_tokens` — integer Upper bound on generated tokens for this response, **reasoning tokens included**. The documented maximum output is **128,000** tokens. Reasoning tokens bill as **output** tokens and occupy the context window. A budget sized only for the visible answer can truncate on a harder prompt, and it is the usual reason an invoice exceeds an estimate built from answer length. ### `reasoning_effort` — string, default `"medium"` How much the model thinks before answering. See [Reasoning effort](#reasoning-effort). ### `stream` — boolean, default `false` When `true`, tokens arrive as server-sent events terminated by `data: [DONE]`. At the default effort the model thinks before it answers, so streaming is what keeps an interactive surface from looking stalled. ### `tools` / `tool_choice` — optional Function definitions and the selection strategy. Functions, web search, file search and computer use are all available on this family, and this generation adds programmatic tool calling. ### `response_format` — object, optional Constrains the answer's shape, including a JSON schema for machine-consumed output. ### `group` — string, default `"default"` Token group on the gateway. Leave it at `default` unless your account has been given another group to route through. *** ## Reasoning effort Six rungs, and unlike some families these do not collapse into one another — each is a distinct behaviour. The default is **`medium`**: OpenAI's docs state that "if you omit reasoning.effort, GPT-5.6 defaults to medium in both modes." | Effort | OpenAI's stated best-for | | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `none` | Latency-critical tasks that do not benefit from reasoning or multi-chained tool calls — voice, fast retrieval, classification | | `low` | Efficient reasoning with modest added latency: tool use, planning, search, multi-step decisions | | `medium` | **Default.** Quality and reliability where the task involves planning and judgement — agentic coding, research, spreadsheets and slides, delegated long-horizon work | | `high` | Hard reasoning, complex debugging, deep planning, high-value tasks where quality beats latency | | `xhigh` | Deep research and long asynchronous runs — security and code review, enterprise productivity. "Only use when your evals show a clear benefit" | | `max` | "Maximum reasoning for your most complex tasks. If you are currently using xhigh, evaluate if max results in stronger performance" | There is **no `minimal`** on this family. This tier is where the default is genuinely the right starting point. Sweep `low` for speed on planning-shaped work and `high` when a route needs complex debugging; if your evals keep choosing `xhigh` or `max`, that route belongs on the frontier tier instead. OpenAI also documents a **Pro reasoning mode** for GPT-5.6 (`reasoning.mode`, independent of effort), and **multi-agent orchestration** in beta. Both are features of OpenAI's Responses API, so neither is part of a Chat Completions request through this endpoint. *** ## Image input | Modality | Supported | | -------- | :-------: | | Text in | ✅ | | Image in | ✅ | | Text out | ✅ | This generation accepts images **at their original dimensions**, with `original` or `auto` image detail — no resizing step required before a screenshot or scan goes in. Output is text only. *** ## Pricing dimensions Billing is **per token**, in USD, against your `api.reapi.ai` balance, with separate **input** and **output** rates. Three things to keep in mind: * **Reasoning tokens bill as output.** The default effort is `medium`, so a request that omits the field is paying for a reasoning pass. * **Effort is the first lever**, and on this family every rung is real — a middle setting buys a middle cost. * **The tier is the second lever.** All three GPT-5.6 tiers share this context window, this output ceiling, this effort ladder and this endpoint, so moving between them changes reasoning depth and price, not capability surface. Both token rates sit **20% below OpenAI's published per-token rate**, on input and output alike. Current numbers are on the [model page](https://reapi.ai/models/gpt-5-6-terra) and [api.reapi.ai/pricing](https://api.reapi.ai/pricing) — those tables are the canonical source, not this page. OpenAI prices cached input as a separate dimension. **reAPI does not publish a cached-input rate for this model**, so bill against the input and output rates in the pricing table. Chat models bill in USD on the gateway balance. They do **not** draw down the integer credits used by the media-generation endpoints on `reapi.ai/api/v1`. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1785000000, "model": "gpt-5.6-terra", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 1204, "completion_tokens": 860, "total_tokens": 2064 } } ``` `usage.completion_tokens` includes reasoning tokens, so it is the number to reconcile a bill against. On OpenAI's own Responses API the split is reported under `output_tokens_details.reasoning_tokens`. ### Streaming (`stream: true`) Server-sent events, each `data:` line carrying a `chat.completion.chunk` with the incremental text in `choices[0].delta.content`, terminated by `data: [DONE]`. *** ## Errors Failures use the gateway's standard envelope. See the [errors catalog](/docs/api/errors) for the full code list. Common cases: | Trigger | What to do | | ----------------------------------------- | ---------------------------------------------------------------------------------- | | Missing or invalid bearer token | Create a key in the api.reapi.ai console | | Unknown `model` value | Send `gpt-5.6-terra` with the dots — not the hyphenated slug | | `reasoning_effort` set to `minimal` | Not a value on this family — use `none`, `low`, `medium`, `high`, `xhigh` or `max` | | `reasoning.mode` or multi-agent fields | Responses-API features; not part of a Chat Completions request | | `max_completion_tokens` above the ceiling | Lower it; the documented maximum output is 128,000 | | Truncated answer on a hard prompt | The reasoning pass consumed the allowance — raise `max_completion_tokens` | | Insufficient balance | Top up on the gateway | | Upstream rate limit | Retry with backoff, or route through another tier | *** ## Tips * **Leave the default alone first.** `medium` is what OpenAI calls the well-balanced point, and this tier is priced for it. * **Then sweep in both directions** on a real route — `low` for speed, `high` for hard debugging — and keep whichever your evals prefer. * **Escalate on evidence, not instinct.** A route that always wants `xhigh` or `max` is telling you it belongs one tier up. * **Use a JSON schema for agent steps** whose output another step consumes. * **Budget for the reasoning pass** in `max_completion_tokens`, not just the answer. * **The window is the frontier tier's.** Choosing this tier does not shrink what the model can see. *** ## Related * [GPT-5.6 Terra model page](https://reapi.ai/models/gpt-5-6-terra) — current rates * [GPT-5.6 Sol](/docs/gpt-5-6-sol) — the frontier tier above it * [GPT-5.6 Luna](/docs/gpt-5-6-luna) — the volume tier below it * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # gpt-image-2-official (https://reapi.ai/docs/gpt-image-2-stable) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > The **stable channel** of GPT Image 2 on reAPI — async > `/api/v1/images/generations` with the full feature surface: quality tiers > (`auto` / `low` / `medium` / `high`), batches up to 4 images, > mask-based inpainting, and background control. The channel always > returns PNG. See current pricing on the > [model page](https://reapi.ai/models/gpt-image-2). **Wire id is `gpt-image-2-official`.** The doc / pricing page / playground all label this variant as **"Stable"** for clarity, but the request body must set `"model": "gpt-image-2-official"`. The shorter `gpt-image-2` is a separate variant — see [Differences from `gpt-image-2`](#differences-from-gpt-image-2). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2-official", "prompt": "ancient castle beneath a starry sky", "size": "16:9", "resolution": "2k", "quality": "high", "n": 1 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "gpt-image-2-official", "prompt": "ancient castle beneath a starry sky", "size": "16:9", "resolution": "2k", "quality": "high", "n": 1, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "gpt-image-2-official", prompt: "ancient castle beneath a starry sky", size: "16:9", resolution: "2k", quality: "high", n: 1, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gpt-image-2-official", "prompt": "ancient castle beneath a starry sky", "size": "16:9", "resolution": "2k", "quality": "high", "n": 1, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gpt-image-2-official", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.image_urls` holds the generated image URLs (length = `n`), valid for 7 days. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/images/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required `string`. Must be `"gpt-image-2-official"`. ### `prompt` — required `string`, **1–4,000 characters**. English and Chinese both supported. Detailed prompts produce better results. Every prompt goes through pre-submission moderation; rejected prompts return `400` at no charge. Don't restate the ratio in the prompt — pass it via `size`. Repeating it confuses the upstream. **Failure modes.** * Missing / empty → `400 prompt is required` (code `20002`). * Longer than 4,000 chars → `400 prompt must be at most 4000 characters` (code `20007`). ### `size` — string, default `"1:1"` Output ratio. One of these 14 values (or `auto` to let the upstream pick from the prompt / first reference image): ``` auto 1:1 16:9 9:16 4:3 3:4 3:2 2:3 5:4 4:5 2:1 1:2 21:9 9:21 ``` This channel additionally accepts a pixel string `WIDTHxHEIGHT` (e.g. `1024x1024`, `3840x2160`); the upstream snaps it to the closest supported dimension. Anything outside the list and not a pixel string is rejected with `400`. When `size` is omitted: * **T2I** (no `image_urls`) → defaults to `"1:1"`. * **I2I** (`image_urls` set) → output mirrors the first reference image's ratio (upstream-side derivation; gateway omits the field). #### 4K constraint `resolution: "4k"` is only valid with the six widescreen sizes below. Other ratios — including `auto` — exceed the model's total-pixel cap and are rejected with `400`. **`size` is required** when `resolution: "4k"`; sending 4K with no `size` is rejected before the request leaves the gateway. | `size` | `1k` | `2k` | `4k` | | --------------- | ------------ | ------------ | ------------- | | `1:1` | 1024×1024 | 2048×2048 | ❌ | | `3:2` / `2:3` | 1536×1024 | 2048×1360 | ❌ | | `4:3` / `3:4` | 1024×768 | 2048×1536 | ❌ | | `5:4` / `4:5` | 1280×1024 | 2560×2048 | ❌ | | `16:9` / `9:16` | 1536×864 | 2048×1152 | **3840×2160** | | `2:1` / `1:2` | 2048×1024 | 2688×1344 | **3840×1920** | | `21:9` / `9:21` | 2016×864 | 2688×1152 | **3840×1648** | | `auto` | server picks | server picks | ❌ | > `3:2` / `2:3` at 2K resolves to 2048×1360 — 1360 is the nearest > 16-aligned approximation of 3:2 (under 0.5% off). Other cells are > exact. **4K is widescreen-only.** `resolution: "4k"` requires `size` to be one of `16:9`, `9:16`, `2:1`, `1:2`, `21:9`, or `9:21`. Sending 4K with `auto`, a non-widescreen ratio, or no size returns `400 4K requires an explicit size in {16:9, 9:16, 2:1, 1:2, 21:9, 9:21}` (code `20003`). See the 4K table under `size` above for the full grid. ### `resolution` — string, default `"1k"` `1k` / `2k` / `4k`. Case-insensitive — `"2K"` and `"2k"` are equivalent. Drives pricing. ### `quality` — string, default `"auto"` `auto` / `low` / `medium` / `high`. Higher tiers are slower and price separately. **`auto` bills at the `high` rate.** The upstream does not honor a lower-tier hint when `auto` is set — the request runs at `high` internally. reAPI mirrors that on billing: `auto` (and any request that omits `quality`) is charged at the `high` rate. To pay the `low` or `medium` rate, set `quality` explicitly. ### `n` — integer, default `1` Number of images per request. Range `1`–`4`. Each generated image is billed individually — a 4-image batch costs **4×** the per-image rate. `output.image_urls` length matches `n`. ### `image_urls` — string\[] Reference images for image-to-image. Up to **16** entries. Triggers I2I when set. Public HTTP(S) URLs only. **No `data:` URIs.** reAPI rejects base64 inputs platform-wide. Upload to your own object storage (S3 / R2 / OSS) and pass the URL. ### `mask_url` — string PNG mask URL for inpainting. **Requires `image_urls` with at least one entry.** The mask must: * carry an alpha channel where the model should paint, and * share dimensions with the **first** entry in `image_urls`. Public HTTP(S) URL only. Mismatched dimensions or a fully opaque mask return `400` from upstream. ### `background` — string, default `"auto"` `auto` / `opaque` / `transparent`. **`transparent` is silently downgraded.** `gpt-image-2-official` does not produce transparent output even when explicitly requested. Pre- or post-process client-side if you need transparency. ### `moderation` — string, default `"auto"` `auto` / `low`. `low` is more lenient — useful when prompts that should pass are getting rejected. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gpt-image-2-official", "status": "completed", "created_at": 1735000000, "output": { "image_urls": [ "https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png", "https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/1.png" ] }, "error": null } ``` | Field | Type | Notes | | ------------------- | -------------- | ----------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion | | `output.image_urls` | string\[] | Generated image URLs — length = `n`, valid for 7 days | | `error` | object \| null | Populated on `failed` — `{ code, message }` | ### Upstream errors (502 / 503) reAPI does not surface raw upstream `5xx` codes to the caller. When the upstream provider returns `502 Bad Gateway`, `503 Service Unavailable`, or a connection failure, the worker retries up to 5 attempts with exponential backoff (\~30s total budget). If all retries fail, the task ends with one of these reAPI-specific codes (returned via `GET /api/v1/tasks/{id}` as `error.code`): | reAPI code | Meaning | Origin | | ---------- | -------------------------- | ------------------------------------ | | `80001` | `provider_submit_failed` | Upstream `5xx` / network on submit | | `80002` | `provider_polling_timeout` | Wall-clock cap reached while polling | | `80003` | `provider_failed` | Upstream returned a terminal failure | See [Errors catalog](/docs/api/errors) for the full code list. *** ## Validation errors All cases below return HTTP 400 with the noted code. Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed values) and are not a stable contract. | Trigger | Code | Message | | ----------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ | | `prompt` missing / empty | `20002` | `prompt is required` | | `prompt` longer than 4,000 chars | `20007` | `prompt must be at most 4000 characters` | | Unknown `size` value | `20003` | `invalid size "..." (allowed: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 5:4, 4:5, 2:1, 1:2, 21:9, 9:21, auto, or WxH pixels)` | | Unknown `resolution` value | `20003` | `invalid resolution "..." (allowed: 1k, 2k, 4k)` | | `4k` with non-widescreen / `auto` / no `size` | `20003` | `4K requires an explicit size in {16:9, 9:16, 2:1, 1:2, 21:9, 9:21}` | | `n` outside `1`–`4` | `20003` | `n must be between 1 and 4` | | `image_urls` > 16 | `20003` | `image_urls accepts at most 16 entries` | | `mask_url` without `image_urls` | `20003` | `mask_url requires at least one entry in image_urls` | | Any URL field carrying a `data:` URI | `20003` | `image URL must be a public http(s) URL — data: URIs are rejected` (or `mask_url must be a public URL …`) | | Unknown `quality` / `background` / `moderation` | `20003` | `invalid "..." (allowed: …)` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation. *** ## Recipes ### Text-to-image — minimal ```json { "model": "gpt-image-2-official", "prompt": "ancient castle beneath a starry sky" } ``` ### 2K poster ```json { "model": "gpt-image-2-official", "prompt": "cyberpunk night cityscape", "size": "16:9", "resolution": "2k", "quality": "high" } ``` ### 4K wallpaper ```json { "model": "gpt-image-2-official", "prompt": "panoramic snow-capped mountains at sunrise", "size": "16:9", "resolution": "4k", "quality": "high" } ``` ### Multi-reference fusion (image-to-image) ```json { "model": "gpt-image-2-official", "prompt": "blend the two references into one cohesive illustrated poster", "size": "1:1", "quality": "high", "image_urls": [ "https://your-cdn.com/input-a.png", "https://your-cdn.com/input-b.png" ] } ``` ### Mask-based inpainting The mask must match the dimensions of the first `image_urls` entry and carry an alpha channel where the model should paint. ```json { "model": "gpt-image-2-official", "prompt": "replace the background with a desert sunset", "size": "1:1", "quality": "medium", "image_urls": ["https://your-cdn.com/photo.png"], "mask_url": "https://your-cdn.com/mask.png" } ``` ### Batch of 4 variations ```json { "model": "gpt-image-2-official", "prompt": "four minimalist poster variations of a red fox", "size": "1:1", "quality": "low", "n": 4 } ``` ### Lenient moderation ```json { "model": "gpt-image-2-official", "prompt": "moody noir portrait, dramatic lighting", "size": "4:5", "resolution": "2k", "quality": "high", "moderation": "low" } ``` *** ## Polling pattern Latency depends heavily on `quality` and `resolution`: | `quality` × `resolution` | Typical end-to-end | | ------------------------ | ------------------ | | `low` × `1k` | 20 – 40 s | | `medium` × `1k` | 30 – 60 s | | `high` × `2k` | 60 – 120 s | | `high` × `4k` | 120 – 180 s | Recommended cadence: ``` 0–30s: wait before the first poll 30s–3m: poll every 3–5s 3m+: back off to 10s; cap at 30s ``` Set client-side request timeouts to **≥ 180 seconds** when using `quality: "high"` with `2k` / `4k`. The worker's wall-clock cap is **1 hour** (image tasks), comfortably above any realistic queue. *** ## Pricing Per-image rates depend on three axes: * **Resolution** (`1k` / `2k` / `4k`) * **Quality** (`low` / `medium` / `high` — `auto` bills at `high`) * **`size`** (the `2k` / `4k` cells charge slightly more for the widest ratios; live numbers on the [model page](https://reapi.ai/models/gpt-image-2#pricing) are authoritative) When `size` is `"auto"`, reAPI prices against the **most expensive ratio** at the resolved `(resolution, quality)` cell so the bill never undershoots once the upstream picks a ratio at runtime. The forwarded body keeps `auto` — the override is billing-only. **Bill formula** (1 credit = $0.001): ``` credits = ceil(per_image_usd × n × 1000) ``` Charged on submit; refunded automatically on `failed` / `provider_submit_failed` / `provider_polling_timeout`. Moderated prompts return `400` before charging — no balance impact. **Worked example.** `n: 2`, `resolution: "2k"`, `quality: "high"`, `size: "16:9"` charges **2× the 16:9\@2k\_high cell**. Rates evolve; check the [model page](https://reapi.ai/models/gpt-image-2#pricing) for live numbers. *** ## Tips * **Specify ratio in `size`, not in the prompt.** Repeating "16:9 wide shot" inside the prompt confuses the upstream. Use `size` for shape and the prompt for content / style. * **Set `quality` explicitly to save money.** `auto` runs at `high` — if `medium` is good enough, send `"medium"` and pay the medium rate. * **Batches are linear cost.** `n: 4` is exactly 4× the price of `n: 1` at the same parameters — no batch discount, but no batch surcharge either. * **Mask alpha matters.** The mask's transparent regions are where the model paints; opaque regions are preserved. A fully opaque mask returns `400` from upstream. * **Pre-cache reference images.** The upstream fetches each `image_urls` entry once per submit; if your CDN is slow, latency shows up as polling time, not as billing. *** ## Differences from `gpt-image-2` | Feature | [`gpt-image-2`](/docs/gpt-image-2) | `gpt-image-2-official` (this page) | | ------------------------------------- | :--------------------------------: | :--------------------------------------------------------------------------------------------: | | Endpoint | `/api/v1/images/generations` | `/api/v1/images/generations` | | Async / task model | ✅ | ✅ | | `size` enum (14) | ✅ | ✅ | | Resolution tiers (`1k` / `2k` / `4k`) | ✅ | ✅ | | Image-to-image (`image_urls`) | ✅ | ✅ | | Pricing | flat per resolution | varies by resolution × quality × ratio — see [model page](https://reapi.ai/models/gpt-image-2) | | Batch (`n` > 1) | ❌ | ✅ up to 4 | | Quality tiers | ❌ | ✅ `auto` / `low` / `medium` / `high` | | Mask inpainting (`mask_url`) | ❌ | ✅ | | Background control | ❌ | ✅ (`transparent` silently downgraded) | | Moderation knob | ❌ (default) | ✅ `auto` / `low` | *** ## Related * [`gpt-image-2`](/docs/gpt-image-2) — cheaper variant, single image, flat per-resolution pricing * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Pricing — gpt-image-2](https://reapi.ai/models/gpt-image-2#pricing) --- # gpt-image-2 (https://reapi.ai/docs/gpt-image-2) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Async image generation through reAPI's cheap channel. One endpoint > covers text-to-image and image-to-image. Flat per-resolution > pricing — the cheapest variant in the family. For batches, masks, > quality tiers, or transparent backgrounds, switch to > [`gpt-image-2 stable`](/docs/gpt-image-2-stable). * Async processing — `POST` returns a `task_id`, poll `GET /api/v1/tasks/{id}` for the result. * standard `/api/v1/images/generations` envelope (text-to-image / image-to-image). * 14 ratios via `size`; three resolution tiers (`1k` / `2k` / `4k`) via `resolution`. * Up to 16 reference images via `image_urls` — public HTTP(S) URLs only. * Single image per request — `n` is fixed at 1. * Flat per-resolution price; failed / moderated requests are not charged. *** ## Try it *** ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2", "prompt": "a ginger cat on a windowsill at sunset, watercolor", "size": "16:9", "resolution": "2k" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "gpt-image-2", "prompt": "a ginger cat on a windowsill at sunset, watercolor", "size": "16:9", "resolution": "2k", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "gpt-image-2", prompt: "a ginger cat on a windowsill at sunset, watercolor", size: "16:9", resolution: "2k", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "gpt-image-2", "prompt": "a ginger cat on a windowsill at sunset, watercolor", "size": "16:9", "resolution": "2k", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gpt-image-2", "status": "processing", "created_at": 1735000000 } ``` Hold onto `id` and poll `GET /api/v1/tasks/{id}` until completion. *** ## Endpoint ```http POST /api/v1/images/generations # submit a job GET /api/v1/tasks/{id} # poll for the result ``` Async — submit returns a `task_id` immediately; the actual image arrives via the polling endpoint. Polling is free. *** ## Authentication Bearer token, minted at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer rk_live_xxx ``` *** ## Body ### `model` `string` · **required** · default `"gpt-image-2"` Must be `"gpt-image-2"`. ### `prompt` `string` · **required** 1 – 4000 characters. English and Chinese both supported. Detailed prompts produce better results. Every prompt goes through pre-submission moderation; rejected prompts return `400` at no charge. Don't restate the ratio in the prompt — pass it via `size`. Repeating it in the prompt confuses the upstream. ### `size` `string` · default `"1:1"` (text-to-image) / inherited (image-to-image) Output ratio. One of these 14 values: ``` auto 1:1 16:9 9:16 4:3 3:4 3:2 2:3 5:4 4:5 2:1 1:2 21:9 9:21 ``` `auto` lets the upstream pick from the prompt or first reference image. Pixel strings (e.g. `1024x1024`) are not accepted — combine `size` with `resolution` to control output pixels. Anything outside the list is rejected with `400`. When `image_urls` is provided **without** `size`, the output inherits the first reference image's resolution (image-to-image mode). Pass `size` to force a specific ratio. ### `resolution` `string` · default `"1k"` `1k` / `2k` / `4k`. Case-insensitive — `"2K"` and `"2k"` are equivalent. `4k` is only valid with the six widescreen sizes below. Other sizes — including `auto` — exceed the model's total-pixel cap and are rejected with `400`. | `size` | `1k` | `2k` | `4k` | | --------------- | ------------ | ------------ | ------------- | | `1:1` | 1024×1024 | 2048×2048 | ❌ | | `3:2` / `2:3` | 1536×1024 | 2048×1360 | ❌ | | `4:3` / `3:4` | 1024×768 | 2048×1536 | ❌ | | `5:4` / `4:5` | 1280×1024 | 2560×2048 | ❌ | | `16:9` / `9:16` | 1536×864 | 2048×1152 | **3840×2160** | | `2:1` / `1:2` | 2048×1024 | 2688×1344 | **3840×1920** | | `21:9` / `9:21` | 2016×864 | 2688×1152 | **3840×1648** | | `auto` | server picks | server picks | ❌ | ### `n` `integer` · default `1` · **must be `1`** Single image per request. This variant produces one image per call; sending any other value returns `400`. For batches up to 4, use [`gpt-image-2 stable`](/docs/gpt-image-2-stable). ### `image_urls` `string[]` · optional Reference images for image-to-image. Up to **16** entries. Each entry must be a public HTTP(S) URL — `data:` / base64 payloads are rejected. Upload to your own object storage (S3 / R2 / OSS) and pass the URL. **No batch / quality / mask on this variant.** Sending `n > 1`, `quality`, `mask_url`, `background`, `moderation`, `output_format`, or `output_compression` against `gpt-image-2` returns `400`. Switch to [`gpt-image-2 stable`](/docs/gpt-image-2-stable) — set `"model": "gpt-image-2-official"` — when you need those features. *** ## Use cases ### 1. Text-to-image (minimal) ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gpt-image-2", "prompt": "a ginger cat on a windowsill at sunset, watercolor" }' ``` ### 2. Text-to-image at 2K widescreen ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gpt-image-2", "prompt": "a corgi astronaut on the moon, cinematic", "size": "16:9", "resolution": "2k" }' ``` ### 3. Text-to-image at 4K ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gpt-image-2", "prompt": "ancient castle beneath a starry sky", "size": "16:9", "resolution": "4k" }' ``` ### 4. Image-to-image (single reference) ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gpt-image-2", "prompt": "turn this photo into a watercolor painting", "image_urls": ["https://your-cdn.com/photo.jpg"] }' ``` ### 5. Multi-reference fusion ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gpt-image-2", "prompt": "blend these two photos into a poster", "size": "4:3", "resolution": "2k", "image_urls": [ "https://your-cdn.com/photo-a.jpg", "https://your-cdn.com/photo-b.jpg" ] }' ``` ### 6. Force a ratio for image-to-image When the reference is portrait but you need a landscape output: ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -d '{ "model": "gpt-image-2", "prompt": "extend the scene horizontally into a moonlit forest", "size": "21:9", "resolution": "2k", "image_urls": ["https://your-cdn.com/portrait.jpg"] }' ``` *** ## Response `POST` returns immediately with `status: "processing"`; poll `GET /api/v1/tasks/{id}` until `status` is `completed` or `failed`. Both responses share the same envelope — the `output` field is `null` until the task finishes. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gpt-image-2", "status": "processing", "created_at": 1735000000 } ``` ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gpt-image-2", "status": "completed", "created_at": 1735000000, "output": { "image_urls": [ "https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png" ] }, "error": null } ``` URLs are stable for **7 days**. Download to your own storage if you need them longer. ```json { "error": { "code": 20003, "message": "gpt-image-2: field 'quality' is only supported on gpt-image-2-official", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 10003, "message": "API key invalid", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 30001, "message": "Insufficient credits", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 50001, "message": "Rate limit exceeded", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ```json { "error": { "code": 60099, "message": "Internal error — please retry", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` ### Upstream errors (502 / 503) reAPI does not surface raw upstream `5xx` codes to the caller. When the upstream provider returns `502 Bad Gateway`, `503 Service Unavailable`, or a connection failure, the worker retries up to 5 attempts with exponential backoff (\~30s total budget). If all retries fail, the task ends with one of these reapi-specific error codes (returned via `GET /api/v1/tasks/{id}` as `error.code`): | reapi code | Meaning | Origin | | ---------- | -------------------------- | ------------------------------------ | | `80001` | `provider_submit_failed` | Upstream `5xx` / network on submit | | `80002` | `provider_polling_timeout` | Wall-clock cap reached while polling | | `80003` | `provider_failed` | Upstream returned a terminal failure | See [Errors catalog](/docs/api/errors) for the full code list. *** ## Polling | `status` | Meaning | | ------------ | -------------------------------- | | `processing` | Submitted, still generating | | `completed` | `output.image_urls` is ready | | `failed` | See `error.message`; not charged | Recommended cadence: ``` 0–30s: wait before the first poll 30s–3m: poll every 3–5s 3m+: back off to 10s; cap at 30s ``` A 1K image typically completes in 30–60s; 2K adds \~30s; 4K can take 90–120s. *** ## Differences from the stable channel | Feature | `gpt-image-2` (this page) | [`gpt-image-2 stable`](/docs/gpt-image-2-stable) | | ------------------------------- | :--------------------------: | :--------------------------------------------------------------------------: | | Endpoint | `/api/v1/images/generations` | `/api/v1/images/generations` | | `size` enum (14) | ✅ | ✅ | | Resolution tiers (1k / 2k / 4k) | ✅ | ✅ | | Image-to-image (`image_urls`) | ✅ | ✅ | | Pricing | flat per resolution | varies by parameters — see [model page](https://reapi.ai/models/gpt-image-2) | | Batch (`n` > 1) | ❌ | ✅ up to 4 | | Quality tiers | ❌ | ✅ `auto` / `low` / `medium` / `high` | | Mask inpainting (`mask_url`) | ❌ | ✅ | | Background control | ❌ | ✅ (`transparent` is silently downgraded by upstream) | | Output format / compression | ❌ (always PNG) | ✅ `png` / `jpeg` / `webp` + compression | | Moderation knob | ❌ (default) | ✅ `auto` / `low` | *** ## Related * [`gpt-image-2 stable`](/docs/gpt-image-2-stable) — full feature surface (batch, mask, quality tiers). * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Pricing — gpt-image-2](https://reapi.ai/models/gpt-image-2#pricing) --- # grok-imagine-1.0-video (https://reapi.ai/docs/grok-imagine-1-0-video) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Grok Imagine 1.0 Video — async video generation. **One model id** > (`grok-imagine-1.0-video`) covers both **text-to-video** and > **image-to-video**. Mode is implicit: zero `image_urls` runs T2V; 1 to 7 > reference images run I2V. 6 to 30 second outputs at 480p / 720p, five > aspect ratios. See current pricing on the > [model page](https://reapi.ai/models/grok-imagine-1-0-video). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "grok-imagine-1.0-video", "prompt": "A dog running on a sunlit beach, slow-motion", "size": "16:9", "duration": 6, "quality": "720p" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "grok-imagine-1.0-video", "prompt": "A dog running on a sunlit beach, slow-motion", "size": "16:9", "duration": 6, "quality": "720p", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "grok-imagine-1.0-video", prompt: "A dog running on a sunlit beach, slow-motion", size: "16:9", duration: 6, quality: "720p", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "grok-imagine-1.0-video", "prompt": "A dog running on a sunlit beach, slow-motion", "size": "16:9", "duration": 6, "quality": "720p", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "grok-imagine-1.0-video", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URL, valid for 7 days. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Mode routing `grok-imagine-1.0-video` picks its mode from the **count of `image_urls`** you send — there is no `mode` parameter: | `image_urls` count | Mode | What it does | | ------------------ | ------- | ---------------------------------------------------------------- | | `0` (or omitted) | **T2V** | Generate from text. `size` controls output ratio. | | `1` – `7` | **I2V** | Use the references as visual guidance. Output ratio follows ref. | **Mutex rules.** * In T2V (no `image_urls`), `prompt` is **required**. * When `image_urls` is set (1 to 7 entries), `size` is forwarded but ignored upstream — the source frame's ratio decides the output ratio. * More than 7 `image_urls` is rejected with `400 image_urls accepts at most 7 entries`. *** ## Request body ### `model` — required `string`. Must be `"grok-imagine-1.0-video"`. ### `prompt` — string, conditional Up to **4,000 characters**. Required in T2V (when `image_urls` is empty); optional in I2V when at least one image is provided. Empty / whitespace-only prompts are treated as missing. **Failure modes.** * Empty / missing in T2V → `400 prompt is required when image_urls is empty (text-to-video)` (code `20002`). * Longer than 4,000 chars → `400 prompt exceeds 4000 characters (got N)` (code `20007`). ### `size` — string, default `"16:9"` Output aspect ratio in T2V mode. One of: | Value | Shape | | ------ | ------------------- | | `16:9` | Landscape (default) | | `9:16` | Portrait | | `1:1` | Square | | `3:2` | Landscape | | `2:3` | Portrait | In I2V mode the upstream derives the ratio from the reference image, so this field is ignored. ### `duration` — integer, default `6` Output length in seconds. Any integer in `[6, 30]`. Out-of-range → `400`. Drives pricing linearly: `ceil(per_second_usd × duration × 1000)` credits (1 credit = $0.001). **Send a number, not a string.** `"duration": "6"` is rejected with `400`. ### `quality` — string, default `"480p"` `480p` (SD) or `720p` (HD). Lowercase is canonical. Quality does **not** change the per-second rate. ### `image_urls` — string\[] Array of public HTTP(S) URLs. **0 to 7 entries**: * **0 entries** — pure text-to-video. * **1 to 7 entries** — image-to-video; references guide subject and style. **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — every URL field on this endpoint must be a public HTTP(S) URL. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "grok-imagine-1.0-video", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | `output.video_urls` URLs are valid for **7 days**. Re-host to your own storage if you need them longer. *** ## Validation errors All cases below return HTTP 400 with code `20003` unless noted. Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed values, etc.) and are not a stable contract. | Trigger | Code | Message (illustrative) | | -------------------------------------------------- | ------- | --------------------------------------------------------------------------- | | `prompt` missing in T2V | `20002` | `grok-imagine: prompt is required when image_urls is empty (text-to-video)` | | `prompt` longer than 4,000 chars | `20007` | `grok-imagine: prompt exceeds 4000 characters (got N)` | | `image_urls` length > 7 | `20003` | `grok-imagine: image_urls accepts at most 7 entries, got N` | | `duration` outside `[6, 30]` | `20003` | `grok-imagine: duration must be 6-30 seconds, got N` | | Unknown `size` | `20003` | `grok-imagine: invalid size "X" (allowed: 16:9 / 9:16 / 1:1 / 3:2 / 2:3)` | | Unknown `quality` | `20003` | `grok-imagine: invalid quality "X" (allowed: 480p / 720p)` | | `image_urls` carrying a `data:` URI or non-http(s) | `20003` | `grok-imagine: image_urls entries must be public http(s) URLs` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### T2V — minimum request ```json { "model": "grok-imagine-1.0-video", "prompt": "A little girl walking down a sunset coastal road" } ``` ### T2V — full parameters ```json { "model": "grok-imagine-1.0-video", "prompt": "A dog running on a sunlit beach, slow-motion, cinematic warm tones", "size": "16:9", "duration": 10, "quality": "720p" } ``` ### I2V — animate from references ```json { "model": "grok-imagine-1.0-video", "prompt": "Bring the scene to life with a gentle camera dolly forward", "image_urls": ["https://your-cdn.com/reference.jpg"], "duration": 8, "quality": "720p" } ``` ### I2V — multi-reference ```json { "model": "grok-imagine-1.0-video", "prompt": "Smooth cinematic motion across the reference subjects", "image_urls": [ "https://your-cdn.com/ref-1.jpg", "https://your-cdn.com/ref-2.jpg", "https://your-cdn.com/ref-3.jpg" ], "duration": 12 } ``` *** ## Polling pattern The task endpoint behaves identically to other video tasks — the only difference is the completed `output` shape (`video_urls` instead of `image_urls`). A pragmatic schedule: ``` 0–5 minutes: poll every 5s 5 min – 1 h: back off gradually toward 1 min ≥ 1 h: cap at 3 min between polls ``` A typical task completes in a few minutes. The worker's wall-clock cap is **48 hours**, comfortably above any realistic queue. *** ## Pricing Per-second rate. `quality` does **not** change the price, and the rate is flat across `480p` and `720p`. See current rate on the [Grok Imagine model page](https://reapi.ai/models/grok-imagine-1-0-video). **Bill formula** (1 credit = $0.001): ``` credits = ceil(per_second_usd × duration × 1000) ``` Failed jobs refund automatically. *** ## Tips * **Prompt motion, not just scene.** "Slow push-in, warm tones, shallow depth of field" outperforms a pure noun-list of what's on screen. * **Sweet-spot duration: 6–10 seconds.** Above 10s the upstream wall-time grows fast; the per-second price stays the same either way. * **Reference-image quality matters.** Subject centered, clear composition, no heavy filters — I2V output quality tracks input quality directly. * **Send up to 7 references for richer guidance.** A first frame plus several style boards usually outperforms a single reference. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # grok-imagine-video-1.5-official (https://reapi.ai/docs/grok-imagine-video-1-5-official) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Grok Imagine Video 1.5 **Official Channel** — async **image-to-video** > with **native synchronized audio**, distinct from the > [`grok-imagine-video-1.5-beta`](/docs/grok-imagine-video-1-5) channel. > Same one-reference-image workflow at a **lower per-second rate**, with a > slightly stricter input contract: the prompt is required and clips run > 6 to 15 seconds. Model id `grok-imagine-video-1.5-official`. See current > pricing on the > [model page](https://reapi.ai/models/grok-imagine-video-1-5). **Channel differences at a glance.** Compared to the beta channel this surface requires a `prompt`, narrows `aspect_ratio` to `1:1` / `16:9` / `9:16` (no `auto`), starts at 6-second clips, adds an `audio` toggle, and has no `nsfw_checker` parameter. The two channels bill independently — each has its own per-second rate. ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "grok-imagine-video-1.5-official", "prompt": "Gentle cinematic push-in, golden-hour light, subtle motion", "image_urls": ["https://your-cdn.com/source.jpg"], "aspect_ratio": "16:9", "resolution": "720p", "duration": 8 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "grok-imagine-video-1.5-official", "prompt": "Gentle cinematic push-in, golden-hour light, subtle motion", "image_urls": ["https://your-cdn.com/source.jpg"], "aspect_ratio": "16:9", "resolution": "720p", "duration": 8, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "grok-imagine-video-1.5-official", prompt: "Gentle cinematic push-in, golden-hour light, subtle motion", image_urls: ["https://your-cdn.com/source.jpg"], aspect_ratio: "16:9", resolution: "720p", duration: 8, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "grok-imagine-video-1.5-official", "prompt": "Gentle cinematic push-in, golden-hour light, subtle motion", "image_urls": []string{"https://your-cdn.com/source.jpg"}, "aspect_ratio": "16:9", "resolution": "720p", "duration": 8, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "grok-imagine-video-1.5-official", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URL (with audio), valid for 7 days. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. This is an **image-to-video** model — exactly one reference image is required on every request. There is no text-to-video mode, no last-frame or reference image input, and no `mode` parameter. *** ## Request body ### `model` — required `string`. Must be `"grok-imagine-video-1.5-official"`. ### `prompt` — string, required Describes the motion, camera, atmosphere, and any dialogue or sound you want in the generated audio. **Required on this channel** (the beta channel accepts image-only requests; this one does not). Maximum **4000 characters**; whitespace-only prompts and prompts over 4000 characters are rejected with `400`. ### `image_urls` — string\[], required Array with **exactly one** public HTTP(S) image URL — the first frame the model animates. Accepted source formats: JPEG, PNG, WebP. **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — the image URL must be a public HTTP(S) link. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. More than one entry is rejected. ### `aspect_ratio` — string, default `"16:9"` Output framing. `auto` is **not** available on this channel. Output pixel size follows the ratio × resolution matrix: | Value | 480p | 720p | | ------ | ------- | -------- | | `1:1` | 544×544 | 960×960 | | `16:9` | 736×400 | 1280×720 | | `9:16` | 400×736 | 720×1280 | ### `resolution` — string, default `"480p"` `480p` or `720p`. `720p` costs 2× per second — see Pricing. ### `duration` — integer, default `8` Output length in seconds. Any integer in `[6, 15]` — note the 6-second minimum (the beta channel starts at 1). Out-of-range → `400`. Drives pricing linearly. **Send a number, not a string.** `"duration": "8"` is rejected with `400`. ### `audio` — boolean, default `true` Whether the generated clip carries a native synchronized audio track. Set `false` for a silent video at the same per-second rate. Each request produces exactly **one** video. For multiple takes, submit concurrent requests — each bills and refunds independently. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "grok-imagine-video-1.5-official", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | `output.video_urls` URLs are valid for **7 days** — re-host to your own storage if you need them longer. *** ## Validation errors Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed values) and are not a stable contract. | Trigger | Code | Message (illustrative) | | -------------------------------------------------- | ------- | ------------------------------------------------ | | `prompt` missing, empty, or whitespace-only | `20002` | `prompt is required` | | `prompt` longer than 4000 characters | `20003` | `prompt must be at most 4000 characters` | | `image_urls` missing | `20002` | `image_urls is required` | | `image_urls` with more than one entry | `20003` | `image_urls allows at most 1 entry` | | `duration` outside `[6, 15]` | `20003` | `duration must be 6-15 seconds` | | Unknown `resolution` | `20003` | `invalid resolution (allowed: 480p / 720p)` | | `aspect_ratio` outside `1:1` / `16:9` / `9:16` | `20003` | `invalid aspect_ratio` | | `image_urls` carrying a `data:` URI or non-http(s) | `20003` | `image_urls entries must be public http(s) URLs` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see the [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### Minimum request ```json { "model": "grok-imagine-video-1.5-official", "prompt": "Slow push-in with ambient room tone", "image_urls": ["https://your-cdn.com/source.jpg"] } ``` ### Directed motion + HD ```json { "model": "grok-imagine-video-1.5-official", "prompt": "Slow dolly forward, wind moving the hair, warm cinematic light", "image_urls": ["https://your-cdn.com/portrait.jpg"], "resolution": "720p", "duration": 10 } ``` ### Vertical social clip, no audio ```json { "model": "grok-imagine-video-1.5-official", "prompt": "Energetic motion, quick handheld feel", "image_urls": ["https://your-cdn.com/poster.jpg"], "aspect_ratio": "9:16", "resolution": "720p", "duration": 6, "audio": false } ``` *** ## Polling pattern The task endpoint behaves identically to other video tasks. A pragmatic schedule: ``` 0–5 minutes: poll every 5s 5 min – 1 h: back off gradually toward 1 min ≥ 1 h: cap at 3 min between polls ``` A typical task completes in about a minute. The worker's wall-clock cap is **48 hours**, comfortably above any realistic queue. *** ## Pricing Per-second rate by **resolution** — `720p` costs 2× the `480p` rate. This channel is priced independently of (and lower than) the beta channel. See current rates on the [Grok Imagine Video 1.5 model page](https://reapi.ai/models/grok-imagine-video-1-5). **Bill formula** (1 credit = $0.001): ``` credits = ceil(per_second_usd × duration × 1000) ``` Failed jobs refund automatically. *** ## Tips * **Write the prompt like a shot direction.** It is required here — lean into it: camera move, subject motion, atmosphere, and the sound you want. * **One clear subject image works best.** A centered, well-lit reference with clean composition tracks identity and motion far better than a busy frame. * **Sweet-spot duration: 6–10 seconds.** Longer clips raise wall-time without changing the per-second rate. * **Pick `720p` for hero shots, `480p` to save.** The 720p rate is exactly 2× the 480p rate on this channel. *** ## Related * [grok-imagine-video-1.5-beta](/docs/grok-imagine-video-1-5) * [grok-imagine-1.0-video](/docs/grok-imagine-1-0-video) * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # grok-imagine-video-1.5-beta (https://reapi.ai/docs/grok-imagine-video-1-5) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Grok Imagine Video 1.5 — async **image-to-video** with **native > synchronized audio**. Pass exactly one reference image (and an optional > prompt) and the model returns a realistic clip with lifelike motion at > 480p or 720p, 1 to 15 seconds. Model id `grok-imagine-video-1.5-beta`. > See current pricing on the > [model page](https://reapi.ai/models/grok-imagine-video-1-5). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "grok-imagine-video-1.5-beta", "prompt": "Gentle cinematic push-in, golden-hour light, subtle motion", "image_urls": ["https://your-cdn.com/source.jpg"], "resolution": "720p", "duration": 8 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "grok-imagine-video-1.5-beta", "prompt": "Gentle cinematic push-in, golden-hour light, subtle motion", "image_urls": ["https://your-cdn.com/source.jpg"], "resolution": "720p", "duration": 8, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "grok-imagine-video-1.5-beta", prompt: "Gentle cinematic push-in, golden-hour light, subtle motion", image_urls: ["https://your-cdn.com/source.jpg"], resolution: "720p", duration: 8, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "grok-imagine-video-1.5-beta", "prompt": "Gentle cinematic push-in, golden-hour light, subtle motion", "image_urls": []string{"https://your-cdn.com/source.jpg"}, "resolution": "720p", "duration": 8, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "grok-imagine-video-1.5-beta", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URL (with audio), valid for 7 days. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. This is an **image-to-video** model — exactly one reference image is required on every request. There is no text-to-video mode and no `mode` parameter. *** ## Request body ### `model` — required `string`. Must be `"grok-imagine-video-1.5-beta"`. ### `image_urls` — string\[], required Array with **exactly one** public HTTP(S) image URL — the frame the model animates. Accepted source formats: JPEG, PNG, WebP. **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — the image URL must be a public HTTP(S) link. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. More than one entry is rejected. ### `prompt` — string, optional Up to **4,096 characters**. Optional — the reference image alone will animate. Use it to direct motion, camera, atmosphere, and any dialogue or sound you want in the generated audio. ### `aspect_ratio` — string, default `"auto"` Output framing. `auto` follows the source image's size. One of: | Value | Shape | | ------ | ----------------------------- | | `auto` | Follow source image (default) | | `1:1` | Square | | `16:9` | Landscape | | `9:16` | Portrait | | `4:3` | Landscape | | `3:4` | Portrait | | `3:2` | Landscape | | `2:3` | Portrait | ### `resolution` — string, default `"480p"` `480p` or `720p`. Unlike a flat-rate model, `720p` costs more per second than `480p` — see Pricing. ### `duration` — integer, default `8` Output length in seconds. Any integer in `[1, 15]`. Out-of-range → `400`. Drives pricing linearly. **Send a number, not a string.** `"duration": "8"` is rejected with `400`. ### `nsfw_checker` — boolean, default `true` Content safety filter. Defaults to `true`. You can set it to `false` to relax filtering for your own request. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "grok-imagine-video-1.5-beta", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | The generated MP4 carries the native audio track. `output.video_urls` URLs are valid for **7 days** — re-host to your own storage if you need them longer. *** ## Validation errors Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed values) and are not a stable contract. | Trigger | Code | Message (illustrative) | | -------------------------------------------------- | ------- | ------------------------------------------------ | | `image_urls` missing | `20002` | `image_urls is required` | | `image_urls` with more than one entry | `20003` | `image_urls allows at most 1 entry` | | `prompt` longer than 4,096 chars | `20007` | `prompt must be at most 4096 characters` | | `duration` outside `[1, 15]` | `20003` | `duration must be 1-15 seconds` | | Unknown `resolution` | `20003` | `invalid resolution (allowed: 480p / 720p)` | | Unknown `aspect_ratio` | `20003` | `invalid aspect_ratio` | | `image_urls` carrying a `data:` URI or non-http(s) | `20003` | `image_urls entries must be public http(s) URLs` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see the [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### Minimum request — image only ```json { "model": "grok-imagine-video-1.5-beta", "image_urls": ["https://your-cdn.com/source.jpg"] } ``` ### Directed motion + HD ```json { "model": "grok-imagine-video-1.5-beta", "prompt": "Slow dolly forward, wind moving the hair, warm cinematic light", "image_urls": ["https://your-cdn.com/portrait.jpg"], "resolution": "720p", "duration": 10 } ``` ### Vertical social clip ```json { "model": "grok-imagine-video-1.5-beta", "prompt": "Energetic motion with ambient street sound", "image_urls": ["https://your-cdn.com/poster.jpg"], "aspect_ratio": "9:16", "resolution": "720p", "duration": 6 } ``` *** ## Polling pattern The task endpoint behaves identically to other video tasks. A pragmatic schedule: ``` 0–5 minutes: poll every 5s 5 min – 1 h: back off gradually toward 1 min ≥ 1 h: cap at 3 min between polls ``` A typical task completes in a few minutes. The worker's wall-clock cap is **48 hours**, comfortably above any realistic queue. *** ## Channels Grok Imagine Video 1.5 ships in two independent channels. You pick a channel by switching the `model` id you POST; each bills at its own per-second rate and neither falls back to the other. | Channel | `model` id | prompt | duration | aspect\_ratio | extras | | -------------------- | --------------------------------- | -------- | -------- | ----------------------- | -------------- | | Official *(default)* | `grok-imagine-video-1.5-official` | required | 6–15 s | `1:1` / `16:9` / `9:16` | `audio` toggle | | Beta | `grok-imagine-video-1.5-beta` | optional | 1–15 s | `auto` + 7 ratios | `nsfw_checker` | Both are image-to-video with exactly one reference image and native audio; submit/poll envelope, task id format, retention (7 days), and error codes are identical. The official channel has the lower per-second rate — see the [full official-channel reference](/docs/grok-imagine-video-1-5-official). *** ## Pricing Per-second rate by **resolution** — `720p` costs more per second than `480p`. See current rates on the [Grok Imagine Video 1.5 model page](https://reapi.ai/models/grok-imagine-video-1-5). **Bill formula** (1 credit = $0.001): ``` credits = ceil(per_second_usd × duration × 1000) ``` Failed jobs refund automatically. *** ## Tips * **One clear subject image works best.** A centered, well-lit reference with clean composition tracks identity and motion far better than a busy frame. * **Prompt the motion and the sound.** "Slow push-in, ambient room tone, soft breathing" gives the native audio something to lock onto, not just the video. * **Sweet-spot duration: 5–10 seconds.** Longer clips raise wall-time without changing the per-second rate. * **Pick `720p` for hero shots, `480p` to save.** Resolution changes the per-second cost on this model, unlike flat-rate siblings. *** ## Related * [grok-imagine-video-1.5-official](/docs/grok-imagine-video-1-5-official) * [grok-imagine-1.0-video](/docs/grok-imagine-1-0-video) * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # happyhorse-1.0-official (https://reapi.ai/docs/happyhorse-1-0-official) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Happy Horse 1.0 **Official Channel** — direct first-party routing, > distinct from the standard [`happyhorse-1.0`](/docs/happyhorse-1-0) > channel. It uses the official Aliyun Model Studio SKUs behind > one ReAPI model id and keeps ReAPI's URL-only media contract. **Official channel, ReAPI boundary.** The upstream provider is Aliyun Model Studio first-party. Media inputs must still be public `http(s)` URLs; base64/data URI media is not accepted by ReAPI even where upstream docs show base64 examples. Watermark policy is also a ReAPI override: Aliyun's official default is `true`, but ReAPI defaults `watermark` to `false`. Send `"watermark": true` if you want the upstream watermark. ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "happyhorse-1.0-official", "prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel", "resolution": "1080P", "size": "4:5", "duration": 5, "seed": 42 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "happyhorse-1.0-official", "prompt": "A coastal road at sunset, slow-motion camera push-in", "resolution": "1080P", "size": "4:5", "duration": 5, "seed": 42, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "happyhorse-1.0-official", prompt: "A coastal road at sunset, slow-motion camera push-in", resolution: "1080P", size: "4:5", duration: 5, seed: 42, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "happyhorse-1.0-official", "prompt": "A coastal road at sunset, slow-motion camera push-in", "resolution": "1080P", "size": "4:5", "duration": 5, "seed": 42, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Request surface The public endpoint and async response envelope are the same as the standard channel: ```txt POST /api/v1/videos/generations ``` One `model` id auto-routes by request shape: | Shape | Official upstream SKU | | ---------------------------------------------------- | --------------------------- | | `prompt` only | `happyhorse-1.0-t2v` | | `first_frame_image` (+ optional `prompt`) | `happyhorse-1.0-i2v` | | `image_urls` 1-9 + `prompt` | `happyhorse-1.0-r2v` | | `video_url` (+ optional `image_urls` 0-5) + `prompt` | `happyhorse-1.0-video-edit` | `first_frame_image`, `image_urls`, and `video_url` are mutually exclusive except for the legal EDIT combination: `video_url + image_urls`. ## Official-channel constraints | Field | Official channel behavior | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | Must be `"happyhorse-1.0-official"` | | `prompt` | Required for T2V / R2V / EDIT, optional for I2V. Aliyun truncates over-length prompt text upstream; ReAPI does not reject official-channel prompts at the standard-channel 2500-character cap. | | `first_frame_image` | Public `http(s)` URL only. Base64/data URI is rejected by ReAPI. | | `image_urls` | Public `http(s)` URLs only. R2V accepts 1-9 images; EDIT accepts 0-5 reference images. | | `video_url` | Public `http(s)` URL only. EDIT source video must be 3-60 seconds, long side ≤2160 px, short side ≥320 px, and aspect ratio between 1:2.5 and 2.5:1. Aliyun also enforces file size ≤100 MB and fps >8. | | `resolution` | `"720P"` or `"1080P"`; omitted lets upstream apply its default. | | `size` | T2V/R2V ratio: `"16:9"`, `"9:16"`, `"1:1"`, `"4:3"`, `"3:4"`, `"4:5"`, `"5:4"`. Ignored for I2V and EDIT because output shape follows the source media. | | `duration` | 3-15 seconds for T2V/I2V/R2V. Ignored for EDIT because output length follows the source video. | | `watermark` | ReAPI default is `false` even though Aliyun's official default is `true`. Explicit `true` / `false` is honored. | | `seed` | Integer from 0 to 2147483647. | | `audio_setting` | EDIT only: `"auto"` or `"origin"`. | ## Differences from `happyhorse-1.0` | Aspect | `happyhorse-1.0` | `happyhorse-1.0-official` | | ----------------------- | ----------------------------------- | ----------------------------------------------------------------------- | | Upstream channel | Standard | Aliyun Model Studio official | | Wire `model` value | `"happyhorse-1.0"` | `"happyhorse-1.0-official"` | | T2V/R2V ratios | `16:9`, `9:16`, `1:1`, `4:3`, `3:4` | Adds `4:5` and `5:4` | | Prompt cap | ReAPI rejects above 2500 chars | Aliyun truncation semantics; no local 2500-char reject | | EDIT video dimensions | Standard channel validation rules | Official Aliyun validation rules | | Default watermark | ReAPI default `false` | ReAPI default `false` (intentional override from Aliyun default `true`) | | Per-second rate | Baseline | **10% off** the baseline | | Validation error prefix | `happyhorse:` | `happyhorse-official:` | *** ## Pricing Per-second × resolution. **10% off** the standard channel at every supported resolution. See current 720P / 1080P / 4K rates on the [Happy Horse model page](https://reapi.ai/models/happyhorse-1-0). **Bill formula** (1 credit = $0.001): | Mode | Billable seconds | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | T2V / I2V / R2V | `duration` you sent (default 5) | | EDIT | `ceil(probed_source_seconds) + min(ceil(probed_source_seconds), 15)` — vendor processes the source AND produces a capped output; both sides are billable. Failed probe → `400 PRICING_UNAVAILABLE`, no charge. | Final bill: `ceil(per_second_usd_after_discount × billable_seconds × 1000)` credits. Failed jobs refund automatically. ### Examples | Source video | Mode | Billable seconds | | ------------ | ------------------ | --------------------- | | — | T2V, `duration=5` | 5 | | — | T2V, `duration=10` | 10 | | 5s clip | EDIT | 5 + min(5, 15) = 10 | | 8.3s clip | EDIT | 9 + min(9, 15) = 18 | | 60s clip | EDIT | 60 + min(60, 15) = 75 | | 20s clip | EDIT | 20 + min(20, 15) = 35 | Apply `ceil(per_second_usd_after_discount × billable_seconds × 1000)` for the credit charge. *** ## Validation errors The response envelope and numeric error-code system match the standard channel, but official-channel validation follows the official Aliyun rules listed above. Error messages from this channel use the `happyhorse-official:` prefix. Pattern-match on the numeric `code`, not the message string. *** ## When to pick which channel | Need | Channel | | --------------------------------------------- | ------------------------- | | Lowest unit price | `happyhorse-1.0-official` | | Official Aliyun Model Studio route | `happyhorse-1.0-official` | | `size` values `4:5` or `5:4` | `happyhorse-1.0-official` | | Existing integration with no migration | `happyhorse-1.0` | | Standard channel route / existing constraints | `happyhorse-1.0` | Switching channels = changing the `model` string in your request body. The response envelope and polling flow are shared; provider-specific validation and pricing differ as documented above. *** ## Related * [`happyhorse-1.0` — full reference](/docs/happyhorse-1-0) * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Aliyun official T2V reference](https://help.aliyun.com/zh/model-studio/happyhorse-text-to-video-api-reference) * [Aliyun official I2V reference](https://help.aliyun.com/zh/model-studio/happyhorse-image-to-video-api-reference) * [Aliyun official R2V reference](https://help.aliyun.com/zh/model-studio/happyhorse-reference-to-video-api-reference) * [Aliyun official EDIT reference](https://help.aliyun.com/zh/model-studio/happyhorse-video-edit-api-reference) --- # happyhorse-1.0 (https://reapi.ai/docs/happyhorse-1-0) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Alibaba Cloud Bailian Happy Horse 1.0 — a single async video endpoint that > auto-routes between **T2V / I2V / R2V / EDIT** based on which media field > your request carries. 720P or 1080P, 3–15 second outputs, billed only by > resolution × duration regardless of mode. See current pricing on the > [model page](https://reapi.ai/models/happyhorse-1-0). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "happyhorse-1.0", "prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel", "resolution": "1080P", "size": "16:9", "duration": 5, "seed": 42 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "happyhorse-1.0", "prompt": "A coastal road at sunset, slow-motion camera push-in", "resolution": "1080P", "size": "16:9", "duration": 5, "seed": 42, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "happyhorse-1.0", prompt: "A coastal road at sunset, slow-motion camera push-in", resolution: "1080P", size: "16:9", duration: 5, seed: 42, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "happyhorse-1.0", "prompt": "A coastal road at sunset, slow-motion camera push-in", "resolution": "1080P", "size": "16:9", "duration": 5, "seed": 42, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "happyhorse-1.0", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URLs, valid for 7 days. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Mode routing `happyhorse-1.0` is **one model id** that picks its mode from which media fields you set: | Fields you send | Mode | What it does | | --------------------------------------------------------------------- | -------- | ----------------------------------------- | | `prompt` only | **T2V** | Generate from text | | `prompt` + `first_frame_image` | **I2V** | Animate starting from a still frame | | `prompt` + `image_urls` (1–9) | **R2V** | Compose a new scene from reference images | | `video_url` (+ `prompt`, optional `image_urls` ≤ 5 / `audio_setting`) | **EDIT** | Restyle / rewrite an existing clip | Resolution priority when multiple fields are set: `video_url` > `first_frame_image` > `image_urls` > `prompt`-only. **Mutex rule.** The three media fields (`first_frame_image`, `image_urls`, `video_url`) are mutually exclusive **in pairs**. The single legal pairing is `video_url + image_urls` (EDIT with style references). Any other combination is rejected with `400 first_frame_image and image_urls cannot be combined` or `400 first_frame_image and video_url cannot be combined` (code `20003`). *** ## Request body ### `model` — required `string`. Always `"happyhorse-1.0"`. ### `prompt` — string Up to **2,500 characters**. Required in T2V / R2V / EDIT; optional in I2V (but recommended — phrasing the camera move and motion improves output quality). **Failure modes.** * Missing in non-I2V → `400 prompt is required in T2V / R2V / EDIT modes` (code `20002`). * Longer than 2,500 chars → `400 prompt must be at most 2500 characters` (code `20007`). ### `first_frame_image` — string Public HTTP(S) URL pointing at the still you want animated. Triggers **I2V** when set. Mutually exclusive with `image_urls` and `video_url`. Recommended source asset: JPEG / PNG / BMP / WEBP, short side ≥ 300px, ratio between `1:2.5` and `2.5:1`, ≤ 10MB. The upstream model also enforces these — the gateway forwards the URL untouched, so non-compliant assets surface as a delayed `provider_failed` rather than an immediate 400. Validate before submitting if the source isn't yours. **No `data:` URIs.** reapi rejects base64 inputs platform-wide. Upload to public storage (your own CDN, S3, R2…) and pass the URL. ### `image_urls` — string\[] Array of public HTTP(S) URLs. * **R2V** (no `video_url`): **1–9** entries. The upstream composes a fresh scene that incorporates the supplied subjects / styles. * **EDIT** (`video_url` set): **0–5** entries acting as style references on top of the source video. Sending more than 5 is rejected with `400 image_urls allows at most 5 entries in EDIT mode`. Same per-asset constraints as `first_frame_image` (short side ≥ 720px is recommended for R2V, short / long ≥ 0.4, ≤ 10MB each). T2V and I2V requests are **rejected** if `image_urls` is present — the upstream wouldn't consume it, and silently dropping it would make billing surprising. Mutually exclusive with `first_frame_image`. ### `video_url` — string Public HTTP(S) URL of the source clip. Triggers **EDIT** mode. Combinable with `image_urls` (≤ 5) and `audio_setting`. Mutually exclusive with `first_frame_image`. Source asset shape (enforced upstream): MP4 / MOV (H.264 recommended), duration 3–60 seconds, ≥ 480p / short side ≥ 360, ratio between `1:8` and `8:1`, > 8 fps, ≤ 100MB. **Length caps the output.** If the source video runs longer than 15s, the upstream truncates from second 0 to second 15 before processing. The output clip's length **matches the source's processed length** — trim the input yourself if you need a different segment or a tighter total. In EDIT mode the `duration` parameter is **ignored for both generation and billing**; reapi probes the source clip server-side and charges `(ceil(probed_seconds) + min(ceil(probed_seconds), 15)) × per_second_usd` — input and capped output are both billable. See the `duration` field below. ### `audio_setting` — string, default `"auto"` Only valid in EDIT mode. Sending it without `video_url` is rejected with `400 audio_setting requires video_url (EDIT mode only)`. | Value | Behavior | | ---------- | -------------------------------------- | | `"auto"` | Generate a fresh audio track (default) | | `"origin"` | Keep the source video's original audio | ### `resolution` — string, default `"1080P"` `"720P"` or `"1080P"`. Drives pricing — every other parameter is free across the two tiers. Lowercase forms (`"720p"`, `"1080p"`) are accepted and normalized for symmetry with seedance; the upstream sees the canonical uppercase form. ### `size` — string, default `"16:9"` Output ratio for **T2V and R2V only**. One of `16:9` / `9:16` / `1:1` / `4:3` / `3:4`. In **I2V** and **EDIT**, the upstream derives the output ratio from the input media (first-frame image / source video) and ignores `size`. The gateway still accepts the field — it's just inert. ### `duration` — integer, default `5` Output length in seconds for **T2V / I2V / R2V**. Any integer in `[3, 15]`. Drives pricing linearly: `ceil(per_second_usd × duration × 1000)` credits (1 credit = $0.001). **EDIT mode ignores `duration` for billing.** When `video_url` is set, reapi probes the source video's actual length on the server (ffmpeg metadata) and bills both the input clip AND the (capped) output: ``` billable = ceil(probed_seconds) + min(ceil(probed_seconds), 15) bill_usd = billable × per_second_usd ``` A 5s source bills 10s; a 60s source bills 75s (60 + 15-cap output). Whatever you send in `duration` is ignored for cost. The upstream also ignores `duration` here (output length tracks the source). Probe failures return `400 PRICING_UNAVAILABLE` (code `30002`) with no charge. ### `watermark` — boolean, default `false` Adds the platform watermark to the generated clip when `true`. ### `seed` — integer Reproducibility hint. Range `[0, 2147483647]`. Same seed plus an otherwise identical request returns a similar (not bit-for-bit identical) result. Omit for full randomness. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "happyhorse-1.0", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | `output.video_urls` URLs are valid for **7 days**. Re-host to your own storage if you need them longer. *** ## Validation errors All cases below return HTTP 400 with code `20003` unless noted. Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed dimensions, etc.) and are not a stable contract. | Trigger | Code | Message (illustrative) | | ----------------------------------------------------- | ------- | --------------------------------------------------------------------------------- | | `prompt` missing in T2V / R2V / EDIT | `20002` | `happyhorse: prompt is required in T2V / R2V / EDIT modes` | | `prompt` longer than 2,500 chars | `20007` | `happyhorse: prompt must be at most 2500 characters` | | `first_frame_image` + `image_urls` together | `20003` | `happyhorse: first_frame_image and image_urls cannot be combined` | | `first_frame_image` + `video_url` together | `20003` | `happyhorse: first_frame_image and video_url cannot be combined` | | `image_urls` empty array in R2V | `20003` | `happyhorse: image_urls contained no usable URLs` | | `image_urls` > 5 in EDIT | `20003` | `happyhorse: image_urls allows at most 5 entries in EDIT mode` | | `audio_setting` set without `video_url` | `20003` | `happyhorse: audio_setting requires video_url (EDIT mode only)` | | `image_urls` carrying a `data:` URI | `20003` | `happyhorse: image_urls must be public http(s) URLs` | | `video_url` carrying a `data:` URI | `20003` | `happyhorse: video_url must be a public http(s) URL` | | EDIT source duration \< 3s or > 60s | `20003` | `video_url duration X.XXs is out of range (must be 3–60s)` | | EDIT source resolution below 480p (short side \< 360) | `20003` | `video_url resolution WxH is below the 480p minimum (short side must be ≥ 360px)` | | EDIT source ratio outside 1:8–8:1 | `20003` | `video_url aspect ratio WxH is out of range (must be between 1:8 and 8:1)` | | EDIT source video probe fails (network / format) | `30002` | `Could not determine source video duration for billing: …` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### T2V — minimum request ```json { "model": "happyhorse-1.0", "prompt": "A little girl walking down the road, cinematic feel" } ``` ### T2V — full parameters ```json { "model": "happyhorse-1.0", "prompt": "Sunset coastal road, slow camera push-in, cinematic warm tones", "resolution": "1080P", "size": "16:9", "duration": 8, "watermark": false, "seed": 42 } ``` ### I2V — first-frame animation ```json { "model": "happyhorse-1.0", "prompt": "Bring the scene to life with gentle camera dolly forward", "first_frame_image": "https://your-cdn.com/first_frame.png", "resolution": "1080P", "duration": 5 } ``` ### R2V — multiple references ```json { "model": "happyhorse-1.0", "prompt": "The protagonist from image 1 runs through image 2's scene then picks up the prop from image 3. 3D cartoon style, smooth motion.", "image_urls": [ "https://your-cdn.com/img_01.jpg", "https://your-cdn.com/img_02.png", "https://your-cdn.com/img_03.jpeg" ], "resolution": "1080P", "size": "16:9", "duration": 5 } ``` ### EDIT — keep original audio + style reference ```json { "model": "happyhorse-1.0", "prompt": "Repaint the character in a 3D cartoon style, keep the original motion", "video_url": "https://your-cdn.com/source.mp4", "image_urls": ["https://your-cdn.com/style_ref.jpg"], "resolution": "1080P", "audio_setting": "origin", "seed": 42 } ``` ### 720P — cost-conscious ```json { "model": "happyhorse-1.0", "prompt": "Waves crashing on a beach at sunset, wide shot", "resolution": "720P", "size": "16:9", "duration": 5 } ``` *** ## Choosing a mode | Need | Send | | ----------------------------------------- | ------------------------------------------------------------------- | | Generate from text | `prompt` only (T2V) | | Animate a still | `prompt + first_frame_image` (I2V) | | Compose a new scene from reference images | `prompt + image_urls` 1–9 (R2V) | | Restyle / rewrite an existing clip | `video_url` (+ `prompt`, optional refs ≤ 5, `audio_setting`) (EDIT) | | Cut spend in half | Set `resolution: "720P"` | *** ## Polling pattern The task endpoint behaves identically to image tasks — the only difference is the completed `output` shape (`video_urls` instead of `image_urls`). A pragmatic schedule: ``` 0–5 minutes: poll every 5s 5 min – 1 h: back off gradually toward 1 min ≥ 1 h: cap at 3 min between polls ``` A typical task completes in a few minutes. The worker's wall-clock cap is **48 hours**, comfortably above any realistic queue. *** ## Channels `happyhorse-1.0` ships in three channels. The wire schema is identical; you pick a channel by switching the `model` id you POST. Pricing, upstream routing, and a few feature corners differ — same input you send to any of them, just at different cost / quality / latency. | Channel | `model` id | Pricing | 4K | mask | negative prompt | | -------------------- | ------------------------- | -------- | -- | ---- | --------------- | | Standard *(default)* | `happyhorse-1.0` | baseline | — | — | — | | Official *(-10%)* | `happyhorse-1.0-official` | 0.9 × | ✓ | — | — | Both accept the **same request body** documented in this page — `prompt`, `first_frame_image`, `image_urls`, `video_url`, `audio_setting`, `resolution`, `size`, `duration`, `seed`, `watermark`. The only client-visible difference at the schema level is: * **Official channel**: adds 2 extra aspect ratios (`4:5`, `5:4`) and supports `4K` resolution. `watermark` is forced `false`. Submit/poll envelope is identical across channels — task id format, `status` enum, `output.video_urls` shape. Polling rate, retention (7 days for video URLs), and validation error codes are the same. Pick by use case: * **Standard** is the default for new integrations — predictable latency, full feature surface (only one that supports R2V image cardinality up to 9). * **Official** if you need 4K output, the wider aspect-ratio set, or the 10% discount applies to your volume. *** ## Pricing Per-second × resolution. Mode does **not** change the rate. Both channels share the same parameter shape: * **Standard** — `happyhorse-1.0`, full feature surface. * **Official** — `happyhorse-1.0-official`, cheaper than Standard, supports 4K (see official-only doc). See current 720P / 1080P / 4K rates per channel on the [Happy Horse model page](https://reapi.ai/models/happyhorse-1-0). **Bill formula** (1 credit = $0.001): | Mode | Billable seconds | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | T2V / I2V / R2V | `duration` you sent (default 5) | | EDIT | `ceil(server_probed_source_seconds) + min(ceil(server_probed_source_seconds), 15)` — input and capped output both billable. `duration` is **ignored** in EDIT; server measures the uploaded clip. Failed probe → `400 PRICING_UNAVAILABLE`, no charge | Final bill: `ceil(per_second_usd × billable_seconds × 1000)` credits. Failed jobs refund automatically. *** ## Tips * **Prompt motion, not just scene.** "Slow push-in, warm tones, shallow depth of field" outperforms a pure noun-list of what's on screen. * **Sweet-spot duration: 5–10 seconds.** Below 5s motion looks choppy; above 10s upstream wall-time grows fast. * **First-frame quality matters.** Subject centered, clear composition, no heavy filters — I2V output quality tracks input quality directly. * **Pre-trim EDIT sources.** > 15s clips get auto-truncated to the first 15s upstream **and capped at 15s for billing**. Slice the input yourself if you want a different segment. * **EDIT cost = source length.** A 5s source bills 5s; an 8s source bills 8s; a 60s source bills 15s (the cap). The playground's draft estimate may show a default before the upload finishes — the authoritative number is computed at submit after the server probes the file. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # happyhorse-1-1 (https://reapi.ai/docs/happyhorse-1-1) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Alibaba HappyHorse 1.1 — a single async video endpoint that auto-routes > between **T2V / I2V / R2V** based on which media field your request carries. > 720p or 1080p, 3–15 second outputs, billed only by resolution × duration > regardless of mode. See current pricing on the > [model page](https://reapi.ai/models/happyhorse-1-1). Generation is **asynchronous**: the POST returns a task id, then poll [`GET /api/v1/tasks/{id}`](/docs/api/tasks) until `status` is `completed`. ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "happyhorse-1-1", "prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel", "resolution": "1080p", "aspect_ratio": "16:9", "duration": 5 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "happyhorse-1-1", "prompt": "A coastal road at sunset, slow-motion camera push-in", "resolution": "1080p", "aspect_ratio": "16:9", "duration": 5, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "happyhorse-1-1", prompt: "A coastal road at sunset, slow-motion camera push-in", resolution: "1080p", aspect_ratio: "16:9", duration: 5, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "happyhorse-1-1", "prompt": "A coastal road at sunset, slow-motion camera push-in", "resolution": "1080p", "aspect_ratio": "16:9", "duration": 5, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() var out map[string]any json.NewDecoder(resp.Body).Decode(&out) fmt.Println(out) } ``` ## Endpoint ```http POST /api/v1/videos/generations Authorization: Bearer rk_live_xxx Content-Type: application/json ``` Submitting returns a task id; poll [`GET /api/v1/tasks/{id}`](/docs/api/tasks) for the result. Polling does not consume credits. ## Parameters | Parameter | Type | Required | Default | Description | | ---------------------- | --------- | ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `model` | string | yes | — | `happyhorse-1-1` | | `prompt` | string | T2V / R2V: yes · I2V: no | — | Any language. ≤5000 non-CJK / ≤2500 CJK characters (over-length is auto-truncated upstream). In R2V, reference images with `[Image 1]`, `[Image 2]`, … | | `image_urls` | string\[] | I2V | — | First-frame image, **exactly 1** public URL. Presence selects **image-to-video**. JPEG/PNG/WEBP, short side ≥300px, ratio 1:2.5–2.5:1, ≤20MB. | | `reference_image_urls` | string\[] | R2V | — | **1–9** reference image URLs. Presence selects **reference-to-video**. JPEG/PNG/WEBP, short side ≥400px, ≤20MB. | | `resolution` | enum | no | `720p` | `720p` · `1080p` | | `aspect_ratio` | enum | no | `16:9` | `16:9` `9:16` `3:4` `4:3` `4:5` `5:4` `1:1` `9:21` `21:9`. **T2V / R2V only** — in I2V the orientation is derived from the source image. | | `duration` | integer | no | `5` | Output length in seconds, `3`–`15`. | `image_urls` (I2V) and `reference_image_urls` (R2V) are **mutually exclusive**. All media inputs must be public HTTP(S) URLs — base64 / `data:` URIs are rejected. ## Modes Mode is implicit — selected by which inputs you send: | Mode | Trigger | prompt | aspect\_ratio | | ---------------------------- | ---------------------------- | -------- | --------------- | | **Text-to-video (T2V)** | no media | required | yes | | **Image-to-video (I2V)** | `image_urls` (1) | optional | no (from image) | | **Reference-to-video (R2V)** | `reference_image_urls` (1–9) | required | yes | ```json // I2V — animate a first frame { "model": "happyhorse-1-1", "image_urls": ["https://…/frame.jpg"], "resolution": "1080p", "duration": 5 } // R2V — keep subjects consistent across the clip { "model": "happyhorse-1-1", "prompt": "the woman in [Image 1] walks through [Image 2]", "reference_image_urls": ["https://…/a.jpg", "https://…/b.jpg"], "resolution": "1080p", "duration": 5 } ``` ## Pricing Billed by **per-second rate × resolution × duration**; the routing mode does not change the rate. Two tiers: `720p` and `1080p`. See the [model page](https://reapi.ai/models/happyhorse-1-1) for current rates. **Bill formula** (`1 credit = $0.001`): ``` credits = ceil(per_second_usd × duration × 1000) ``` ## Output On success, `GET /api/v1/tasks/{id}` returns: ```json { "id": "task_…", "model": "happyhorse-1-1", "status": "completed", "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/…/0.mp4"] }, "error": null } ``` ## Errors | HTTP | `code` | When | | ---- | ----------------- | ------------------------------------------------------------------------------------ | | 400 | `20002` | Missing / invalid parameter (e.g. prompt required in T2V/R2V, both image fields set) | | 401 | `10001` – `10005` | Auth missing / invalid / revoked | | 402 | `30001` | Insufficient credits | | 429 | `50001` | Per-user rate limit exceeded | Failed generations are surfaced under `error` in the polling response and are refunded automatically. Full catalog: [Errors](/docs/api/errors). ## Tips * **Pick the mode by inputs, not a flag.** Sending `reference_image_urls` switches to R2V; sending `image_urls` switches to I2V; neither → T2V. * In **R2V**, name each subject explicitly and reference it by `[Image N]` in the prompt, matching the array order, for the strongest identity retention. * `aspect_ratio` is ignored in I2V — crop your source image to the orientation you want instead. * Longer `duration` scales the bill linearly; start at 5s while iterating. ## Related * [Tasks](/docs/api/tasks) — universal polling endpoint * [Errors](/docs/api/errors) — full error catalog * [happyhorse-1-0](/docs/happyhorse-1-0) — the previous generation --- # humanize (https://reapi.ai/docs/humanize) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > `humanize` is a single async endpoint that takes AI-generated text and returns > a rewrite that reads as human-written — varied rhythm, natural transitions, no > tell-tale AI cadence — built to pass common AI detectors. Tune the rewrite > with `readability`, `purpose`, `strength`, and `model_version`. See current > pricing on the [model page](https://reapi.ai/models/humanize). ## Quick example ```bash curl https://reapi.ai/api/v1/humanize \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "humanize", "content": "Artificial intelligence has fundamentally transformed the way modern enterprises approach data-driven decision making.", "readability": "University", "purpose": "General Writing", "strength": "Balanced", "model_version": "v2" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/humanize", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "humanize", "content": "Artificial intelligence has fundamentally transformed the way modern enterprises approach data-driven decision making.", "readability": "University", "purpose": "General Writing", "strength": "Balanced", "model_version": "v2", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/humanize", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "humanize", content: "Artificial intelligence has fundamentally transformed the way modern enterprises approach data-driven decision making.", readability: "University", purpose: "General Writing", strength: "Balanced", model_version: "v2", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "humanize", "content": "Artificial intelligence has fundamentally transformed the way modern enterprises approach data-driven decision making.", "readability": "University", "purpose": "General Writing", "strength": "Balanced", "model_version": "v2", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/humanize", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "humanize", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` until `status === "completed"`. The completed payload's `output.humanized_text` holds the rewritten text. A rewrite usually finishes in a few seconds. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/humanize GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; polling the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required Always `"humanize"`. ### `content` — required (string) The AI-generated text to humanize. Minimum **50 characters**. Longer text takes proportionally longer to return. ### `readability` — required (string) Target reading level of the rewrite. One of: | Value | Register | | ------------- | --------------------------------- | | `High School` | Simple, accessible prose. | | `University` | Standard academic / professional. | | `Doctorate` | Dense, formal, advanced. | | `Journalist` | Punchy, news-style. | | `Marketing` | Persuasive, brand-friendly. | ### `purpose` — required (string) What the text is for — tunes tone and structure. One of: `General Writing`, `Essay`, `Article`, `Marketing Material`, `Story`, `Cover Letter`, `Report`, `Business Material`, `Legal Material`. ### `strength` — optional (string) How aggressively to rewrite. Default: `"Balanced"`. | Value | Behavior | | ------------ | ----------------------------------------------------------- | | `Quality` | Lightest touch; stays closest to the source wording. | | `Balanced` | Default trade-off between fidelity and humanization. | | `More Human` | Most aggressive rewrite for the strongest detector evasion. | ### `model_version` — optional (string) Which humanizer model handles the rewrite. Default: `"v2"`. | Value | Best for | | ------- | -------------------------------------------------- | | `v2` | All languages, medium humanization. | | `v11` | English, high humanization. | | `v11sr` | English, strongest humanization (slightly slower). | `model_version` maps to the underlying engine's model selector. reAPI uses `model` at the top level to route the request, so this knob is exposed as a separate `model_version` field to avoid the name collision — its values are unchanged. *** ## Output ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "humanize", "status": "completed", "created_at": 1735000000, "output": { "humanized_text": "AI has reshaped how today's companies make decisions with data..." }, "error": null } ``` `output.humanized_text` is plain text — drop it straight back into your document or CMS. *** ## Pricing Billed **per word** of the `content` you submit, with a **50-word floor** (text under 50 words is charged as 50 words). Polling the task does not add any charge. Failed and rejected requests are refunded automatically. `1 credit = $0.001 USD`. See the live banner on the [model page](https://reapi.ai/models/humanize) for the current per-1,000-words rate in credits. *** ## Errors Standard envelope: ```json { "error": { "code": 20003, "message": "content must be at least 50 characters", "request_id": "req_..." } } ``` Common cases: | Code | When | | ------- | -------------------------------------------------------------------------------- | | `20002` | `content`, `readability`, or `purpose` missing. | | `20003` | Invalid enum value, or `content` under 50 characters. | | `30001` | Insufficient credits for the submitted word count. | | `80001` | Provider rejected the submission — includes insufficient upstream credits/words. | | `80003` | Provider failed while processing the rewrite. | *** ## Related * [AI Text Detector](/docs/ai-text-detector) — score text 0–100 for AI authorship. Pair it with `humanize` for a detect → rewrite → detect QA loop. --- # imagen-4-0 (https://reapi.ai/docs/imagen-4-0) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Google's Imagen 4 model on reAPI. **Text-to-image only** — no reference > images, no inpainting masks. Five aspect ratios at a **flat per-image > rate**. Async-first: submit returns a `task_id`; poll until ready. See > current pricing on the [model page](https://reapi.ai/models/imagen-4-0). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "imagen-4-0", "prompt": "A corgi wearing an astronaut helmet on the lunar surface, Earth in the background, cinematic lighting, 8k", "size": "16:9" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "imagen-4-0", "prompt": "A corgi wearing an astronaut helmet on the lunar surface, Earth in the background, cinematic lighting, 8k", "size": "16:9", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "imagen-4-0", prompt: "A corgi wearing an astronaut helmet on the lunar surface, Earth in the background, cinematic lighting, 8k", size: "16:9", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "imagen-4-0", "prompt": "A corgi wearing an astronaut helmet on the lunar surface, Earth in the background, cinematic lighting, 8k", "size": "16:9", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` The response carries a `task_id`. Poll [`GET /api/v1/tasks/{task_id}`](/docs/api/tasks) until `status` is `completed`, then read `result.images[].url`. ## Request body | Field | Type | Required | Default | Description | | -------- | ------- | -------- | ------- | --------------------------------------------------------------------------------------------------------- | | `model` | string | yes | — | Must be `imagen-4-0`. | | `prompt` | string | yes | — | Image description. English or Chinese both supported. Up to 4000 characters. | | `n` | integer | no | `1` | Number of images per request. Only `1` is accepted. | | `size` | string | no | `16:9` | Aspect ratio. One of `1:1` / `4:3` / `3:4` / `16:9` / `9:16`. Passing an unsupported ratio returns a 400. | `imagen-4-0` is **text-to-image only**. The endpoint rejects `image_urls`, `image`, `mask`, and similar reference fields. For image-to-image, see [seedream-5-0-lite](/docs/seedream-5-0-lite) or the [gemini-3-pro-image-preview](/docs/gemini-3-pro-image-preview) family. ## Response Submission returns the standard async envelope: ```json { "code": 200, "data": [ { "status": "submitted", "task_id": "task_01K8AYYM6R03TGZ3Q2P0TZVNPX" } ] } ``` Polled completion (`GET /api/v1/tasks/{task_id}`): ```json { "code": 200, "data": { "status": "completed", "result": { "images": [{ "url": "https://cdn.reapi.ai/..." }] } } } ``` Image URLs are valid for 24 hours from completion. Re-host the asset to your own storage if you need durable access. ## Pricing Flat per-image rate. `n` is fixed at `1`, so total charge is exactly one image per request. See the [model page](https://reapi.ai/models/imagen-4-0) for the live rate. ## Errors `imagen-4-0` shares the platform-wide [error envelope](/docs/api/errors). The validation surface is small: * `prompt` missing or empty → `400 INVALID_REQUEST`. * `size` outside the five accepted ratios → `400 INVALID_REQUEST`. * `n` set to any value other than `1` → `400 INVALID_REQUEST`. * Any reference media (`image_urls`, `image`, `mask`) supplied → `400 INVALID_REQUEST` with a text-to-image-only message. --- # Welcome (https://reapi.ai/docs) reAPI is an aggregator that runs every leading image, video, chat, and code model behind a single standard endpoint. Pay-as-you-go via credits, no per-provider account juggling. ## Where to start * **[Quickstart](/docs/api/quickstart)** — first call in 5 minutes. * **[Authentication](/docs/api/authentication)** — create and use API keys. * **[Tasks](/docs/api/tasks)** — `GET /api/v1/tasks/{id}` polling reference (image, video, and audio). * **[Errors](/docs/api/errors)** — error codes and how to handle them. Per-model request schemas (parameters, sizes, resolutions, examples) live on each model's own page — see the **Models** sidebar. --- # kimi-k3 (https://reapi.ai/docs/kimi-k3) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Moonshot's Kimi K3 — the flagship for long-horizon coding and end-to-end > knowledge work — exposed through api.reapi.ai as a drop-in OpenAI-compatible > Chat Completions endpoint. A **1,048,576-token** context window, output > defaulting to **131,072** tokens and raisable to the full window, **reasoning > that is always on** with a three-rung `reasoning_effort` dial, native **image > and video** input, tool calling with a `required` tool choice, strict JSON > Schema output, and automatic context caching. The wire `model` id is > `kimi-k3`. Current rates live on the > [model page](https://reapi.ai/models/kimi-k3) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k3", "messages": [ { "role": "user", "content": "Refactor this module and add tests." } ], "reasoning_effort": "high", "stream": true }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="kimi-k3", messages=[{"role": "user", "content": "Refactor this module and add tests."}], reasoning_effort="high", stream=True, ) for chunk in stream: delta = chunk.choices[0].delta reasoning = getattr(delta, "reasoning_content", None) if reasoning: print(reasoning, end="") if delta.content: print(delta.content, end="") ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "kimi-k3", messages: [{ role: "user", content: "Refactor this module and add tests." }], reasoning_effort: "high", stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "kimi-k3", "messages": []map[string]string{ {"role": "user", "content": "Refactor this module and add tests."}, }, "reasoning_effort": "high", }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Chat models are served from the `api.reapi.ai` gateway, which has its own console and its own key. Create the key there, then send it as a bearer token: ```http Authorization: Bearer YOUR_API_KEY ``` The gateway key is **not** the same credential as a media-generation key used against `reapi.ai/api/v1`. Sign in at [api.reapi.ai](https://api.reapi.ai/) to create one. *** ## Endpoint ```http POST /v1/chat/completions ``` Base URL `https://api.reapi.ai`. The wire format is OpenAI-compatible, so the same SDKs (`openai-python`, `openai-node`, `openai-go`, …) work once you swap the base URL, the key and the model string. Moonshot's own quickstart drives this model through the OpenAI SDK, so the compatibility is the vendor's design rather than a translation layer. *** ## Request body ### `model` — string, required Must be `kimi-k3` exactly — no date suffix, no version decimal. ### `messages` — array, required Conversation history, each entry an object with `role` and `content`. Text, image and video parts are supported — see [Visual input](#visual-input). **Echo the assistant message back unchanged.** In multi-turn conversations and tool-call loops, the complete assistant message returned by the API has to go back into `messages` as-is, including `reasoning_content` and `tool_calls`. Keeping only `content` — the habit most OpenAI-shaped code has — breaks this model's Preserved Thinking. ### `max_completion_tokens` — integer Upper bound on output tokens for this response. Moonshot documents a **default of 131,072**, raisable to **1,048,576** — the size of the whole context window. Reasoning runs before the answer, so budget for both. ### `reasoning_effort` — string, default `"max"` Top-level field controlling how hard the model thinks. See [Reasoning](#reasoning). ### `stream` — boolean, default `false` When `true`, tokens arrive as server-sent events. Reasoning and answer come as **separate deltas** — `reasoning_content` and `content` — so a client can render the reasoning live and still parse the answer on its own. ### `tools` / `tool_choice` — optional Tool definitions and the strategy for picking among them. `tool_choice` accepts `auto`, `none` and `required`. See [Tool calling](#tool-calling). ### `response_format` — object, optional A JSON Schema with `strict: true` constrains the **answer** field. Parse that field, not `reasoning_content`, which is prose. ### `group` — string, default `"default"` Token group on the gateway. Leave it at `default` unless your account has been given another group to route through. *** ## Reasoning **This model always reasons.** Moonshot's own FAQ answers "how do I turn off the chain of thought" with a flat *you can't*. There is no thinking toggle; the lever is effort. `reasoning_effort` takes **three** rungs and defaults to the most expensive one: | Level | Use it for | | ------ | --------------------------------------------------------------------------------------------- | | `max` | **The default.** The hardest reasoning, where correctness outweighs cost. | | `high` | A step down that still reasons hard. | | `low` | Short, scoped, latency-sensitive work — and the answer to "the reasoning is taking too long". | There is no `medium`. **Pick the rung before the conversation starts.** Moonshot documents that switching effort levels **invalidates prefix-cache hits**, so flipping it mid-session silently throws away your cache. The K2-era `thinking` object is **not** a parameter on this model. If you are migrating from `kimi-k2.6` or `kimi-k2.7-code`, delete it and use top-level `reasoning_effort` instead. Code that already sends OpenAI's `reasoning_effort` needs no change beyond the accepted values. *** ## Parameters that are fixed Moonshot pins all five of these on this model. Passing any other value returns an error, so leave them out of the request entirely: | Parameter | Fixed at | | ------------------- | -------- | | `temperature` | `1.0` | | `top_p` | `0.95` | | `n` | `1` | | `presence_penalty` | `0` | | `frequency_penalty` | `0` | Steer with prompting and the `reasoning_effort` rung instead. *** ## Tool calling Two controls are specific to this generation. **`tool_choice: "required"`** forces at least one tool call on the turn — the way to stop an agent answering from memory when it was supposed to look something up. The K2 models reject this value; this one accepts it. **Dynamic tool loading** introduces a tool partway through a conversation: put its complete definition in a `system` message that carries `tools` and **no** `content`. It becomes available from that position onward. ```json { "role": "system", "tools": [ { "type": "function", "function": { "name": "calculate", "description": "Evaluate an arithmetic expression", "parameters": { "type": "object", "properties": { "expression": { "type": "string" } }, "required": ["expression"] } } } ] } ``` The server does **not** retain a dynamically loaded tool. Keep that `system` message in your request history or the tool disappears on the next turn. Include the complete `name`, `description` and `parameters` in the definition, and after executing calls, append one `tool` message per call with the matching `tool_call_id`. *** ## Visual input | Modality | Supported | | -------- | :-------: | | Text | ✅ | | Image | ✅ | | Video | ✅ | Output is **text only**. Vision is native to this model rather than a separate variant, which is what makes screenshot-driven work — frontend layout, game development, CAD — practical: it can look at what it just produced. **Public image URLs are not accepted.** Moonshot documents base64 data URIs, or a file reference from its own upload API, as the two ways in. `content` must also be an **array of parts**, not a serialized string. ```json { "role": "user", "content": [ { "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0..." } }, { "type": "text", "text": "Why does this layout break at 768px?" } ] } ``` Note that file references come from Moonshot's Files API, which the Chat Completions endpoint does not itself provide. *** ## Context caching Caching is **automatic** — no cache id, no TTL, no extra parameter. Keep a long prefix (system prompt, knowledge document, tool definitions) stable and repeat requests attempt a hit on their own. Two conditions decide whether that happens: * The **previous** request's prompt tokens must exceed **256**. Below that the request is not cached at all. * The `reasoning_effort` rung must not change — switching it invalidates the prefix cache. Put the fixed bulk at the front of `messages` and append the varying question after it. *** ## Pricing dimensions Billing is **per token**, in USD, against your `api.reapi.ai` balance, with separate **input** and **output** rates. Three things to keep in mind: * **Reasoning tokens bill as output.** Since this model always reasons, that is the usual reason a bill exceeds an estimate built from visible answer length. * **The rate is flat across context length.** Moonshot documents no long-context tier, so a million-token prompt costs the same per token as a short one. * **Effort moves the bill.** It is the only reasoning lever, and it defaults to the most expensive rung — so it is the first thing to tune. Both token rates sit **below Moonshot's published per-token rate**, output by a full fifth. Current numbers are on the [model page](https://reapi.ai/models/kimi-k3) and [api.reapi.ai/pricing](https://api.reapi.ai/pricing) — those tables are the canonical source, not this page. Chat models bill in USD on the gateway balance. They do **not** draw down the integer credits used by the media-generation endpoints on `reapi.ai/api/v1`. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1785000000, "model": "kimi-k3", "choices": [ { "index": 0, "message": { "role": "assistant", "reasoning_content": "...", "content": "..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 1204, "completion_tokens": 860, "total_tokens": 2064 } } ``` `reasoning_content` is a sibling of `content`, not a replacement for it — and it is the field you must carry into the next request. ### Streaming (`stream: true`) Server-sent events, each `data:` line carrying a `chat.completion.chunk`. Reasoning arrives in `choices[0].delta.reasoning_content` and the answer in `choices[0].delta.content`, terminated by `data: [DONE]`. *** ## Errors Failures use the gateway's standard envelope. See the [errors catalog](/docs/api/errors) for the full code list. Common cases: | Trigger | What to do | | ------------------------------------------------------ | ---------------------------------------------------- | | Missing or invalid bearer token | Create a key in the api.reapi.ai console | | Unknown `model` value | Send `kimi-k3` exactly | | `temperature` / `top_p` / `n` / penalty params present | Remove them; they are fixed on this model | | K2-era `thinking` object present | Remove it and use `reasoning_effort` | | `reasoning_effort` set to `medium` | Not a valid rung — use `low`, `high` or `max` | | A public image URL in an `image_url` part | Send a base64 data URI or an uploaded file reference | | `content` sent as a string for a multimodal turn | Make it an array of parts | | `max_completion_tokens` above the ceiling | Lower it; the documented ceiling is 1,048,576 | | Insufficient balance | Top up on the gateway | | Upstream rate limit | Retry with backoff, or route through another model | Moonshot flags its own `web_search` tool as **being updated** and does not recommend using it in the near term. Treat web search as unavailable on this model for now and supply fresh context yourself. *** ## Tips * **Give the whole task up front.** This model is built for long-horizon work under minimal supervision; a complete specification beats a drip-feed of short turns. * **Drop your sampling parameters first.** The single most common migration error here is a carried-over `temperature`. * **Tune effort before anything else.** The default is `max`; `low` exists precisely for the case where reasoning is costing more than the answer is worth. * **Budget for reasoning.** If responses truncate on hard prompts, the reasoning pass consumed the allowance — raise `max_completion_tokens`. * **Stream anything interactive**, and render `reasoning_content` separately from the answer rather than concatenating them. * **Keep the assistant message intact** in history. Stripping `reasoning_content` is silent — it does not error, it just degrades multi-turn behaviour. * **Front-load the stable bulk** of your prompt so automatic caching can hit, and do not change the effort rung mid-conversation. *** ## Related * [Kimi K3 model page](https://reapi.ai/models/kimi-k3) — current rates * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # kling-3-0-turbo (https://reapi.ai/docs/kling-3-0-turbo) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Kuaishou's Kling 3.0 Turbo on reAPI — the fast tier of Kling 3.0 for > **text-to-video** and **image-to-video** (first frame), at **720p** or > **1080p**. One async endpoint: submit returns a `task_id`; poll until ready. > See current pricing on the [model page](https://reapi.ai/models/kling-3-0-turbo). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kling-3-0-turbo", "prompt": "a corgi running on the beach, cinematic, golden hour", "resolution": "1080p", "aspect_ratio": "16:9", "duration": 5 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "kling-3-0-turbo", "prompt": "a corgi running on the beach, cinematic, golden hour", "resolution": "1080p", "aspect_ratio": "16:9", "duration": 5, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "kling-3-0-turbo", prompt: "a corgi running on the beach, cinematic, golden hour", resolution: "1080p", aspect_ratio: "16:9", duration: 5, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "kling-3-0-turbo", "prompt": "a corgi running on the beach, cinematic, golden hour", "resolution": "1080p", "aspect_ratio": "16:9", "duration": 5, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "kling-3-0-turbo", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated video URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Modes There is no separate model id per modality — the modality is implicit in the request shape: * **Text-to-video** — no `first_frame_image`. `prompt` is required, and `aspect_ratio` applies. * **Image-to-video** — pass `first_frame_image` (a public HTTPS URL). The clip starts from that frame, `prompt` is optional, and `aspect_ratio` is ignored (the frame fixes the ratio). Multi-shot direction is expressed inside the `prompt` (describe each shot); there is no dedicated multi-shot field. *** ## Request body ### `model` — string, required Must be `kling-3-0-turbo`. ### `prompt` — string Up to **3,072 characters** (recommended ≤ 2,500). Required for text-to-video; optional in image-to-video (omit it to animate purely from the first frame). ### `first_frame_image` — string, optional Start frame for image-to-video. **Public HTTPS URL only** — base64 / `data:` URIs are rejected at the gateway. JPG / JPEG / PNG, ≤ 50 MB, ≥ 300 px, with an aspect ratio between 1:2.5 and 2.5:1. ### `resolution` — string, default `720p` Output clarity tier: `720p` or `1080p`. Billed per second at the tier's rate. ### `duration` — integer, default `5` Total video length in seconds, range `3–15`. Billed per second. ### `aspect_ratio` — string, default `16:9` One of `16:9`, `9:16`, `1:1`. **Text-to-video only.** When `first_frame_image` is supplied (image-to-video), this field has **no effect** — the output ratio is determined by the first frame. Set it only for text-to-video. ### `watermark` — boolean, optional Add a watermark to the output video. Omitted by default (no watermark). Modality is auto-detected: supply `first_frame_image` for image-to-video, omit it for text-to-video. You never set a mode flag. *** ## Pricing Kling 3.0 Turbo bills **per second**, by resolution tier (`resolution`): ``` credits = ceil(per_second_usd × seconds × 1000) ``` where `1 credit = $0.001 USD` and `seconds` is `duration`. The 1080p tier carries a higher per-second rate than 720p. Failed and rejected requests are not charged. The exact per-second credit cost for each tier surfaces on the [model page](https://reapi.ai/models/kling-3-0-turbo) and through the playground estimator before submit. *** ## Response The poll envelope returns the video URL in `output.video_urls`: ```json { "id": "task_019dfd44b7fd74168541552a3260a623", "model": "kling-3-0-turbo", "status": "completed", "output": { "video_urls": [ "https://cdn.reapi.ai/...mp4" ] } } ``` Generated URLs expire — mirror them to your own storage if you need long-term retention. *** ## Errors Failures return the standard reAPI envelope `{ error: { code, message, request_id } }`. Common cases: * Invalid input (prompt over 3072 chars, out-of-range `duration`, a non-HTTPS `first_frame_image`, an invalid `resolution` or `aspect_ratio`) → `400`. * Insufficient credits → `402`. * Rate limited → `429`. See the full catalog at [/docs/api/errors](/docs/api/errors). *** ## Tips * Use cinematic language in the prompt (shot type, camera move, lighting) — Kling 3.0 Turbo reads it; there is no dedicated camera-control parameter. * Draft at `720p` to iterate cheaply, then re-run the winner at `1080p` for delivery — same call, one parameter change. * For image-to-video, the first frame fixes the aspect ratio, so you can skip `aspect_ratio` in that mode. * Reach for the full [Kling 3.0](/docs/kling-3-0) when you need multi-shot control, native audio, or 4K; Kling 3.0 Turbo trades those for speed and a lower per-second cost. *** ## Related * [Kling 3.0](/docs/kling-3-0) * [Video generation models](/docs/seedance-2-0) * [Tasks API](/docs/api/tasks) * [Error codes](/docs/api/errors) --- # kling-3-0 (https://reapi.ai/docs/kling-3-0) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Kuaishou's Kling 3.0 on reAPI — one async endpoint for **text-to-video**, > **image-to-video** (first/last frame), and **multi-shot** cinematic > sequences, with optional **native multilingual audio** and up to **4K**. > Submit returns a `task_id`; poll until ready. See current pricing on the > [model page](https://reapi.ai/models/kling-3-0). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kling-3-0", "prompt": "A soft anime-style girl in a field, warm sunset glow, smooth loop", "duration": 6, "aspect_ratio": "16:9", "mode": "pro" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "kling-3-0", "prompt": "A soft anime-style girl in a field, warm sunset glow, smooth loop", "duration": 6, "aspect_ratio": "16:9", "mode": "pro", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "kling-3-0", prompt: "A soft anime-style girl in a field, warm sunset glow, smooth loop", duration: 6, aspect_ratio: "16:9", mode: "pro", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "kling-3-0", "prompt": "A soft anime-style girl in a field, warm sunset glow, smooth loop", "duration": 6, "aspect_ratio": "16:9", "mode": "pro", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "kling-3-0", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated video URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Modes There is no separate model id per modality — the modality is implicit in the request shape: * **Text-to-video** — no `image_urls`. `prompt` is required. * **Image-to-video** — pass `image_urls`: index 0 is the start frame, index 1 (optional) is the end frame. Aspect ratio auto-adapts to the images. * **Multi-shot** — set `multi_shots: true` and provide `multi_prompt` (per-shot prompts + durations). The resolution tier (`std` 720p / `pro` 1080p / `4K`) is the `mode` field; native audio is the `sound` toggle. *** ## Request body ### `model` — string, required Must be `kling-3-0`. ### `prompt` — string Up to **2,500 characters**. Required for single-shot; superseded by `multi_prompt` in multi-shot mode. ### `image_urls` — array, optional First/last frame for image-to-video. **Public HTTPS URLs only** — base64 / `data:` URIs are rejected at the gateway. Up to **2** (index 0 = first frame, index 1 = last frame). ### `duration` — integer, default `5` Total video length in seconds, range `3–15`. Billed per second. ### `aspect_ratio` — string, default `16:9` One of `16:9`, `9:16`, `1:1`. Ignored (auto-adapted) when `image_urls` is supplied. ### `mode` — string, default `pro` Resolution tier: `std` (720p), `pro` (1080p), or `4K`. ### `sound` — boolean, default `false` Generate synchronized native audio (dialogue, lip sync, ambient sound). Audio tiers cost more per second. ### `multi_shots` — boolean, default `false` Enable multi-shot mode (a connected sequence of shots). ### `multi_prompt` — array, optional (required when `multi_shots: true`) Up to **5** shots; each item is `{ "prompt": string, "duration": int }` where per-shot duration is **1–12s** and prompt is up to **500 chars**. ```json { "multi_shots": true, "multi_prompt": [ { "prompt": "a chef plating a dish, close-up", "duration": 4 }, { "prompt": "pull back to a busy restaurant", "duration": 5 } ] } ``` ### `kling_elements` — array, optional Up to **3** reusable `@`-referenced elements. Each item is `{ "name": string, "description"?: string, "element_input_urls": [string] }` with **2–4** image URLs (JPG/PNG). Reference an element in the prompt with `@name`. Multi-shot bills the **sum of the per-shot durations**; single-shot bills the top-level `duration`. *** ## Pricing Kling 3.0 bills **per second**, by resolution tier (`mode`) and whether audio is on (`sound`): ``` credits = ceil(per_second_usd × seconds × 1000) ``` where `1 credit = $0.001 USD`, and `seconds` is `duration` (single-shot) or the sum of `multi_prompt` durations (multi-shot). Higher tiers and audio carry a higher per-second rate. Failed and rejected requests are not charged. The exact per-second credit cost for each tier surfaces on the [model page](https://reapi.ai/models/kling-3-0) and through the playground estimator before submit. *** ## Response The poll envelope returns the video URL in `output.video_urls`: ```json { "id": "task_019dfd44b7fd74168541552a3260a623", "model": "kling-3-0", "status": "completed", "output": { "video_urls": [ "https://cdn.reapi.ai/...mp4" ] } } ``` Generated URLs expire — mirror them to your own storage if you need long-term retention. *** ## Errors Failures return the standard reAPI envelope `{ error: { code, message, request_id } }`. Common cases: * Invalid input (prompt over 2500 chars, out-of-range `duration`, a non-HTTPS media URL, more than 2 `image_urls`, more than 5 shots) → `400`. * Insufficient credits → `402`. * Rate limited → `429`. See the full catalog at [/docs/api/errors](/docs/api/errors). *** ## Tips * Use cinematic language in the prompt (shot type, camera move, lighting) — Kling 3.0 reads it; there is no dedicated camera-control parameter. * For sequences, prefer multi-shot over stitching separate requests — characters stay consistent across cuts. * For image-to-video, supply both a first and last frame to control the start and end of the motion. * Reach for `mode: "4K"` only when the destination needs it — the per-second rate is highest there. *** ## Related * [Video generation models](/docs/seedance-2-0) * [Grok Imagine Video 1.5](/docs/grok-imagine-video-1-5) * [Tasks API](/docs/api/tasks) * [Error codes](/docs/api/errors) --- # kling-motion-control (https://reapi.ai/docs/kling-motion-control) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Kling Motion Control transfers the motion from a **reference video** onto a > subject taken from a **reference image**. One async endpoint, two version > tiers (`kling-v3-motion-control`, `kling-v2-6-motion-control`), `std` or > `pro` quality. Billing is per second of the source video's server-probed > length. See current pricing on the > [model page](https://reapi.ai/models/kling-motion-control). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "kling-v3-motion-control", "prompt": "Keep the subject consistent, follow the reference motion, cinematic lighting", "image_url": "https://your-cdn.com/subject.png", "video_url": "https://your-cdn.com/motion-8s.mp4", "character_orientation": "image", "mode": "std", "keep_original_sound": "yes" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "kling-v3-motion-control", "prompt": "Follow the reference motion, keep the subject consistent", "image_url": "https://your-cdn.com/subject.png", "video_url": "https://your-cdn.com/motion-8s.mp4", "character_orientation": "image", "mode": "std", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "kling-v3-motion-control", prompt: "Follow the reference motion, keep the subject consistent", image_url: "https://your-cdn.com/subject.png", video_url: "https://your-cdn.com/motion-8s.mp4", character_orientation: "image", mode: "std", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "kling-v3-motion-control", "prompt": "Follow the reference motion, keep the subject consistent", "image_url": "https://your-cdn.com/subject.png", "video_url": "https://your-cdn.com/motion-8s.mp4", "character_orientation": "image", "mode": "std", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "kling-v3-motion-control", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URLs. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Version tiers Two `model` ids share the **exact same request shape** — pick one by the `model` string you POST: | `model` id | Tier | Notes | | --------------------------- | ---- | --------------------------------------------- | | `kling-v3-motion-control` | v3 | Latest — higher motion fidelity & consistency | | `kling-v2-6-motion-control` | v2.6 | Budget tier, lower per-second rate | Everything else in this page applies identically to both ids. See current per-second rates for each tier on the [model page](https://reapi.ai/models/kling-motion-control). *** ## Request body ### `model` — required `string`. One of `"kling-v3-motion-control"` or `"kling-v2-6-motion-control"`. ### `prompt` — required `string`. Refines the motion, camera, and style. The API rejects requests without a prompt — more specific prompts yield more stable results. ### `image_url` — required `string`. Public HTTP(S) URL of the **reference image** — the subject whose appearance and identity the output keeps. **No `data:` URIs.** reApi rejects base64 inputs platform-wide. Upload to public storage (your own CDN, S3, R2…) and pass the URL. ### `video_url` — required `string`. Public HTTP(S) URL of the **reference video** — the clip whose motion is transferred onto the subject. MP4 / MOV recommended, ≤ 100MB. The allowed source length depends on `character_orientation` (see below). The **billable second count is the source video's server-probed duration**, not a client estimate. ### `character_orientation` — required `string`. Controls whose facing the subject follows. | Value | Behavior | Source video length | | --------- | -------------------------------------- | ------------------- | | `"image"` | Facing follows the reference **image** | 3 – 10 seconds | | `"video"` | Facing follows the reference **video** | 3 – 30 seconds | ### `mode` — required `string`. Quality / cost tier. | Value | Behavior | | ------- | ------------------------------------------------- | | `"std"` | Standard — balances speed and quality | | `"pro"` | Pro — higher quality, usually slower; higher rate | ### `keep_original_sound` — string, default `"yes"` Whether to retain the reference video's original audio track. | Value | Behavior | | ------- | --------------------------------- | | `"yes"` | Keep the original audio (default) | | `"no"` | Drop the original audio | ### `watermark_info` — object Watermark control. Default disabled. ```json { "watermark_info": { "enabled": false } } ``` | Field | Type | Default | Behavior | | --------- | ------- | ------- | --------------- | | `enabled` | boolean | `false` | Add a watermark | *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "kling-v3-motion-control", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | *** ## Pricing Per-second × `mode`. The billable second count is the source video's **server-probed** length — reApi measures the uploaded clip server-side rather than trusting a client value. `kling-v3-motion-control` and `kling-v2-6-motion-control` have separate per-second rates, and `pro` costs more than `std`. **Bill formula** (1 credit = $0.001): ``` billable_seconds = ceil(server_probed_source_seconds) bill_usd = per_second_usd(tier, mode) × billable_seconds credits = ceil(bill_usd × 1000) ``` See current per-second rates for each tier and mode on the [model page](https://reapi.ai/models/kling-motion-control). Failed jobs refund automatically. A probe failure returns `400 PRICING_UNAVAILABLE` (code `30002`) with no charge. The playground's draft estimate may show a default before the upload finishes — the authoritative number is computed at submit, after the server probes the file. *** ## Validation errors All cases below return HTTP 400. Pattern-match on `code`, not `message` — message strings carry request-specific context and are not a stable contract. | Trigger | Code | Message (illustrative) | | -------------------------------------------------- | ------- | -------------------------------------------------------------- | | `image_url` missing | `20002` | `kling-motion-control: image_url is required` | | `video_url` missing | `20002` | `kling-motion-control: video_url is required` | | `character_orientation` missing / invalid | `20003` | `kling-motion-control: invalid character_orientation` | | `mode` missing / invalid | `20003` | `kling-motion-control: invalid mode (allowed: std / pro)` | | `keep_original_sound` invalid | `20003` | `kling-motion-control: invalid keep_original_sound` | | `image_url` / `video_url` carrying a `data:` URI | `20003` | `kling-motion-control: image_url must be a public http(s) URL` | | Source video probe fails (network / format) | `30002` | `Could not determine source video duration for billing: …` | | Source video length outside the orientation window | `80007` | Provider rejected the request as invalid | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### Minimum request (image orientation) ```json { "model": "kling-v3-motion-control", "prompt": "Follow the reference motion, keep the subject consistent", "image_url": "https://your-cdn.com/subject.png", "video_url": "https://your-cdn.com/motion-8s.mp4", "character_orientation": "image", "mode": "std" } ``` ### Video orientation, pro quality, up to 30s ```json { "model": "kling-v3-motion-control", "prompt": "Follow the reference performance and rhythm, keep motion continuous", "image_url": "https://your-cdn.com/subject.png", "video_url": "https://your-cdn.com/motion-20s.mp4", "character_orientation": "video", "mode": "pro", "keep_original_sound": "no" } ``` ### Budget tier, watermark off ```json { "model": "kling-v2-6-motion-control", "image_url": "https://your-cdn.com/subject.png", "video_url": "https://your-cdn.com/motion-6s.mp4", "character_orientation": "image", "mode": "std", "watermark_info": { "enabled": false } } ``` *** ## Tips * **Match the clip to the orientation.** `character_orientation: "image"` caps the reference video at 10s; use `"video"` when you need up to 30s. * **Cost tracks the source clip.** A 5s reference video bills \~5 seconds; trim the input to control spend. * **Prompt the motion, not just the scene.** Phrasing the action ("turns and waves, smooth and continuous") sharpens the transfer. * **Start on `std`, escalate to `pro`.** Validate the motion on the cheaper mode, then re-run on `pro` for the final take. * **Pick the tier by budget.** `kling-v2-6-motion-control` is the cheaper run; `kling-v3-motion-control` maximizes fidelity and subject consistency. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # midjourney-v7 (https://reapi.ai/docs/midjourney-v7) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Midjourney V7 on reAPI. **Four images per request**, native MJ prompt > syntax (`--ar`, `--s`, `--chaos`, `--sref`, `--oref`, …), and **eleven edit > operations** that chain off any generated image. Async-first: submit > returns a `task_id`; poll until ready. See current pricing on the > [model page](https://reapi.ai/models/midjourney-v7). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "mj-v7", "prompt": "a serene Japanese garden with cherry blossoms --ar 16:9 --s 500", "model_params": { "speed": "fast" } }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "mj-v7", "prompt": "a serene Japanese garden with cherry blossoms --ar 16:9 --s 500", "model_params": {"speed": "fast"}, }, timeout=30, ) task_id = resp.json()["id"] ``` ```javascript const resp = await fetch('https://reapi.ai/api/v1/images/generations', { method: 'POST', headers: { Authorization: 'Bearer rk_live_xxx', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'mj-v7', prompt: 'a serene Japanese garden with cherry blossoms --ar 16:9 --s 500', model_params: { speed: 'fast' }, }), }); const { id } = await resp.json(); ``` ```go body := strings.NewReader(`{ "model": "mj-v7", "prompt": "a serene Japanese garden with cherry blossoms --ar 16:9 --s 500", "model_params": { "speed": "fast" } }`) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", body) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) ``` Generation is asynchronous. The call returns a `task_id`; poll `GET /api/v1/tasks/:task_id` until `status` is `completed`, then read the image URLs. Each request returns **1–4 images** (content review may filter some) and is billed **once per request**. ## Endpoint ``` POST https://reapi.ai/api/v1/images/generations GET https://reapi.ai/api/v1/tasks/:task_id ``` | Header | Value | | --------------- | -------------------- | | `Authorization` | `Bearer rk_live_xxx` | | `Content-Type` | `application/json` | reAPI accepts only **public http(s) image URLs** for every image input — never base64 or `data:` URIs. For image-to-image, place the URL at the start of the `prompt`; for the direct-image edits, pass it in `image_urls`. ## Models The family is one base generator plus eleven edit operations. Each is a separate `model` id on the same endpoint. | `model` | Operation | References a prior task? | | -------------------- | ------------------------------- | -------------------------------- | | `mj-v7` | Text-to-image / image-to-image | — | | `mj-v7-variation` | Subtle/strong variations | yes (`task_id` + `image_number`) | | `mj-v7-upscale` | Upscale one image | yes | | `mj-v7-remix` | Re-prompt an image | yes | | `mj-v7-enhance` | Enhance a draft image | yes (draft tasks only) | | `mj-v7-pan` | Extend the canvas directionally | yes | | `mj-v7-outpaint` | Zoom out / extend the frame | yes | | `mj-v7-inpaint` | Repaint a masked region | yes | | `mj-v7-edit` | Canvas edit (reposition + fill) | yes | | `mj-v7-remove-bg` | Remove background | no (`image_urls`) | | `mj-v7-retexture` | Re-texture / restyle | no (`image_urls`) | | `mj-v7-upload-paint` | Upload + masked repaint | no (`image_urls`) | The eight parent-referencing edits take the reAPI `task_id` of a **completed Midjourney V7 generation** in `model_params.task_id`, plus `model_params.image_number` (0–3) to pick which of the four grid images to act on. reAPI resolves your task id to the upstream reference automatically. ## Base generation — `mj-v7` | Field | Type | Required | Default | Notes | | -------------------- | ------ | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | — | `mj-v7` | | `prompt` | string | yes | — | Native MJ syntax, ≤ 8192 chars. Image-to-image: place public image URL(s) at the start. A single image with no text is rejected. | | `model_params.speed` | string | no | `fast` | `draft` / `fast` / `turbo` | Native MJ parameters are written **inside the prompt**, not as JSON fields: | Flag | Range | Default | Meaning | | ----------------- | ------------ | ------- | ------------------------------ | | `--ar W:H` | any ratio | `1:1` | Aspect ratio | | `--s` | 0–1000 | 100 | Stylize | | `--chaos` / `--c` | 0–100 | 0 | Variation spread | | `--no` | keywords | — | Negative prompt | | `--seed` | 0–4294967295 | random | Reproducible seed | | `--weird` / `--w` | 0–3000 | 0 | Unconventional degree | | `--exp` | 0–100 | 0 | Experimental aesthetic (V7) | | `--raw` | flag | off | Disable default beautification | | `--tile` | flag | off | Seamless tile | | `--sref [URL]` | URL | — | Style Reference | | `--sw` | 0–1000 | 100 | Style weight | | `--sv` | 1–6 | 4 | Style version | | `--oref [URL]` | URL | — | Omni Reference (doubles cost) | | `--ow` | 1–1000 | 100 | Omni Reference weight | | `--iw` | 0–3 | 1 | Image-prompt weight | `--v` / `--version` / `--niji` are ignored (the version is locked to V7). Speed is set via `model_params.speed`, not a prompt flag. ## Edit operations All edits share the endpoint and the async `task_id` lifecycle. `speed` (where present) is `fast` / `turbo` (default `fast`). ### Parent-referencing edits Common `model_params`: `task_id` (required, the reAPI task id of a completed Midjourney V7 generation), `image_number` (0–3, default 0). | `model` | Extra `model_params` | Top-level `prompt` | | ----------------- | ------------------------------------------------------------------------------------------------------- | ------------------ | | `mj-v7-variation` | `type`: `subtle` \| `strong` (default `subtle`); `speed` | optional | | `mj-v7-upscale` | `type`: `standard` \| `creative` (default `standard`) | — | | `mj-v7-remix` | `mode`: `strong` \| `subtle` (default `strong`); `speed` | **required** | | `mj-v7-enhance` | — (parent must be a `draft` task) | — | | `mj-v7-pan` | `direction`: `down` \| `right` \| `up` \| `left` (default `down`); `scale` 1.1–3 (default 1.5); `speed` | optional | | `mj-v7-outpaint` | `scale` 1.1–2 (default 1.5); `speed` | optional | | `mj-v7-inpaint` | `mask` (required); `speed` | optional | | `mj-v7-edit` | `canvas` (required); `img_pos` (required); `mask` (optional); `speed` | **required** | `mask` is one of two shapes (mutually exclusive): ```json { "mask": { "areas": [ { "width": 200, "height": 200, "points": [50,50,50,250,250,250,250,50] } ] } } ``` ```json { "mask": { "url": "https://example.com/mask.png" } } ``` `points` is a flat `[x1,y1,x2,y2,…]` closed polygon; for the URL form, white = repaint region, black = preserve. `canvas` is `width` / `height` (px); `img_pos` is `width` / `height` / `x` / `y` (placement of the source image on the canvas). Example — upscale image 0 of a prior generation: ```json { "model": "mj-v7-upscale", "model_params": { "task_id": "task_xxx", "image_number": 0, "type": "standard" } } ``` ### Direct-image edits These take the source image in `image_urls` (exactly one public http(s) URL) and do not reference a prior task. | `model` | Required | `model_params` | | -------------------- | ---------------------- | --------------------------------------------------------------------- | | `mj-v7-remove-bg` | `image_urls` | — | | `mj-v7-retexture` | `prompt`, `image_urls` | `speed` (optional) | | `mj-v7-upload-paint` | `prompt`, `image_urls` | `mask` (required), `canvas` (required), `img_pos` (required), `speed` | ## Pricing Midjourney V7 bills **per request** (four images), not per image. Cost scales with: * **Speed tier** — `draft` \< `fast` \< `turbo`. * **Operation** — base generation and lightweight edits (remove-bg, pan, outpaint, enhance) cost less than heavy edits (upscale, variation, remix, inpaint, canvas edit, retexture, upload-paint). * **`--oref`** — Omni Reference in the prompt **doubles** the cost. Integer credits, `1 credit = $0.001`: ``` credits = ceil(request_price_usd × 1000) ``` where `request_price_usd` is the (model, speed) rate, doubled when the prompt carries `--oref`. See the [model page](https://reapi.ai/models/midjourney-v7) for current rates. ## Output Poll `GET /api/v1/tasks/:task_id`. On `completed`: ```json { "id": "task_xxx", "status": "completed", "output": { "image_urls": ["https://cdn.reapi.ai/.../0.png", "https://cdn.reapi.ai/.../1.png"] } } ``` `output.image_urls` holds 1–4 URLs (content review may filter some of the four). Save them promptly. ## Errors Customer-facing errors use the standard envelope `{ error: { code, message, request_id } }`. Common cases: | Situation | Code | | ----------------------------------------------------- | -------------------------- | | Prompt rejected by content review | `CONTENT_POLICY_VIOLATION` | | Malformed / out-of-range request | `INVALID_REQUEST` | | Referenced task not found / not yours / not completed | `INVALID_REQUEST` | | Insufficient credits | `INSUFFICIENT_CREDITS` | | Upstream generation failed | `UPSTREAM_ERROR` | See the full catalog at [/docs/api/errors](/docs/api/errors). ## Tips * A single reference image with no text is rejected — add a short description. * Use `--oref` for subject consistency and `--sref` for style transfer; they combine. `--oref` doubles the bill, so reserve it for shots that need it. * Generate with `mj-v7` first, then chain `mj-v7-upscale` / `mj-v7-variation` / `mj-v7-inpaint` off the returned `task_id` — no re-upload needed. * `mj-v7-enhance` only accepts a parent created with `speed: "draft"`. * Keep the version implicit — `--v` / `--niji` are ignored on V7. ## Related * [Model page & live playground](https://reapi.ai/models/midjourney-v7) * [API quickstart](/docs/api/quickstart) * [Error codes](/docs/api/errors) --- # midjourney-v8 (https://reapi.ai/docs/midjourney-v8) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Midjourney V8 on reAPI. One `midjourney` model with an `action` parameter > covering generation, blend, edit, and the upscale / variation / zoom / pan / > reroll / reshape toolkit; a separate `midjourney-video` model animates a > still into a short clip. Async-first: submit returns a `task_id`; poll until > ready. See current pricing on the > [model page](https://reapi.ai/models/midjourney-v8). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "midjourney", "prompt": "a serene Japanese garden with cherry blossoms, painterly", "version": "8.1", "size": "16:9", "speed": "fast" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "midjourney", "prompt": "a serene Japanese garden with cherry blossoms, painterly", "version": "8.1", "size": "16:9", "speed": "fast", }, timeout=30, ) task_id = resp.json()["data"][0]["task_id"] ``` ```javascript const resp = await fetch('https://reapi.ai/api/v1/images/generations', { method: 'POST', headers: { Authorization: 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'midjourney', prompt: 'a serene Japanese garden with cherry blossoms, painterly', version: '8.1', size: '16:9', speed: 'fast', }), }); const { data } = await resp.json(); ``` ```go body := strings.NewReader(`{ "model": "midjourney", "prompt": "a serene Japanese garden with cherry blossoms, painterly", "version": "8.1", "size": "16:9", "speed": "fast" }`) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", body) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) ``` Generation is asynchronous. The call returns a `task_id`; poll `GET /api/v1/tasks/:task_id` until `status` is `completed`, then read the image URLs. Generation returns **1–4 images** (content review may filter some) and is billed **once per request**. ## Endpoint ``` POST https://reapi.ai/api/v1/images/generations # midjourney (image) POST https://reapi.ai/api/v1/videos/generations # midjourney-video GET https://reapi.ai/api/v1/tasks/:task_id ``` | Header | Value | | --------------- | --------------------- | | `Authorization` | `Bearer YOUR_API_KEY` | | `Content-Type` | `application/json` | reAPI accepts only **public http(s) URLs** for every media input (`image_urls`, `cref`, `sref`, `dref`, `mask_url`, …) — never base64 or `data:` URIs. ## Operations — `action` `midjourney` runs one operation per request, selected by `action` (default `imagine`). All share the images endpoint. | `action` | Operation | References a prior task? | | ---------------- | ------------------------------- | ------------------------- | | `imagine` | Text-to-image / image-to-image | — | | `blend` | Fuse 2–4 images | — | | `edits` | Rewrite an image from a prompt | — | | `upscale` | Upscale one tile | yes (`task_id` + `index`) | | `variation` | Variations of one tile | yes | | `high_variation` | Strong variation | yes | | `low_variation` | Subtle variation | yes | | `reroll` | Re-roll the whole grid | yes (`task_id`) | | `zoom` | Zoom out / outpaint | yes | | `pan` | Extend the canvas directionally | yes | | `remix_strong` | Strong reshape (v8.1 / v8.2) | yes (`task_id` + `index`) | | `remix_subtle` | Subtle reshape (v8.1 / v8.2) | yes | The parent-referencing actions take the reAPI `task_id` of a **completed `midjourney` task** plus `index` (1–4) to pick which grid image to act on. reAPI resolves your task id to the upstream reference automatically. ## Generate — `action: "imagine"` | Field | Type | Required | Default | Notes | | ------------ | --------- | -------- | --------- | --------------------------- | | `model` | string | yes | — | `midjourney` | | `action` | string | no | `imagine` | Operation selector | | `prompt` | string | yes | — | Image description | | `image_urls` | string\[] | no | — | Image-to-image reference(s) | | `speed` | string | no | `relax` | `relax` / `fast` / `turbo` | The structured parameters below are the JSON form of Midjourney's native `--flags`. You may also type the flags into `prompt`; a body field overrides the matching flag. Ranges mirror Midjourney exactly. | Field | Flag | Range / values | Notes | | ----------------- | ----------- | ------------------------------------------- | --------------------------------------- | | `size` | `--ar` | e.g. `16:9`, `1:1`, `9:16` | Aspect ratio | | `quality` | `--q` | `0.25` / `0.5` / `1` / `2` | Render quality | | `style` | `--style` | e.g. `raw` | Style preset | | `version` | `--v` | `8.2` / `8.1` / `7` / `6.1` / `5.2` / `5.1` | Model version | | `seed` | `--seed` | integer | Reproducible seed | | `negative_prompt` | `--no` | keywords | What to avoid | | `stylize` | `--s` | 0–1000 | Stylization strength | | `chaos` | `--c` | 0–100 | Grid variety | | `weird` | `--w` | 0–3000 | Unconventional degree | | `tile` | `--tile` | boolean | Seamless tile | | `niji` | `--niji` | boolean | Anime model (pair with `version` 7 / 6) | | `iw` | `--iw` | 0–3 | Image-prompt weight | | `cw` | `--cw` | 0–100 | Character-reference weight | | `sw` | `--sw` | 0–1000 | Style-reference weight | | `cref` | `--cref` | URL | Character reference | | `sref` | `--sref` | URL | Style reference | | `dref` | `--dref` | URL | Depth reference | | `dw` | `--dw` | 0–100 | Depth-reference weight | | `repeat` | `--repeat` | 2–40 | Repeat the prompt | | `raw` | `--raw` | boolean | Raw mode (v5.1+) | | `draft` | `--draft` | boolean | Draft mode (v7+) | | `hd` | `--hd` | boolean | HD (v8.1 / v8.2) | | `stop` | `--stop` | 10–100 | Stop early (v5–6.1 / niji 5–6) | | `extra` | any `--xxx` | string | Appended to the prompt verbatim | | `metadata` | — | object | Opaque, stored with the task | Online-verified versions: `8.2`, `8.1`, `7`, `6.1`, `5.2`, `5.1`, plus niji 7 / niji 6 (set `niji: true` with `version: "7"` or `"6"`). The version does not change the price. ## Follow-up operations All follow-ups share the images endpoint and the async `task_id` lifecycle. Common fields: `task_id` (required, a completed `midjourney` task), `index` (1–4, which grid image), `speed`. | `action` | Extra fields | Notes | | ------------------------------------------------ | ---------------------------- | ---------------------------------------------------------------------------------------------- | | `upscale` | `index` | Upscale one tile | | `variation` / `high_variation` / `low_variation` | `index` | Variation strength differs | | `reroll` | — | Re-rolls the whole grid (no `index`) | | `zoom` | `index`; `zoom_ratio` | Below 2 = 1.5× outpaint, 2 and up = 2× custom zoom | | `pan` | `index`; `direction` | `direction`: `left` / `right` / `up` / `down`; v6+ / niji 6 parents only (v5.x fails upstream) | | `remix_strong` / `remix_subtle` | `index` (required); `prompt` | v8.1 / v8.2 only | `blend` takes `image_urls` (2–4) and an optional aspect ratio: free-form `size` (any `w:h`) or three-step `dimensions` (`SQUARE` / `PORTRAIT` / `LANDSCAPE`); `size` overrides `dimensions`. `edits` takes `prompt` + `image_urls` plus the same structured params as `imagine`. Example — upscale tile 1 of a prior generation: ```json { "model": "midjourney", "action": "upscale", "task_id": "task_xxx", "index": 1 } ``` ## Image-to-video — `midjourney-video` Animate a still — or one image of a completed `midjourney` grid — into a short (\~5 second) clip on the videos endpoint. Supply exactly one of `image_urls` (a start frame; `prompt` required) or `task_id` (a completed `midjourney` task of yours; reAPI resolves it upstream automatically). | Field | Type | Required | Default | Notes | | -------------- | --------- | -------- | ----------------- | ---------------------------------------------------------------- | | `model` | string | yes | — | `midjourney-video` | | `image_urls` | string\[] | one of | — | Start frame (exactly one URL); requires `prompt` | | `task_id` | string | one of | — | Completed `midjourney` task to animate | | `index` | integer | no | — | `0`–`3` — which grid image (`task_id` path) | | `prompt` | string | no | parent prompt | Required with `image_urls`; optional with `task_id` | | `video_type` | string | no | `vid_1.1_i2v_480` | `vid_1.1_i2v_480` / `_720` / `_start_end_480` / `_start_end_720` | | `animate_mode` | string | no | `manual` | `manual` / `auto`; `auto` requires `task_id` + `index` | | `motion` | string | no | `high` | `low` / `high` | | `batch_size` | integer | no | `1` | `1` / `2` / `4` (clips returned) | | `end_url` | string | no | — | End frame (upgrades to a start-end type) | ## Pricing `midjourney` bills **per request** (a 4-image grid for generation; one image for upscale and the like). The bill depends only on: * **Operation tier** — generation vs every other image action. * **Speed** — `relax` / `fast` / `turbo`. The model version never changes the price. `midjourney-video` bills per resolution (480p / 720p) × `batch_size`. Integer credits, `1 credit = $0.001`: ``` credits = ceil(request_price_usd × 1000) # midjourney credits = ceil(clip_price_usd × batch_size × 1000) # midjourney-video ``` See the [model page](https://reapi.ai/models/midjourney-v8) for current rates. ## Output Poll `GET /api/v1/tasks/:task_id`. On `completed`: ```json { "id": "task_xxx", "status": "completed", "output": { "image_urls": ["https://cdn.reapi.ai/.../0.png", "https://cdn.reapi.ai/.../1.png"] } } ``` `output.image_urls` holds 1–4 URLs (content review may filter some). `midjourney-video` returns `output.video_urls`. Save them promptly. ## Errors Customer-facing errors use the standard envelope `{ error: { code, message, request_id } }`. Common cases: | Situation | Code | | ----------------------------------------------------- | -------------------------- | | Prompt rejected by content review | `CONTENT_POLICY_VIOLATION` | | Malformed / out-of-range request | `INVALID_REQUEST` | | Referenced task not found / not yours / not completed | `INVALID_REQUEST` | | Insufficient credits | `INSUFFICIENT_CREDITS` | | Upstream generation failed | `UPSTREAM_ERROR` | See the full catalog at [/docs/api/errors](/docs/api/errors). ## Tips * Generate with `imagine` first, then chain `upscale` / `variation` / `zoom` / `pan` / `remix_strong` off the returned `task_id` — no re-upload needed. * A body field overrides the matching `--flag` in the prompt, so pick one. * `relax` is the cheapest and the default; `fast` / `turbo` only change queue priority and price, not the visual result. * `remix_strong` / `remix_subtle` require a v8.1 / v8.2 parent; use the variation actions for older versions. * All references (`cref` / `sref` / `dref`, blend inputs) must be public http(s) URLs. ## Related * [Model page & live playground](https://reapi.ai/models/midjourney-v8) * [API quickstart](/docs/api/quickstart) * [Error codes](/docs/api/errors) --- # minimax-m3 (https://reapi.ai/docs/minimax-m3) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > MiniMax M3 is an open-weight model that pairs frontier coding and agentic > benchmarks with a 1M-token context window and native multimodal input — > exposed through api.reapi.ai as a drop-in OpenAI-compatible Chat > Completions endpoint. 1M context, 512K max output, native thinking, image > and video input, prompt caching, and tool use. The wire `model` id is > `minimax/minimax-m3`. Current rates live on the > [model page](https://reapi.ai/models/minimax-m3) and on > [api.reapi.ai/pricing](https://api.reapi.ai/pricing). ## Quick example ```bash curl https://api.reapi.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "minimax/minimax-m3", "group": "default", "messages": [ { "role": "user", "content": "Hello" } ], "stream": true, "max_tokens": 4096, "temperature": 1.0 }' ``` ```python from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.reapi.ai/v1", ) stream = client.chat.completions.create( model="minimax/minimax-m3", messages=[{"role": "user", "content": "Hello"}], stream=True, max_tokens=4096, temperature=1.0, extra_body={"group": "default"}, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ```js import OpenAI from "openai"; const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.reapi.ai/v1", }); const stream = await client.chat.completions.create({ model: "minimax/minimax-m3", messages: [{ role: "user", content: "Hello" }], stream: true, max_tokens: 4096, temperature: 1.0, // `group` is an api.reapi.ai-specific extension; pass via extra body. // @ts-expect-error — not part of the OpenAI types group: "default", }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); } ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "minimax/minimax-m3", "group": "default", "messages": []map[string]string{ {"role": "user", "content": "Hello"}, }, "stream": true, "max_tokens": 4096, "temperature": 1.0, }) req, _ := http.NewRequest("POST", "https://api.reapi.ai/v1/chat/completions", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Authentication Every request needs a Bearer token. The MiniMax M3 chat workspace lives on the `api.reapi.ai` platform — sign in there to create a key and top up tokens. 1. Open [api.reapi.ai](https://api.reapi.ai/) and sign in (or create an account). 2. Generate an API key under **API Keys**. 3. Top up tokens under **Top Up** (pay-as-you-go, billed in USD per 1M tokens — see [api.reapi.ai/pricing](https://api.reapi.ai/pricing)). ```http Authorization: Bearer YOUR_API_KEY ``` The chat surface (api.reapi.ai) is a **separate workspace** from the image/video/audio task gateway at `reapi.ai/api/v1/*`. Keys and balances do not cross over — a key issued on `reapi.ai/settings/apikeys` will not authenticate against `api.reapi.ai/v1/chat/completions`, and vice versa. *** ## Endpoint ```http POST https://api.reapi.ai/v1/chat/completions ``` Drop-in for the OpenAI SDKs — same request shape, same SSE wire format. Set `base_url` to `https://api.reapi.ai/v1` and `model` to `minimax/minimax-m3`. *** ## Request body ### `model` — string, required Must be `"minimax/minimax-m3"`. Echoed back in the response envelope. ### `messages` — array, required Conversation history as an array of message objects. Same shape as the OpenAI Chat Completions spec, plus content-parts for image and video input: ```json { "role": "system" | "user" | "assistant" | "tool", "content": "string OR content-parts array (text + image_url + video_url parts)" } ``` Multi-turn history is sent in chronological order — the last message is the one the model responds to. Strip a prior turn's reasoning content before re-sending it in `messages`. ### `max_tokens` — integer, default `4096` Upper bound on output tokens for this response, **including the chain-of-thought when MiniMax M3 is thinking**. The synchronous API supports up to **512K** output tokens (128K recommended) — set it generously for long-form or reasoning-heavy outputs. ### `stream` — boolean, default `false` When `true`, the response is streamed as server-sent events (SSE) with `Content-Type: text/event-stream`. Each event is a JSON delta in the OpenAI format, terminated by a `data: [DONE]` line. ### `temperature` — number, default `1` Sampling temperature. Lower values produce more deterministic output. ### `top_p` — number, default `0.95` Nucleus sampling cutoff. ### `tools` / `tool_choice` — optional Standard OpenAI tool-calling parameters. MiniMax M3 is tuned for agentic, multi-step workflows with reliable function calling and JSON output, and it can interleave reasoning with tool calls across a long run. ### `group` — string, default `"default"` api.reapi.ai-specific extension. Selects a token group on the gateway, which routes the request to a specific upstream channel pool. Omit if default routing is fine. *** ## Thinking MiniMax M3 is a native thinking model: it reasons before it answers and can interleave reasoning with tool calls during a multi-step run. Thinking is **adaptive by default** — the model reasons on hard tasks and answers directly on simple ones. When the model thinks, the chain-of-thought is returned in a `reasoning_content` field alongside `content`: ```json { "choices": [ { "index": 0, "message": { "role": "assistant", "reasoning_content": "Let me work through this step by step...", "content": "The final answer." }, "finish_reason": "stop" } ] } ``` For latency-sensitive or simple calls you can disable thinking for faster, cheaper responses. Strip `reasoning_content` from assistant messages before sending them back in a follow-up request — the chain-of-thought from a previous turn is not meant to be re-fed as input. *** ## Multimodal input MiniMax M3 is natively multimodal — send images and video alongside text via OpenAI content-parts: ```json { "model": "minimax/minimax-m3", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "What does this chart show?" }, { "type": "image_url", "image_url": { "url": "https://example.com/chart.png" } } ] } ] } ``` Video frames are passed the same way via `video_url` content-parts. Each image or video counts toward the input token budget based on its resolution and length. *** ## Prompt caching MiniMax M3 caches stable prompt prefixes. When a request reuses a cached prefix, those input tokens bill at a small fraction of the standard input rate — a big saving for agent loops and chatbots that replay long system prompts and tool schemas. The `usage.prompt_tokens_details.cached_tokens` field reports how many input tokens were served from cache. *** ## Response shape ### Non-streaming (`stream: false`) ```json { "id": "chatcmpl-018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "object": "chat.completion", "created": 1735000000, "model": "minimax/minimax-m3", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help you today?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21, "prompt_tokens_details": { "cached_tokens": 0 } } } ``` When the model thinks, `message.reasoning_content` carries the chain-of-thought alongside `content`. ### Streaming (`stream: true`) `Content-Type: text/event-stream`. Each `data:` line is a JSON delta in the OpenAI chunk format; the final event before `[DONE]` carries the `finish_reason` (`stop` / `length` / `tool_calls` / `content_filter`). *** ## Pricing MiniMax M3 is billed **pay-as-you-go in USD** against your api.reapi.ai token balance. It bills along three dimensions — input tokens, output tokens, and cache-read tokens. Current rates live on [api.reapi.ai/pricing](https://api.reapi.ai/pricing) and in the pricing card at the top of the [model page](https://reapi.ai/models/minimax-m3). Per-call bill: ``` billable_input = (prompt_tokens - cached_tokens) × input_rate / 1,000,000 cache_read_bill = cached_tokens × cache_read_rate / 1,000,000 output_bill = completion_tokens × output_rate / 1,000,000 ``` Output tokens include the chain-of-thought when the model is thinking. Failed requests are not charged. *** ## Limits | Limit | Value | | ------------------- | ----------- | | Context window | 1M tokens | | Max output per call | 512K tokens | Streams that hit the output cap finish with `finish_reason: "length"`; call again with a continuation message if you need more text. *** ## Errors The error envelope follows the OpenAI shape — HTTP status, plus a JSON body: ```json { "error": { "message": "...", "type": "invalid_request_error", "code": "..." } } ``` Common cases: | Status | When | Notes | | ------ | ------------------------------------------ | -------------------------------------------- | | `400` | Bad request shape, unsupported param combo | Check the `messages` array and `model` id | | `401` | Missing / invalid API key | Re-issue a key at api.reapi.ai | | `402` | Insufficient balance | Top up at api.reapi.ai | | `429` | Per-group rate limit hit | Back off, or move to a different `group` | | `500` | Upstream / gateway error | Safe to retry — failed calls are not charged | api.reapi.ai does **not** internally retry chat requests. Every customer call maps to exactly one upstream POST. If a network error reaches you, that is a one-for-one wire failure and a retry from your side is safe; the gateway will not double-bill. *** ## Recipes ### Minimum request ```json { "model": "minimax/minimax-m3", "max_tokens": 4096, "messages": [ { "role": "user", "content": "Summarise this in three sentences." } ] } ``` ### Tool use (function calling) ```json { "model": "minimax/minimax-m3", "max_tokens": 4096, "messages": [ { "role": "user", "content": "What's the weather in Tokyo today?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Look up the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ], "tool_choice": "auto" } ``` ### Vision ```json { "model": "minimax/minimax-m3", "max_tokens": 4096, "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Read the error in this screenshot and suggest a fix." }, { "type": "image_url", "image_url": { "url": "https://your-cdn.com/screenshot.png" } } ] } ] } ``` ### Long-context analysis ```json { "model": "minimax/minimax-m3", "max_tokens": 8192, "messages": [ { "role": "system", "content": "" }, { "role": "user", "content": "List every mention of constraint X with line numbers." } ] } ``` Keep the long reference block stable across calls so the cache-read rate applies on subsequent requests. *** ## When to pick MiniMax M3 Pick MiniMax M3 when you want frontier coding and agentic capability at open-weight pricing: * **Long-horizon agentic coding** — multi-file refactors, tool-using agents, and runs that must stay on-task across many steps. * **Million-token analysis** — whole repositories, long research packs, and multi-document review in a single call. * **Multimodal workflows** — tasks that mix screenshots, diagrams, video, and code in one conversation. Route lighter traffic (classification, short replies, tight loops) to a cheaper model on the same key. *** ## Tips * **Set `max_tokens` generously when the task is hard.** The chain-of-thought counts toward the output budget; a low cap can truncate before the final answer. * **Strip `reasoning_content` before the next turn.** Re-feeding a prior turn's chain-of-thought as input is not supported. * **Stream by default for chat UX.** Streaming cuts perceived latency. * **Cache stable prefixes.** Reuse the same system prompt and tool schemas across calls to bill repeated input at the low cache-read rate. * **Disable thinking for simple, latency-sensitive calls.** Adaptive thinking already skips reasoning on easy prompts, but you can force it off when you never need the chain-of-thought. *** ## Related * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Errors catalog](/docs/api/errors) --- # Multistem Splitter API (https://reapi.ai/docs/multistem-splitter) # Multistem Splitter API Use `audio-multistem` to extract up to six supported stems from one public audio URL. ## Endpoint ```http POST /api/v1/audio/generations ``` Poll completion with: ```http GET /api/v1/tasks/{id} ``` ## Example ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer $REAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "audio-multistem", "audio_url": "https://cdn.example.com/song.wav", "stem_list": ["vocals", "drum", "bass"], "encoder_format": "mp3" }' ``` ## Parameters | Field | Type | Required | Notes | | ------------------ | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Use `audio-multistem`. | | `audio_url` | URL | yes | Public HTTP(S) source audio URL. | | `stem_list` | enum\[] | yes | 1-6 values: `vocals`, `drum`, `piano`, `bass`, `electric_guitar`, `acoustic_guitar`. | | `splitter` | enum | no | `auto`, `andromeda`, `perseus`, `orion`, `phoenix`, `lyra`, or `lynx`. `auto` is omitted upstream so the default engine is used. | | `extraction_level` | enum | no | `deep_extraction` or `clear_cut`. Defaults to `deep_extraction`. | | `dereverb_enabled` | boolean | no | Enable dereverb cleanup. | | `encoder_format` | enum | no | `mp3`, `wav`, `flac`, `aac`, or `ogg`. | ## Output Completed tasks return `output.audio_urls` and, when available, labeled `output.tracks`. Multistem jobs are billed per rounded-up source minute, multiplied by the selected stem count. See current rate on the [Multistem Splitter model page](https://reapi.ai/models/multistem-splitter). --- # Mureka V9 Song API (https://reapi.ai/docs/mureka-v9-song) # Mureka V9 Song API Use `mureka-v9-song` to turn written lyrics into one or more fully produced songs. Each call is asynchronous: submit the task, poll for completion, then fetch the rendered audio from the returned URLs. ## Endpoint ```http POST /api/v1/audio/generations ``` Poll completion with: ```http GET /api/v1/tasks/{id} ``` The task stays in `processing` until the song is rendered; final URLs land in `output.audio_urls` when the status flips to `completed`. ## Example ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer $REAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "mureka-v9-song", "lyrics": "Verse 1...\nChorus...\nVerse 2...", "prompt": "Emotional pop ballad with piano, warm strings, cinematic chorus, expressive female vocal, polished modern production", "number_of_songs": 1, "output_format": "mp3" }' ``` ## Parameters | Field | Type | Required | Notes | | ----------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `mureka-v9-song`. | | `lyrics` | string | yes | Lyrics for the song. Up to 3000 characters. | | `prompt` | string | no | Optional style prompt — genre, mood, instrumentation, vocal tone, tempo, production feel. Up to 1024 characters. | | `number_of_songs` | integer | no | `1`, `2`, or `3`. Defaults to `1`. Each additional song multiplies the per-request cost. | | `output_format` | enum | no | `mp3`, `wav`, or `flac`. Defaults to `mp3`. | | `reference_id` | string | no | Optional Mureka reference-track ID for tighter style guidance. | | `vocal_id` | string | no | Optional Mureka vocal-reference ID. | | `melody_id` | string | no | Optional Mureka melody-reference ID. | The three reference IDs are minted by Mureka's own upload system. ReAPI forwards them verbatim and does not proxy uploads — bring an ID you already have, or omit them entirely for fully generated songs. ## Output Successful tasks return one URL per generated song in `output.audio_urls`. With `number_of_songs: 3` the array contains three URLs, all in the same format selected by `output_format`. ## Pricing Billed per generated song. Only `number_of_songs` affects pricing — `prompt`, `output_format`, and the three reference IDs are free to use. See current rates on the [Mureka V9 model page](https://reapi.ai/models/mureka-v9-song). ## Tips * Structure lyrics with clear `Verse` / `Chorus` / `Bridge` blocks for better arrangement. * Use the style prompt to pin genre, tempo, and vocal character — Mureka follows these strongly. * Set `number_of_songs > 1` when you want quick variations from the same lyrics. * Use a reference ID only when you want the model to track a specific vocal or melody — without one it composes freely from the lyrics + prompt. * Stick with `mp3` while iterating; switch to `wav` or `flac` for final mastering. --- # Music Extractor API (https://reapi.ai/docs/music-extractor) # Music Extractor API Use `audio-music-extractor` to extract background music from a public source audio URL. ## Endpoint ```http POST /api/v1/audio/generations ``` Poll completion with: ```http GET /api/v1/tasks/{id} ``` ## Example ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer $REAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "audio-music-extractor", "audio_url": "https://cdn.example.com/mix.wav", "encoder_format": "mp3" }' ``` ## Parameters | Field | Type | Required | Notes | | ------------------ | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Use `audio-music-extractor`. | | `audio_url` | URL | yes | Public HTTP(S) source audio URL. | | `splitter` | enum | no | `auto`, `andromeda`, `perseus`, `orion`, `phoenix`, `lyra`, or `lynx`. `auto` is omitted upstream so the default engine is used. | | `dereverb_enabled` | boolean | no | Enable dereverb cleanup. | | `encoder_format` | enum | no | `mp3`, `wav`, `flac`, `aac`, or `ogg`. | ## Output Completed tasks return `output.audio_urls` and, when available, labeled `output.tracks`. Audio jobs are billed per rounded-up source minute. See current rate on the [Music Extractor model page](https://reapi.ai/models/music-extractor). --- # music-video-1-0 (https://reapi.ai/docs/music-video-1-0) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Music Video 1.0 turns a **song** into a **music video**. Pass an audio > track plus **1-7 reference images** (the visual style/model) and the API > returns a video synced to the song. One async endpoint, five aspect ratios, > up to 1080P, optional burned-in subtitles. Billing is per second of the > song's server-probed length. See current pricing on the > [model page](https://reapi.ai/models/music-video-1-0). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "music-video-1-0", "reference_image_urls": ["https://your-cdn.com/style.png"], "audio_url": "https://your-cdn.com/song.mp3", "aspect_ratio": "16:9", "resolution": "540P" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "music-video-1-0", "reference_image_urls": ["https://your-cdn.com/style.png"], "audio_url": "https://your-cdn.com/song.mp3", "aspect_ratio": "16:9", "resolution": "540P", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "music-video-1-0", reference_image_urls: ["https://your-cdn.com/style.png"], audio_url: "https://your-cdn.com/song.mp3", aspect_ratio: "16:9", resolution: "540P", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "music-video-1-0", "reference_image_urls": []string{"https://your-cdn.com/style.png"}, "audio_url": "https://your-cdn.com/song.mp3", "aspect_ratio": "16:9", "resolution": "540P", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "music-video-1-0", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required `string`. Must be `"music-video-1-0"`. ### `reference_image_urls` — required `string[]`. **1 to 7** public HTTP(S) image URLs (JPEG / PNG / WebP). These are the style / model references that fix the visual identity of the music video. **No `data:` URIs.** reApi rejects base64 inputs platform-wide. Upload to public storage (your own CDN, S3, R2…) and pass the URL. ### `audio_url` — required `string`. Public HTTP(S) URL of the **song** (MP3). The audio must be **10 to 300 seconds** (up to 5 minutes). The output music video length tracks the song, and the **billable second count is the song's server-probed duration**, not a client estimate. ### `aspect_ratio` — string, default `"16:9"` Output frame shape. | Value | Orientation | | -------- | ------------------- | | `"1:1"` | Square | | `"16:9"` | Landscape (default) | | `"9:16"` | Portrait | | `"4:3"` | Landscape | | `"3:4"` | Portrait | ### `resolution` — string, default `"540P"` Output clarity. Higher resolutions take longer to render. | Value | Notes | | --------- | ----------------- | | `"540P"` | Fastest (default) | | `"720P"` | Balanced | | `"1080P"` | Highest clarity | ### `name` — string, optional A label for the track. Shown on subtitles when `add_subtitle` is enabled. ### `prompt` — string, optional Up to **3000 characters**. Steers the visual style, mood, and scene direction of the music video. ### `add_subtitle` — boolean, default `false` Burn lyric subtitles into the music video. With `add_subtitle: true` and no `srt_url`, subtitles are generated from the song. ### `subtitle_color` — string, default `"#FFFFFF"` Hex color for burned-in subtitles (e.g. `"#FF0000"`). ### `srt_url` — string, optional Public HTTP(S) URL of a `.srt` subtitle file. Overrides auto-generated subtitles when `add_subtitle` is on. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "music-video-1-0", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ---------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds the MP4 | | `error` | object \| null | Populated on `failed` — `{ code, message }` | *** ## Pricing Flat **per second of the song**. The billable second count is the audio's **server-probed** length — reApi measures the uploaded track server-side rather than trusting a client value. **Bill formula** (1 credit = $0.001): ``` billable_seconds = min(ceil(server_probed_song_seconds), 300) bill_usd = per_second_usd × billable_seconds credits = ceil(bill_usd × 1000) ``` See the current per-second rate on the [model page](https://reapi.ai/models/music-video-1-0). Failed jobs refund automatically. A probe failure returns `400 PRICING_UNAVAILABLE` (code `30002`) with no charge. The playground's draft estimate may show a default before the upload finishes — the authoritative number is computed at submit, after the server probes the song. *** ## Validation errors All cases below return HTTP 400. Pattern-match on `code`, not `message` — message strings carry request-specific context and are not a stable contract. | Trigger | Code | Message (illustrative) | | -------------------------------------- | ------- | --------------------------------------------------------------- | | `reference_image_urls` missing / empty | `20002` | `reference_image_urls is required` | | More than 7 reference images | `20003` | `reference_image_urls accepts at most 7 items` | | `audio_url` missing | `20002` | `audio_url is required` | | `aspect_ratio` / `resolution` invalid | `20003` | `invalid aspect_ratio (allowed: 1:1 / 16:9 / 9:16 / 4:3 / 3:4)` | | `subtitle_color` not a hex color | `20003` | `subtitle_color must be a hex color like #FFFFFF` | | Any media field carrying a `data:` URI | `20003` | `audio_url must be a public http(s) URL` | | Song probe fails (network / format) | `30002` | `Could not determine source audio duration for billing: …` | | Song length outside the 10-300s window | `80007` | Provider rejected the request as invalid | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### Minimum request ```json { "model": "music-video-1-0", "reference_image_urls": ["https://your-cdn.com/style.png"], "audio_url": "https://your-cdn.com/song.mp3", "aspect_ratio": "16:9", "resolution": "540P" } ``` ### Portrait lyric video, 1080P, with subtitles ```json { "model": "music-video-1-0", "reference_image_urls": [ "https://your-cdn.com/style-1.png", "https://your-cdn.com/style-2.png" ], "audio_url": "https://your-cdn.com/song.mp3", "aspect_ratio": "9:16", "resolution": "1080P", "prompt": "Dreamy pastel anime style, soft lighting, visuals shift with each chorus", "add_subtitle": true, "subtitle_color": "#FFE0F0" } ``` ### Bring your own subtitle file ```json { "model": "music-video-1-0", "reference_image_urls": ["https://your-cdn.com/style.png"], "audio_url": "https://your-cdn.com/song.mp3", "aspect_ratio": "16:9", "resolution": "720P", "add_subtitle": true, "srt_url": "https://your-cdn.com/lyrics.srt" } ``` *** ## Tips * **Cost tracks the song.** A 90-second track bills \~90 seconds; trim the audio to control spend. Songs must be 10 to 300 seconds. * **Use reference images to lock the look.** Pass 1-7 style/model images; reuse the same set across tracks for a consistent channel aesthetic. * **Prompt the mood, not just the scene.** Phrasing the energy ("dynamic lights pulsing on the downbeat") sharpens the result. * **Subtitles, three ways.** Leave `add_subtitle` off for a clean cut, on for auto-generated lyrics, or supply your own `srt_url` for exact timing. * **Start at 540P.** Validate the look on the fastest tier, then re-run at 720P / 1080P for the final take. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # nano-banana-2-lite (https://reapi.ai/docs/nano-banana-2-lite) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Google DeepMind's Nano Banana 2 Lite (aka **Gemini 3.1 Flash-Lite Image**) on > reAPI — the speed-focused member of the Nano Banana family: fast **1K > text-to-image** and **prompt-based image editing** with up to 10 reference > images. Submit returns a `task_id`; poll until ready. See current pricing on > the [model page](https://reapi.ai/models/nano-banana-2-lite). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "nano-banana-2-lite", "prompt": "a pig on the grass, cinematic light", "aspect_ratio": "16:9" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "nano-banana-2-lite", "prompt": "a pig on the grass, cinematic light", "aspect_ratio": "16:9", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "nano-banana-2-lite", prompt: "a pig on the grass, cinematic light", aspect_ratio: "16:9", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "nano-banana-2-lite", "prompt": "a pig on the grass, cinematic light", "aspect_ratio": "16:9", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_019f25700fef760e879fc22ad9de512c", "model": "nano-banana-2-lite", "status": "processing", "created_at": 1783039530 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.image_urls` holds the generated image URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/images/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. The generation mode is implicit — there is no `mode` field: * **No `image_urls` (or an empty array)** → text-to-image. * **`image_urls` set** → prompt-based editing / reference-driven generation using up to 10 input images. Each request produces **exactly one 1K image** (no `n` parameter, no resolution control). *** ## Request body ### `model` — string, required Must be `nano-banana-2-lite`. ### `prompt` — string, required Up to **20,000 characters**. For text-to-image, describe subject, scene, style and composition. For editing, state the change you want ("replace the background with…", "make it nighttime, keep the subject unchanged"). ### `image_urls` — string\[], optional Up to **10 public http(s) image URLs** used as edit sources or visual references. Accepted types: JPEG, PNG, WebP; up to 30 MB per image. Omit it (or pass an empty array) for pure text-to-image. Base64 / `data:` URIs are rejected platform-wide — host the image on a public URL first. ### `aspect_ratio` — string, default `auto` One of `1:1`, `1:4`, `1:8`, `2:3`, `3:2`, `3:4`, `4:1`, `4:3`, `4:5`, `5:4`, `8:1`, `9:16`, `16:9`, `21:9`, `auto`. With `auto` the model chooses the ratio itself (for edits it follows the source image). *** ## Pricing Nano Banana 2 Lite bills a flat rate **per generated image**, independent of aspect ratio and mode (text-to-image and editing cost the same). Each request produces one image: ``` credits = ceil(per_image_usd × 1000) ``` where `1 credit = $0.001 USD`. It is one of the lowest per-image rates on the platform. Failed and rejected requests are not charged. The exact per-image credit cost surfaces on the [model page](https://reapi.ai/models/nano-banana-2-lite) and through the playground estimator before submit. *** ## Response The poll envelope returns the image URL in `output.image_urls`: ```json { "id": "task_019f25700fef760e879fc22ad9de512c", "model": "nano-banana-2-lite", "status": "completed", "output": { "image_urls": [ "https://cdn.reapi.ai/...jpeg" ] } } ``` Generated URLs expire — mirror them to your own storage if you need long-term retention. *** ## Errors Failures return the standard reAPI envelope `{ error: { code, message, request_id } }`. Common cases: * Invalid input (prompt over 20,000 characters, more than 10 `image_urls`, an unsupported `aspect_ratio`) → `400`. * Insufficient credits → `402`. * Rate limited → `429`. See the full catalog at [/docs/api/errors](/docs/api/errors). *** ## Tips * Nano Banana 2 Lite is the **speed tier** of the Nano Banana family — pick it for drafts, previews and high-volume 1K assets; step up to [Nano Banana 2](/docs/gemini-3-1-flash-image-preview) when you need 2K/4K output or maximum quality. * For edits, reference what should **stay unchanged** ("keep the furniture and composition unchanged") — the model is strong at targeted, consistent edits. * `aspect_ratio: "auto"` follows the source image on edits; set an explicit ratio when you need a fixed canvas (e.g. `16:9` thumbnails). *** ## Related * [Nano Banana 2](/docs/gemini-3-1-flash-image-preview) * [Nano Banana Pro](/docs/gemini-3-pro-image-preview) * [Z-Image](/docs/z-image) * [Tasks API](/docs/api/tasks) * [Error codes](/docs/api/errors) --- # pixverse-v6 (https://reapi.ai/docs/pixverse-v6) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Pixverse v6 — async video generation. **One model id** (`pixverse-v6`) and > one endpoint cover five modes: **text-to-video**, **image-to-video**, > **first/last-frame** transition, **multi-reference fusion**, and **video > extend**. Mode is implicit — the fields you send pick it. 1–15 second > outputs at 360p / 540p / 720p / 1080p, optional generated audio. See current > pricing on the [model page](https://reapi.ai/models/pixverse-v6). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "pixverse-v6", "prompt": "A neon-lit Tokyo alley at night, light rain, anamorphic flare", "size": "21:9", "resolution": "720p", "duration": 8 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "pixverse-v6", "prompt": "A neon-lit Tokyo alley at night, light rain, anamorphic flare", "size": "21:9", "resolution": "720p", "duration": 8, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "pixverse-v6", prompt: "A neon-lit Tokyo alley at night, light rain, anamorphic flare", size: "21:9", resolution: "720p", duration: 8, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "pixverse-v6", "prompt": "A neon-lit Tokyo alley at night, light rain, anamorphic flare", "size": "21:9", "resolution": "720p", "duration": 8, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "pixverse-v6", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URL, valid for 7 days. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Mode routing `pixverse-v6` picks its mode from **which fields you send** — there is no `mode` parameter. Matching is by priority; the first satisfied condition wins: | Send | Mode | What it does | | ---------------------------------------- | -------------------- | -------------------------------------------------------- | | `prompt` only | **Text-to-video** | Generate from text. `size` applies. | | `image_urls` | **Image-to-video** | Animate from a single starting frame (first used). | | `first_frame_image` + `last_frame_image` | **First/Last-frame** | Interpolate a transition between two frames. | | `img_references` | **Multi-reference** | Fuse 1–7 reference images into one clip. `size` applies. | | `extend_from_task_id` | **Video extend** | Continue a completed `pixverse-v6` clip. | **Field rules.** * `prompt` is **required** in every mode. * `first_frame_image` and `last_frame_image` must be sent **together**. * `img_references` accepts **1 to 7** entries. * First/Last-frame mode accepts only **5 or 8** second `duration`. * `size` is honored only in text-to-video and multi-reference fusion. *** ## Request body ### `model` — required `string`. Always `"pixverse-v6"`. ### `prompt` — string, required Up to **5,000 characters**. Required in every mode. Empty / whitespace-only prompts are treated as missing. ### `resolution` — string, default `"540p"` One of `360p` / `540p` / `720p` / `1080p`. Drives pricing. ### `duration` — integer, default `5` Output length in seconds. Any integer in `[1, 15]`. First/Last-frame mode accepts only `5` or `8`. Drives pricing linearly: `ceil(per_second_usd × duration × 1000)` credits (1 credit = $0.001). ### `size` — string, default `"16:9"` Output aspect ratio. Honored in **text-to-video** and **multi-reference fusion** only (other modes derive the ratio from the source media). One of: | Value | Shape | | ------ | -------------- | | `16:9` | Landscape | | `4:3` | Landscape 4:3 | | `1:1` | Square | | `3:4` | Portrait 3:4 | | `9:16` | Portrait | | `2:3` | Portrait 2:3 | | `3:2` | Landscape 3:2 | | `21:9` | Cinematic wide | ### `seed` — integer, default `0` Reproducibility hint. Range `[0, 2147483647]`. Same prompt plus seed returns a similar (not bit-for-bit identical) result. ### `negative_prompt` — string Up to **2,048 characters**. Describes content to keep out of the frame. ### `audio` — boolean, default `false` When `true`, the model synthesizes a soundtrack alongside the video. Audio **raises the per-second rate** (see Pricing). Default `false` is silent. ### `watermark` — boolean, default `false` When `true`, adds a watermark to the bottom-right corner. ### `motion_mode` — string `pixverse-v6` supports only `"normal"`. Other values are rejected upstream. ### `generate_multi_clip_switch` — boolean, default `false` When `true`, generates a multi-segment continuous video. Supported in **text-to-video** and **image-to-video** only. ### `image_urls` — string\[] (image-to-video) Public HTTP(S) URL array. The model uses the **first** entry as the starting frame. ### `first_frame_image` / `last_frame_image` — string (first/last-frame) Public HTTP(S) URLs. Must be sent **as a pair**; the model interpolates motion from the first frame to the last over a 5 or 8 second clip. ### `img_references` — string\[] (multi-reference fusion) **1 to 7** public HTTP(S) URLs. The model fuses subjects from each reference into one clip. ### `extend_from_task_id` — string (video extend) The reAPI task id (`task_...`) of one of **your own completed `pixverse-v6`** videos. Do not pass the upstream provider task id — reAPI resolves that internally before sending the extend request. The model continues the scene from where that clip ended. **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — every URL field on this endpoint must be a public HTTP(S) URL. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "pixverse-v6", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | `output.video_urls` URLs are valid for **7 days**. Re-host to your own storage if you need them longer. To extend a clip later, keep the task `id` — pass it as `extend_from_task_id`. *** ## Validation errors All cases below return HTTP 400. Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed values) and are not a stable contract. | Trigger | Code | Message (illustrative) | | ---------------------------------------------------- | ------- | ------------------------------------------------------------------ | | `prompt` missing / empty | `20002` | `prompt is required` | | `prompt` longer than 5,000 chars | `20007` | `prompt exceeds 5000 characters (got N)` | | Unknown `resolution` | `20003` | `invalid resolution "X" (allowed: 360p / 540p / 720p / 1080p)` | | `duration` outside `[1, 15]` | `20003` | `duration must be 1-15 seconds, got N` | | `duration` not 5/8 in first/last-frame mode | `20003` | `first-last-frame transition supports only 5 or 8 second duration` | | Only one of `first_frame_image` / `last_frame_image` | `20003` | `first_frame_image and last_frame_image must be provided together` | | `img_references` length > 7 | `20003` | `img_references supports at most 7 images, got N` | | `motion_mode` not `normal` | `20003` | `motion_mode must be "normal"` | | A URL field carrying a `data:` URI or non-http(s) | `20003` | `image_urls entries must be public http(s) URLs` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### Text-to-video — minimum request ```json { "model": "pixverse-v6", "prompt": "A corgi running through a sunflower field at golden hour" } ``` ### Text-to-video — full parameters ```json { "model": "pixverse-v6", "prompt": "A neon-lit Tokyo alley at night, light rain, anamorphic lens flare", "size": "21:9", "resolution": "720p", "duration": 8, "seed": 42, "audio": true } ``` ### Image-to-video — animate a single frame ```json { "model": "pixverse-v6", "prompt": "Camera slowly zooms in, gentle wind moves the leaves", "image_urls": ["https://your-cdn.com/first_frame.jpg"], "resolution": "540p", "duration": 5 } ``` ### First/Last-frame transition ```json { "model": "pixverse-v6", "prompt": "Transform smoothly from a puppy to a cat", "first_frame_image": "https://your-cdn.com/puppy.jpg", "last_frame_image": "https://your-cdn.com/cat.jpg", "resolution": "540p", "duration": 5 } ``` ### Multi-reference fusion ```json { "model": "pixverse-v6", "prompt": "A girl wearing the outfit from image 2, holding the cat from image 3", "img_references": [ "https://your-cdn.com/character.jpg", "https://your-cdn.com/outfit.jpg", "https://your-cdn.com/cat.jpg" ], "size": "9:16", "resolution": "720p", "duration": 5 } ``` ### Video extend ```json { "model": "pixverse-v6", "prompt": "The character now walks into a forest", "extend_from_task_id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "resolution": "540p", "duration": 5 } ``` *** ## Choosing a mode | Need | Send | | ------------------------------------ | -------------------------------------------------------- | | Generate from text | `prompt` only — `size` applies | | Animate a still | `prompt + image_urls` | | Smooth transition between two frames | `first_frame_image + last_frame_image` (duration 5/8) | | Combine subjects from several images | `prompt + img_references` (1–7) | | Continue an existing clip | `prompt + extend_from_task_id` | | Cut spend | Drop `resolution`, shorten `duration`, leave `audio` off | *** ## Polling pattern The task endpoint behaves identically to other video tasks — the completed `output` carries `video_urls`. A pragmatic schedule: ``` 0–5 minutes: poll every 5s 5 min – 1 h: back off gradually toward 1 min ≥ 1 h: cap at 3 min between polls ``` A typical task completes in a few minutes. *** ## Pricing Per-second × resolution. Turning **audio** on raises the per-second rate at every tier; every other parameter is free. See current rates on the [Pixverse v6 model page](https://reapi.ai/models/pixverse-v6). **Bill formula** (1 credit = $0.001): ``` credits = ceil(per_second_usd × duration × 1000) ``` Failed jobs refund automatically. *** ## Tips * **Prompt motion, not just scene.** "Slow push-in, warm tones, shallow depth of field" outperforms a pure noun-list of what's on screen. * **Keep references on-topic.** Multi-reference fusion works best when each image contributes a distinct, clearly-framed subject (a face, an outfit, a prop) rather than overlapping whole scenes. * **Two frames need to make sense as endpoints.** First/Last interpolation is smoothest when the two frames share enough subject and composition. * **Chain extends one beat at a time.** Build a longer sequence by extending the latest clip's task id repeatedly instead of asking for one long shot. * **Audio is opt-in here.** Leave `audio` off unless you need a soundtrack — it raises the per-second rate. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # qwen-image-2 (https://reapi.ai/docs/qwen-image-2) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Alibaba's Qwen Image 2 on reAPI — one async endpoint for **generation and > editing**. Write a prompt for **text-to-image**, or attach one source image > to **edit it in plain language**. Known for **structured in-image text** > (posters, slides, infographics, comics). Submit returns a `task_id`; poll > until ready. See current pricing on the > [model page](https://reapi.ai/models/qwen-image-2). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen-image-2", "prompt": "a vintage travel poster that reads VISIT MARS in bold retro type", "image_size": "16:9" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "qwen-image-2", "prompt": "a vintage travel poster that reads VISIT MARS in bold retro type", "image_size": "16:9", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "qwen-image-2", prompt: "a vintage travel poster that reads VISIT MARS in bold retro type", image_size: "16:9", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "qwen-image-2", "prompt": "a vintage travel poster that reads VISIT MARS in bold retro type", "image_size": "16:9", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "qwen-image-2", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.image_urls` holds the generated image URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/images/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Modes There is no `mode` field — the modality is implicit in the request shape: * **Text-to-image** — no `image_url`. `prompt` is required. * **Image editing** — pass a single `image_url`. `prompt` describes the change (background swap, object edit, restyle, in-frame text rewrite). Each request produces **exactly one image** — there is no `n` parameter. *** ## Request body ### `model` — string, required Must be `qwen-image-2`. ### `prompt` — string, required Up to **800 characters**. Required for both text-to-image and editing. ### `image_url` — string, optional A single source image for editing. **Public HTTPS URL only** — base64 / `data:` URIs are rejected at the gateway. Passing it switches the request to editing mode; omit it for text-to-image. ### `image_size` — string, optional, default `16:9` Output aspect ratio. * **Text-to-image** accepts: `1:1`, `3:4`, `4:3`, `9:16`, `16:9`. * **Editing** additionally accepts: `2:3`, `3:2`, `21:9`. `2:3`, `3:2`, and `21:9` are **editing-only**. Requesting one without an `image_url` (text-to-image) is rejected with `400`. ### `output_format` — string, optional, default `png` One of `png` or `jpeg`. ### `seed` — integer, optional The same seed with the same prompt yields a repeatable result. ### `nsfw_checker` — boolean, optional, default `false` Enables upstream content moderation. Off by default. *** ## Pricing Qwen Image 2 bills a flat rate **per generated image**, independent of modality, resolution, and aspect ratio. Each request produces one image: ``` credits = ceil(per_image_usd × 1000) ``` where `1 credit = $0.001 USD`. Failed and rejected requests are not charged. The exact per-image credit cost surfaces on the [model page](https://reapi.ai/models/qwen-image-2) and through the playground estimator before submit. *** ## Response The poll envelope returns the image URL in `output.image_urls`: ```json { "id": "task_019dfd44b7fd74168541552a3260a623", "model": "qwen-image-2", "status": "completed", "output": { "image_urls": [ "https://cdn.reapi.ai/...png" ] } } ``` Generated URLs expire — mirror them to your own storage if you need long-term retention. *** ## Errors Failures return the standard reAPI envelope `{ error: { code, message, request_id } }`. Common cases: * Invalid input (prompt over 800 characters, an editing-only `image_size` in text-to-image, a non-HTTPS `image_url`) → `400`. * Insufficient credits → `402`. * Rate limited → `429`. See the full catalog at [/docs/api/errors](/docs/api/errors). *** ## Tips * The modality is decided by your inputs, not a flag — omit `image_url` for generation, include it to edit. * Put the literal text you want rendered **in the prompt** — Qwen Image 2 is tuned for legible in-image typography, so spelling out headline copy works. * For wide layouts, `21:9` is available only when editing (pass an `image_url`). * To produce a set of images, send multiple requests — each is billed as one image. *** ## Related * [Image generation models](/docs/gpt-image-2) * [Wan 2.7 Image](/docs/wan-2-7-image) * [Tasks API](/docs/api/tasks) * [Error codes](/docs/api/errors) --- # seedance-2-0-mini (https://reapi.ai/docs/seedance-2-0-mini) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > ByteDance Seedance 2.0 **Mini** — the low-cost tier of the Seedance 2.0 > family. A single async video endpoint that auto-routes between > **T2V / I2V / R2V** based on which media field your request carries. > 480p or 720p, 4–15 second outputs. See current pricing on the > [model page](https://reapi.ai/models/seedance-2-0-mini). Generation is **asynchronous**: the POST returns a task id, then poll [`GET /api/v1/tasks/{id}`](/docs/api/tasks) until `status` is `completed`. **URL-only media.** All media inputs must be public `http(s)` URLs. base64 / `data:` URI media is **not accepted** by ReAPI — even where upstream docs show base64 examples. ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.0-mini", "prompt": "A kitten yawning at the camera, soft morning light", "resolution": "720p", "aspect_ratio": "16:9", "duration": 5 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "seedance-2.0-mini", "prompt": "A kitten yawning at the camera, soft morning light", "resolution": "720p", "aspect_ratio": "16:9", "duration": 5, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "seedance-2.0-mini", prompt: "A kitten yawning at the camera, soft morning light", resolution: "720p", aspect_ratio: "16:9", duration: 5, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "seedance-2.0-mini", "prompt": "A kitten yawning at the camera, soft morning light", "resolution": "720p", "aspect_ratio": "16:9", "duration": 5, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() var out map[string]any json.NewDecoder(resp.Body).Decode(&out) fmt.Println(out) } ``` ## Endpoint ```http POST /api/v1/videos/generations Authorization: Bearer rk_live_xxx Content-Type: application/json ``` Submitting returns a task id; poll [`GET /api/v1/tasks/{id}`](/docs/api/tasks) for the result. Polling does not consume credits. ## Parameters Exactly 12 input fields. The mode is implicit — which media fields you set decides text-to-video, image-to-video, or reference-driven generation. | Parameter | Type | Required | Default | Description | | ---------------------- | --------- | ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------ | | `prompt` | string | T2V: yes · I2V / R2V: no | — | Text prompt. Required for text-to-video; optional when a `first_frame_url` or `reference_image_urls` is set. | | `first_frame_url` | string | I2V | — | First-frame image, a single public `http(s)` URL. Presence selects **image-to-video**. | | `last_frame_url` | string | no | — | Optional last-frame image, a public `http(s)` URL. | | `reference_image_urls` | string\[] | R2V | — | **1–9** reference image URLs. Presence selects **reference-to-video**. | | `reference_video_urls` | string\[] | no | — | **Up to 3** reference video URLs. | | `reference_audio_urls` | string\[] | no | — | **Up to 3** reference audio URLs. | | `generate_audio` | boolean | no | `false` | Generate an audio track for the output video. | | `resolution` | enum | no | `720p` | `480p` · `720p`. | | `aspect_ratio` | enum | no | `16:9` | `16:9` `9:16` `1:1` `4:3` `3:4` `21:9` `adaptive`. | | `duration` | integer | no | `5` | Output length in seconds, `4`–`15`. | | `web_search` | boolean | no | `false` | Allow the model to ground the prompt with web search. | | `nsfw_checker` | boolean | no | `true` | Run the upstream NSFW content check. | All media inputs (`first_frame_url`, `last_frame_url`, `reference_image_urls`, `reference_video_urls`, `reference_audio_urls`) must be public HTTP(S) URLs — base64 / `data:` URIs are rejected. ## Modes Mode is implicit — selected by which inputs you send: | Mode | Trigger | prompt | | ---------------------------- | ----------------------------------------------- | -------- | | **Text-to-video (T2V)** | no media | required | | **Image-to-video (I2V)** | `first_frame_url` (optionally `last_frame_url`) | optional | | **Reference-to-video (R2V)** | `reference_image_urls` (1–9) | optional | ```json // I2V — animate a first frame { "model": "seedance-2.0-mini", "first_frame_url": "https://…/frame.jpg", "resolution": "720p", "duration": 5 } // R2V — keep subjects consistent across the clip { "model": "seedance-2.0-mini", "prompt": "the woman walks through the plaza", "reference_image_urls": ["https://…/a.jpg", "https://…/b.jpg"], "resolution": "720p", "duration": 5 } ``` ## More examples ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.0-mini", "first_frame_url": "https://example.com/frame.jpg", "resolution": "720p", "duration": 5 }' ``` ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.0-mini", "prompt": "the subject walks through a neon-lit street at night", "reference_image_urls": [ "https://example.com/a.jpg", "https://example.com/b.jpg" ], "resolution": "720p", "duration": 5 }' ``` ## Pricing Per-second, billed by **resolution × whether a reference video is uploaded**. A request that carries `reference_video_urls` bills at a cheaper reference tier. See current 480p / 720p rates on the [model page](https://reapi.ai/models/seedance-2-0-mini). **Bill formula** (1 credit = $0.001): | Input | Billable seconds | | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | No `reference_video_urls` (text / image / first-last-frame / reference-image) | `duration` you sent (default 5) | | With `reference_video_urls` | `duration` + `ceil(sum of source video seconds)` — the vendor processes the input clip(s) AND produces the output; both are billable. Failed probe → `400 PRICING_UNAVAILABLE`, no charge. | Final bill: `ceil(per_second_usd × billable_seconds × 1000)` credits. Failed jobs refund automatically. ## Output On success, `GET /api/v1/tasks/{id}` returns: ```json { "id": "task_…", "model": "seedance-2.0-mini", "status": "completed", "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/…/0.mp4"] }, "error": null } ``` ## Errors | HTTP | `code` | When | | ---- | ----------------- | ----------------------------------------------------------------------------- | | 400 | `20002` | Missing / invalid parameter (e.g. prompt required in T2V, value out of range) | | 400 | `80007` | Upstream content rejection (e.g. a flagged source image) | | 401 | `10001` – `10005` | Auth missing / invalid / revoked | | 402 | `30001` | Insufficient credits | | 429 | `50001` | Per-user rate limit exceeded | Pattern-match on the numeric `code`, not the message string. Failed generations are surfaced under `error` in the polling response and are refunded automatically. Full catalog: [Errors](/docs/api/errors). ## Tips * **Pick the mode by inputs, not a flag.** Sending `reference_image_urls` switches to R2V; sending `first_frame_url` switches to I2V; neither → T2V. * Seedance 2.0 Mini is the low-cost tier — for higher resolutions (1080p / 4k) use [`seedance-2-0`](/docs/seedance-2-0) or its [official channel](/docs/seedance-2-0-official). * Longer `duration` scales the bill linearly; start at 5s while iterating. ## Related * [`seedance-2-0` — full reference](/docs/seedance-2-0) * [`seedance-2-0-official` — Official channel](/docs/seedance-2-0-official) * [Tasks](/docs/api/tasks) — universal polling endpoint * [Errors](/docs/api/errors) — full error catalog --- # doubao-seedance-2.0-official (https://reapi.ai/docs/seedance-2-0-official) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Doubao Seedance 2.0 **Official Channel** — direct first-party routing, > distinct from the standard [`doubao-seedance-2.0`](/docs/seedance-2-0) > channel. Two model ids: `doubao-seedance-2.0-official` (480p / 720p / > 1080p / 4k) and `doubao-seedance-2.0-fast-official` (480p / 720p only). Same > async endpoint, same parameter shape as the standard channel — pick the > channel via the `model` id. **Official channel, ReAPI boundary.** The upstream is Volcengine Ark (火山方舟) first-party. Media inputs must still be public `http(s)` URLs; base64 / data URI media is not accepted by ReAPI even where upstream docs show base64 examples. **No real-person inputs.** This channel rejects source images / videos that appear to contain a real person (upstream privacy policy) — the request fails with `400` (code `80007`). For real-person uploads use a Face variant on the standard channel (`doubao-seedance-2.0-face` / `-fast-face`). **Tip — synthetic faces pass.** The filter blocks only real persons, not AI-generated faces. A portrait generated with [Seedream 5.0](/docs/seedream-5-0-lite) (a face-bearing synthetic image) is accepted as a source image on this channel. ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-seedance-2.0-official", "prompt": "A kitten yawning at the camera, soft morning light", "size": "16:9", "resolution": "720p", "duration": 5 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "doubao-seedance-2.0-official", "prompt": "A kitten yawning at the camera, soft morning light", "size": "16:9", "resolution": "720p", "duration": 5, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "doubao-seedance-2.0-official", prompt: "A kitten yawning at the camera, soft morning light", size: "16:9", resolution: "720p", duration: 5, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "doubao-seedance-2.0-official", "prompt": "A kitten yawning at the camera, soft morning light", "size": "16:9", "resolution": "720p", "duration": 5, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` *** ## Request surface The public endpoint and async response envelope are identical to the standard channel: ```txt POST /api/v1/videos/generations ``` Mode is implicit — which media fields you set decides text-to-video, image-to-video, first/last-frame, or reference-driven generation: | Field | Official-channel behavior | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | `"doubao-seedance-2.0-official"` or `"doubao-seedance-2.0-fast-official"` | | `prompt` | Required on every request (min 3 chars). | | `size` | `"16:9"`, `"9:16"`, `"1:1"`, `"4:3"`, `"3:4"`, `"21:9"`, `"adaptive"`. Default `"adaptive"`. | | `resolution` | `"480p"`, `"720p"`, `"1080p"`, `"4k"`. Default `"720p"`. `4k` is `doubao-seedance-2.0-official` only; `-fast-official` rejects `1080p` / `4k` (480p / 720p only). | | `duration` | 4–15 seconds. Default `5`. | | `generate_audio` | Boolean. Default `true`. | | `return_last_frame` | Boolean. Default `false`. | | `tools` | `[{"type": "web_search"}]` to enable web search. | | `image_urls` | Public `http(s)` URLs, up to 9. Mutually exclusive with `image_with_roles`. | | `image_with_roles` | First / last-frame slots (`role`: `first_frame` or `last_frame`). Cannot combine with `video_urls` or `audio_urls`. | | `video_urls` | Public `http(s)` URLs, up to 3. Presence switches billing to the cheaper reference tier (see Pricing). | | `audio_urls` | Public `http(s)` URLs, up to 3. Must be used together with `image_urls` or `video_urls`. | reAPI never silently substitutes one variant for another. Sending `resolution: "1080p"` to `doubao-seedance-2.0-fast-official` returns `400` (code `20003`), never an auto-downgraded clip. ## Differences from `doubao-seedance-2.0` | Aspect | `doubao-seedance-2.0` (standard) | `doubao-seedance-2.0-official` | | ----------------------- | ----------------------------------------- | ------------------------------------------------- | | Upstream channel | Standard | Volcengine Ark (火山方舟) official | | Wire `model` value | `doubao-seedance-2.0-face` / `-fast-face` | `doubao-seedance-2.0-official` / `-fast-official` | | Real-person inputs | Accepted only on Face variants | Not accepted (no Face variant) | | Per-second rate | Baseline | Lower — direct official pricing | | Validation error prefix | `seedance:` | `seedance-official:` | *** ## Pricing Per-second × resolution, with a cheaper reference tier when a source video is uploaded. The official channel is priced **below** the standard channel at the same resolution. See current 480p / 720p / 1080p rates on the [Seedance 2.0 model page](https://reapi.ai/models/seedance-2-0). **Bill formula** (1 credit = $0.001): | Input | Billable seconds | | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | No `video_urls` (text / image / first-last-frame / audio reference) | `duration` you sent (default 5) | | With `video_urls` | `duration` + `ceil(sum of source video seconds)` — the vendor processes the input clip(s) AND produces the output; both are billable. Failed probe → `400 PRICING_UNAVAILABLE`, no charge. | Final bill: `ceil(per_second_usd × billable_seconds × 1000)` credits. Failed jobs refund automatically. *** ## Validation errors The response envelope and numeric error-code system match the standard channel. Official-channel validation messages use the `seedance-official:` prefix. Upstream content rejections (e.g. a real-person source image) surface as `400` with code `80007`. Pattern-match on the numeric `code`, not the message string. *** ## When to pick which channel | Need | Channel | | ------------------------------------ | ---------------------------------------------------- | | Lowest unit price | `doubao-seedance-2.0-official` / `-fast-official` | | Official Volcengine Ark direct route | `doubao-seedance-2.0-official` / `-fast-official` | | Real-person source images / videos | `doubao-seedance-2.0-face` / `-fast-face` (standard) | Switching channels = changing the `model` string in your request body. The response envelope and polling flow are shared; provider-specific validation and pricing differ as documented above. *** ## Related * [`doubao-seedance-2.0` — full reference](/docs/seedance-2-0) * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) --- # doubao-seedance-2.0 (https://reapi.ai/docs/seedance-2-0) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > ByteDance's async video model on reAPI. **Four variants** share one > endpoint and one parameter shape — pick the variant via `model`. Mode > is implicit: which media fields you set (`prompt`, `image_urls`, > `image_with_roles`, `video_urls`, `audio_urls`) decides whether the > request runs as text-to-video, image-to-video, first/last-frame > transition, or reference-driven generation. 4–15 second outputs at > 480p / 720p / 1080p / 4k. See current pricing on the > [model page](https://reapi.ai/models/seedance-2-0). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-seedance-2.0-face", "prompt": "A kitten yawning at the camera, cinematic warm tones", "resolution": "720p", "size": "16:9", "duration": 5 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "doubao-seedance-2.0-face", "prompt": "A kitten yawning at the camera, cinematic warm tones", "resolution": "720p", "size": "16:9", "duration": 5, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "doubao-seedance-2.0", prompt: "A kitten yawning at the camera, cinematic warm tones", resolution: "720p", size: "16:9", duration: 5, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "doubao-seedance-2.0-face", "prompt": "A kitten yawning at the camera, cinematic warm tones", "resolution": "720p", "size": "16:9", "duration": 5, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "doubao-seedance-2.0-face", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URL, valid for 7 days. `output.last_frame_url` is present when the request set `return_last_frame: true`. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Variants `doubao-seedance-2.0` is a family of two variants sharing one parameter shape. Pick via `model`: | Variant | Speed | 1080p / 4k | Real-person uploads | | ------------------------------- | -------- | :------------------: | :-----------------: | | `doubao-seedance-2.0-face` | standard | ✅ | ✅ | | `doubao-seedance-2.0-fast-face` | faster | ❌ (480p / 720p only) | ✅ | reAPI never silently substitutes one variant for another. Sending `resolution: "1080p"` to the Fast variant returns `400`, never an auto-downgraded clip. **Real-person uploads** — both variants accept real-person source images / videos. *** ## Channels The variants above ship across two channels — same async endpoint, selected by the `model` id you send: | Channel | Model ids | Notes | | ------------ | ------------------------------------------------------------------- | --------------------------------------------------------------------------- | | **Standard** | `doubao-seedance-2.0-face`, `doubao-seedance-2.0-fast-face` | Face variants accept real-person inputs. | | **Official** | `doubao-seedance-2.0-official`, `doubao-seedance-2.0-fast-official` | Official direct channel — lower price. Real-person inputs are not accepted. | Standard and Official share the parameter shape documented below. *** ## Mode routing `doubao-seedance-2.0` picks its mode from which media fields you set — there is no `mode` parameter: | Fields you send | Mode | What it does | | ----------------------------------------------------------------------- | ---------- | ---------------------------------------- | | `prompt` only | **T2V** | Generate from text | | `prompt` + `image_urls` (1–9) | **I2V** | Animate / extend from reference images | | `prompt` + `image_with_roles` (1–2 frames) | **FRAMES** | First / last frame transition | | `prompt` + `video_urls` and / or `audio_urls` (+ optional `image_urls`) | **REF** | Reference-driven, optionally multi-modal | **Mutex rules.** Most field combinations are illegal. The single legal multi-field shape is `image_urls + video_urls + audio_urls` (REF mode, multi-modal). Any other combination is rejected with `400` (code `20003`). * `prompt` is required on every request (all four modes carry it) * `image_urls` ⊕ `image_with_roles` — never together * `image_with_roles` cannot be combined with `video_urls` or `audio_urls` * `audio_urls` requires `image_urls` or `video_urls` *** ## Request body ### `model` — required `string`. One of the four variants in the table above. ### `prompt` — string, required **Required on every request**, min **3** characters, up to **4,000** (≤ **500 recommended** — quality drops past \~500 chars on the upstream model). Applies to all modes — T2V, I2V, FRAMES, REF. Best results come from naming, in order, the **subject**, the **action**, the **camera move**, and the **style**. e.g. `"A kitten, yawning into the camera, slow push-in, cinematic warm tones"`. **Failure modes.** * Missing / empty → `400` (code `20002`). * Shorter than 3 chars → `400` (code `20003`). * Longer than 4,000 chars → `400` (code `20003`). ### `duration` — integer, default `5` Output length in seconds. Any integer in `[4, 15]`. Out-of-range → `400`. **Billable seconds = `sum(video_urls clip lengths)` + `duration`.** The input reference clips and the generated output both contribute to cost. Image and audio references don't carry a billable time component — only `video_urls` adds. reAPI probes `video_urls` server-side via ffmpeg metadata; the value reported by your client is never trusted for billing. See [Pricing](#pricing) for the full formula. ### `size` — string, default `"adaptive"` Output ratio. One of: | Value | Shape | | ---------- | ------------------------------------- | | `16:9` | Landscape | | `9:16` | Portrait | | `1:1` | Square | | `4:3` | Traditional landscape | | `3:4` | Traditional portrait | | `21:9` | Cinematic ultrawide | | `adaptive` | Match the input image / video's ratio | Invalid values → `400` (no silent fallback). ### `resolution` — string, default `"720p"` `480p` / `720p` / `1080p` / `4k` — lowercase only. Drives pricing. Uppercase forms like `1080P` are rejected with `400`. **`1080p` and `4k` are variant-gated.** Only `doubao-seedance-2.0` and `doubao-seedance-2.0-face` accept `1080p` / `4k`. The Fast variants (`-fast`, `-fast-face`) cap at 720p — sending a higher resolution returns `400 resolution= is not supported by ` (code `20003`), no auto-downgrade. ### `generate_audio` — boolean, default `true` When `true` (the default), the model synthesizes an audio track that plays alongside the generated video; pass `false` to get a silent clip. Independent of `audio_urls` (which is a **reference** for the model to align with — not a synthesis toggle). ### `return_last_frame` — boolean, default `false` When `true`, the completed task carries an extra `output.last_frame_url` holding the final frame as a still image. Pass it as `image_urls` of the next request to chain continuous video without prompt drift. ### `tools` — object\[] Per-tool capability list. Today only one type is recognized: ```json "tools": [{ "type": "web_search" }] ``` `web_search` lets the model query the web during generation — useful for current events or named brands. Unknown `type` values are rejected with `400 tools[i].type must be "web_search"`. ### `nsfw_checker` — boolean, default `true` Safety checking is enabled by default. Direct API callers can pass `"nsfw_checker": false` on the Standard model ids in this page: ```json { "model": "doubao-seedance-2.0-face", "prompt": "Your prompt", "resolution": "720p", "size": "16:9", "duration": 5, "nsfw_checker": false } ``` When set to `false`, reAPI sends the task directly through the Flexible channel when that channel is available and compatible with the request, and does not attach fallback to that task. If no compatible Flexible channel is available, reAPI silently uses the selected Standard channel instead; Standard channel generation remains safety-checked. In both cases, no fallback is attached for that request. ### `image_urls` — string\[] Array of public HTTP(S) URLs. Up to **9** entries. Triggers I2V (when sent without other media fields) or augments REF (when combined with `video_urls` / `audio_urls`). Mutually exclusive with `image_with_roles`. Sending more than 9 is rejected with `400 at most 9 image_urls allowed`. **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — every URL field on this endpoint must be a public HTTP(S) URL. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. ### `image_with_roles` — object\[] First / last frame interpolation. Each entry is a `{url, role}` object: ```json "image_with_roles": [ { "url": "https://your-cdn.com/day.jpg", "role": "first_frame" }, { "url": "https://your-cdn.com/night.jpg", "role": "last_frame" } ] ``` `role` is one of `first_frame` / `last_frame`. Up to **9** entries (typical use: 1 or 2 — one first frame and one last frame). **Cannot be combined** with `image_urls`, `video_urls`, or `audio_urls` — these modes are exclusive. ### `video_urls` — string\[] Reference video clips for REF mode. Up to **3** entries; each clip **2–15 s** long, **combined ≤ 15 s**. Each clip's frame must be **300–6000 px** on each side, **0.41–8.3 MP** total, aspect ratio **0.4–2.5**. Public HTTP(S) URLs only. **No real people on standard / fast variants.** Use the Face variants (`-face`, `-fast-face`) when the reference clip features identifiable real people — the non-Face variants reject them upstream. reAPI probes each clip's resolution and duration server-side via ffmpeg metadata. Out-of-spec assets surface as a `400`: * Frame outside 300–6000 px/side, 0.41–8.3 MP, or aspect 0.4–2.5 → `400 video_urls[i] resolution WxH is out of range` (code `20003`) * Each clip outside 2–15s, or combined > 15s → `400 video_urls total duration X.XXs exceeds the 15s limit` (code `20003`) * Probe failure (network / format) → `400 Could not determine source video duration for billing` (code `30002`) — no charge Mutually exclusive with `image_with_roles`. ### `audio_urls` — string\[] Reference audio for REF mode. Up to **3** entries; **combined duration ≤ 15 seconds**. Public HTTP(S) URLs only. **Must accompany `image_urls` OR `video_urls`** — a request with `audio_urls` and no visual reference is rejected with `400 audio_urls must be used together with image_urls or video_urls`. Mutually exclusive with `image_with_roles`. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "doubao-seedance-2.0-face", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"], "last_frame_url": "https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png" }, "error": null } ``` | Field | Type | Notes | | ----------------------- | -------------- | ----------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` (the variant you picked) | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion | | `output.video_urls` | string\[] | Generated MP4 URL(s) — valid for 7 days | | `output.last_frame_url` | string \| null | Present only when the request set `return_last_frame: true` | | `error` | object \| null | Populated on `failed` — `{ code, message }` | *** ## Validation errors All cases below return HTTP 400 with the noted code. Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed values) and are not a stable contract. | Trigger | Code | Message | | ------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------ | | Missing `prompt` | `20002` | `prompt: Invalid input: expected string, received undefined` | | `prompt` shorter than 3 chars | `20003` | `prompt: Too small: expected string to have >=3 characters` | | `prompt` longer than 4,000 chars | `20003` | `prompt: Too big: expected string to have <=4000 characters` | | `image_urls` and `image_with_roles` together | `20003` | `image_urls and image_with_roles cannot be used simultaneously` | | `image_with_roles` + `video_urls` or `audio_urls` | `20003` | `image_with_roles cannot be combined with video_urls or audio_urls` | | `audio_urls` without visual reference | `20003` | `audio_urls must be used together with image_urls or video_urls` | | `image_urls` > 9 | `20003` | `at most 9 image_urls allowed, got N` | | `image_with_roles` > 9 | `20003` | `at most 9 image_with_roles allowed, got N` | | `image_with_roles[i].role` invalid | `20003` | `image_with_roles[i].role must be first_frame or last_frame, got "..."` | | `video_urls` > 3 | `20003` | `at most 3 video_urls allowed, got N` | | `video_urls` clip frame out of range (300–6000px / 0.41–8.3MP / aspect 0.4–2.5) | `20003` | `video_urls[i] resolution WxH is out of range` | | `video_urls` combined > 15s | `20003` | `video_urls total duration X.XXs exceeds the 15s limit` | | `audio_urls` > 3 | `20003` | `at most 3 audio_urls allowed, got N` | | `audio_urls` combined > 15s | `20003` | `audio_urls total duration X.XXs exceeds the 15s limit` | | `duration` outside 4–15 | `20003` | `duration must be 4-15 seconds, got N` | | Invalid `size` value | `20005` | `invalid size "..." (allowed: 16:9 / 9:16 / 1:1 / 4:3 / 3:4 / 21:9 / adaptive)` | | Invalid `resolution` value | `20003` | `invalid resolution "..." (allowed: 480p / 720p / 1080p / 4k)` | | `1080p` on Fast variant | `20003` | `resolution=1080p is not supported by (use doubao-seedance-2.0 or doubao-seedance-2.0-face)` | | `tools[i].type` not `web_search` | `20003` | `tools[i].type must be "web_search", got "..."` | | Any URL field carrying a `data:` URI | `20003` | ` entries must be public URLs; base64 data URIs are not supported` | | Reference video probe fails | `30002` | `Could not determine source video duration for billing: ...` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for wire format and request\_id correlation. *** ## Recipes ### T2V — text-to-video ```json { "model": "doubao-seedance-2.0-face", "prompt": "A kitten yawning at the camera, slow push-in, warm tones", "resolution": "720p", "size": "16:9", "duration": 5, "fallback": { "enabled": false } } ``` ### I2V — single reference image ```json { "model": "doubao-seedance-2.0-face", "prompt": "The kitten stands up and walks toward the camera", "image_urls": ["https://your-cdn.com/cat.jpg"], "duration": 5 } ``` ### FRAMES — first / last frame transition ```json { "model": "doubao-seedance-2.0-face", "prompt": "Smooth transition from day to night", "image_with_roles": [ { "url": "https://your-cdn.com/day.jpg", "role": "first_frame" }, { "url": "https://your-cdn.com/night.jpg", "role": "last_frame" } ], "duration": 5 } ``` ### REF — reference video (style transfer) ```json { "model": "doubao-seedance-2.0-face", "prompt": "Restylize the reference clip into anime aesthetics", "video_urls": ["https://your-cdn.com/reference.mp4"] } ``` ### REF — reference video + reference audio ```json { "model": "doubao-seedance-2.0-face", "prompt": "A scene of a person speaking", "video_urls": ["https://your-cdn.com/reference.mp4"], "audio_urls": ["https://your-cdn.com/speech.wav"], "size": "16:9", "duration": 11 } ``` ### Voiced video (synthesized audio) ```json { "model": "doubao-seedance-2.0-face", "prompt": "A man calls out to a woman: \"Remember — never point at the moon with your finger.\"", "generate_audio": true } ``` ### Continuous video chain Step 1 — produce a 5s clip and ask for the last-frame URL: ```json { "model": "doubao-seedance-2.0-face", "prompt": "The kitten approaches the camera", "image_urls": ["https://your-cdn.com/kitten-start.png"], "return_last_frame": true } ``` Step 2 — feed `output.last_frame_url` as `image_urls` of the next call: ```json { "model": "doubao-seedance-2.0-face", "prompt": "The kitten turns and walks away", "image_urls": [""] } ``` ### Fast variant — quick timelapse ```json { "model": "doubao-seedance-2.0-fast-face", "prompt": "City nightscape timelapse", "size": "21:9", "duration": 8 } ``` ### Multi-modal — images + reference video + reference audio The full REF surface — combine all three reference types for tightly directed product / brand spots. ```json { "model": "doubao-seedance-2.0-face", "prompt": "First-person POV product ad with dynamic camera moves", "image_urls": [ "https://your-cdn.com/product-1.jpg", "https://your-cdn.com/product-2.jpg" ], "video_urls": ["https://your-cdn.com/style-ref.mp4"], "audio_urls": ["https://your-cdn.com/bgm.mp3"], "generate_audio": true, "size": "16:9", "duration": 11 } ``` *** ## Choosing a variant | Need | Pick | | -------------------------------------- | ------------------------------- | | Highest quality, full resolution range | `doubao-seedance-2.0-face` | | Cheaper / faster, 720p ceiling | `doubao-seedance-2.0-fast-face` | Variants are independent products — reAPI never rewrites your selected `model` on the primary attempt. Standard variants can still use the `fallback` policy above after an eligible generation-side failure. *** ## Polling pattern The task endpoint behaves identically to image tasks — only the completed `output` shape differs (`video_urls` / `last_frame_url` instead of `image_urls`). A pragmatic schedule: ``` 0–5 minutes: poll every 5s 5 min – 1 h: back off gradually toward 1 min ≥ 1 h: cap at 3 min between polls ``` A typical task completes in a few minutes. A single generation attempt can run for up to **48 hours**; when fallback is enabled, the overall task window can cover two generation attempts. *** ## Pricing Per-second × **billable seconds**, where: ``` billable_seconds = sum(video_urls clip lengths, server-probed) + duration ``` `video_urls` clip lengths are measured server-side via ffmpeg metadata — **client-stated values are never trusted for billing**. Image and audio references don't add to billable time. T2V / I2V / FRAMES requests (no `video_urls`) bill on `duration` alone. The **per-second rate** depends on three axes: * **Variant** (2 options) * **Resolution** (`480p` / `720p` / `1080p` / `4k`) * **Mode** — `text` (no media references) vs. `ref` (any of `image_urls`, `image_with_roles`, `video_urls`, `audio_urls` is set) REF rates are lower than text rates at every cell. See live numbers on the [model page](https://reapi.ai/models/seedance-2-0#pricing) — that table is dynamic and always reflects the current rate. **Bill formula** (1 credit = $0.001): ``` credits = ceil(per_second_usd × billable_seconds × 1000) ``` Charge on submit; refund automatically on `failed`. Probe failures (unreachable / unreadable `video_urls`) return `400 PRICING_UNAVAILABLE` with no charge. When fallback is enabled, reAPI reserves the larger of the primary and fallback attempt prices. The final successful task is settled to the winning attempt's price and the difference is refunded automatically. If both attempts fail, the full reserve is refunded. **Worked example.** `doubao-seedance-2.0` at `720p`, REF mode, with a 5-second reference video and `duration: 6`: * `billable_seconds = 5 + 6 = 11` * `credits = ceil(per_second_usd × 11 × 1000)` The same `duration: 6` request without `video_urls` would bill 6 seconds at the (higher) text rate. *** ## Tips * **Prompt motion, not just scene.** "Slow push-in, warm tones, shallow depth of field" outperforms a noun-list of what's on screen. * **Sweet-spot duration: 5–10 seconds.** Below 5s motion looks choppy; above 10s generation time grows fast. * **Trim reference clips before upload.** Both their actual length AND your `duration` count toward the bill. A 2-second style snippet is usually enough to convey style — there's no quality bonus for uploading a 15s reference. * **Pick `doubao-seedance-2.0-fast` for iteration.** Fast variants cost noticeably less and miss only the 1080p tier — perfect for prompt-tuning loops where final quality comes later. * **Real people → Face variants.** The non-Face variants reject identifiable real-person assets during generation; switching is a one-character change to `model`. * **Chain continuous video with `return_last_frame`.** Pass the returned URL as `image_urls` of the next request. No prompt drift between segments. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Pricing — Seedance 2.0](https://reapi.ai/models/seedance-2-0#pricing) --- # Seedance 2.5 (https://reapi.ai/docs/seedance-2-5) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; **Coming soon.** The Seedance 2.5 API is not available yet. The endpoint, parameters, and pricing below are a **preview** seeded from the current Seedance generation and may change when the model ships. Watch the [model page](https://reapi.ai/models/seedance-2-5) for launch. > ByteDance's next-generation async video model, coming to reAPI. Seedance 2.5 > turns text, photos, clips, or audio into short video. Like the current > Seedance family, mode is implicit: which media fields you set (`prompt`, > `image_urls`, `image_with_roles`, `video_urls`, `audio_urls`) decides whether > the request runs as text-to-video, image-to-video, first/last-frame > transition, or reference-driven generation. See pricing on the > [model page](https://reapi.ai/models/seedance-2-5). ## Status Seedance 2.5 is **coming soon**. This documentation is a preview so you can plan an integration ahead of launch. When the model ships: * The `model` ids, full parameter set, constraints, and per-second rates are finalized here. * The playground on the [model page](https://reapi.ai/models/seedance-2-5) becomes live. * This banner is removed. The shape below mirrors the current Seedance generation. Treat every field as provisional until launch. ## Quick example (preview) ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.5", "prompt": "A kitten yawning at the camera, cinematic warm tones", "resolution": "720p", "size": "16:9", "duration": 5 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "seedance-2.5", "prompt": "A kitten yawning at the camera, cinematic warm tones", "resolution": "720p", "size": "16:9", "duration": 5, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "seedance-2.5", prompt: "A kitten yawning at the camera, cinematic warm tones", resolution: "720p", size: "16:9", duration: 5, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "seedance-2.5", "prompt": "A kitten yawning at the camera, cinematic warm tones", "resolution": "720p", "size": "16:9", "duration": 5, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` These calls will return `404 model not found` until Seedance 2.5 launches. ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. ## Variants (preview) Seedance 2.5 is expected to ship as a family of variants sharing one parameter shape, picked via `model`: | Variant | Speed | 1080p | Real-person uploads | | ------------------------ | -------- | :------------------: | :-----------------: | | `seedance-2.5` | standard | ✅ | — | | `seedance-2.5-fast` | faster | ❌ (480p / 720p only) | — | | `seedance-2.5-face` | standard | ✅ | ✅ | | `seedance-2.5-fast-face` | faster | ❌ (480p / 720p only) | ✅ | reAPI never silently substitutes one variant for another. Final variant ids are confirmed at launch. ## Request body (preview) Mode is implicit — which media fields you set decides text-to-video, image-to-video, first/last-frame, or reference-driven generation. | Field | Type | Default | Notes | | ------------------- | --------- | ------- | -------------------------------------------------------------------- | | `model` | string | — | One of the variants above. **Required.** | | `prompt` | string | — | Describe the video. Optional when a reference field carries content. | | `duration` | integer | `5` | Output length in seconds, `4`–`15`. | | `size` | string | `16:9` | `16:9` / `9:16` / `1:1` / `4:3` / `3:4` / `21:9` / `adaptive`. | | `resolution` | string | `480p` | `480p` / `720p` / `1080p`. `1080p` on standard / face variants only. | | `seed` | integer | — | Reproducibility hint. | | `generate_audio` | boolean | `false` | Synthesize an audio track to play with the video. | | `return_last_frame` | boolean | `false` | Return `output.last_frame_url` for continuous chaining. | | `tools` | object\[] | — | `[{ "type": "web_search" }]` to let the model query the web. | | `image_urls` | string\[] | — | Up to 9 reference images (image-to-video). Public HTTP(S) URLs. | | `image_with_roles` | object\[] | — | First / last frame interpolation (`{ url, role }`). | | `video_urls` | string\[] | — | Up to 3 reference clips, combined ≤ 15s. | | `audio_urls` | string\[] | — | Up to 3 reference audio tracks for lip-sync. | **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — every URL field must be a public HTTP(S) URL. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "seedance-2.5", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/.../0.mp4"], "last_frame_url": "https://cdn.reapi.ai/media/tasks/.../0.png" }, "error": null } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. `output.video_urls` holds the generated MP4 URL. `output.last_frame_url` is present when the request set `return_last_frame: true`. ## Pricing Seedance 2.5 will bill per-second, scaled by resolution and reference mode — the same dimensions as the current Seedance family: ``` credits = ceil(per_second_usd × billable_seconds × 1000) ``` where `1 credit = $0.001`. Final per-second rates are published on the [model page](https://reapi.ai/models/seedance-2-5) at launch — that table is dynamic and always reflects the current rate. Failed jobs are refunded automatically. ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) * [Seedance 2.0 — available now](/docs/seedance-2-0) --- # doubao-seedream-5-0-lite (https://reapi.ai/docs/seedream-5-0-lite) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > ByteDance Doubao's lean image model on reAPI. **2K and 3K** resolution > tiers, **nine aspect ratios**, **image-to-image** via reference URLs, > and **batch generation** of up to four variations per call. Async-first: > submit returns a `task_id`; poll until ready. See current pricing on the > [model page](https://reapi.ai/models/seedream-5-0-lite). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-seedream-5-0-lite", "prompt": "a kitten yawning into the camera, cinematic warm tones", "size": "16:9", "resolution": "2K", "n": 1 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "doubao-seedream-5-0-lite", "prompt": "a kitten yawning into the camera, cinematic warm tones", "size": "16:9", "resolution": "2K", "n": 1, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "doubao-seedream-5-0-lite", prompt: "a kitten yawning into the camera, cinematic warm tones", size: "16:9", resolution: "2K", n: 1, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "doubao-seedream-5-0-lite", "prompt": "a kitten yawning into the camera, cinematic warm tones", "size": "16:9", "resolution": "2K", "n": 1, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "doubao-seedream-5-0-lite", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.image_urls` holds the generated image URLs, valid for **72 hours**. Mirror to your own storage if you need them longer. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/images/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required `string`. Must be `doubao-seedream-5-0-lite` exactly. The dotted / capitalized aliases the upstream model card mentions are not accepted at this gateway — send the canonical hyphen-only id. ### `prompt` — string, required Up to **4,000 characters**. Free-form text describing the image. Detailed prompts that name the **subject**, the **composition**, the **lighting**, and the **style** consistently produce better results. ### `size` — string, default `"1:1"` Output aspect ratio. One of: | Value | Shape | | ------ | --------------------------------------------------------------- | | `1:1` | Square | | `4:3` | Traditional landscape | | `3:4` | Traditional portrait | | `16:9` | Widescreen landscape | | `9:16` | Widescreen portrait | | `3:2` | Photo landscape | | `2:3` | Photo portrait | | `21:9` | Cinematic ultrawide | | `auto` | Match the first reference image's ratio (requires `image_urls`) | **`9:21` is not supported** on Seedream 5.0 Lite. Sending it returns `400` — use `21:9` for ultrawide framing instead. ### `resolution` — string, default `"2K"` Detail tier. Case-insensitive — `"2K"` and `"2k"` are equivalent. | Value | 1:1 example | 16:9 example | | ----- | ----------- | ------------ | | `2K` | 2048 × 2048 | 2848 × 1600 | | `3K` | 3072 × 3072 | 4096 × 2304 | `1K` and `4K` are not supported on this model — only the two tiers above. ### `n` — integer, default `1` How many images to return per call. Range `[1, 4]`. When `n > 1`, the upstream automatically promotes `sequential_image_generation` to `"auto"` so the call returns a consistent batch in one shot. You don't need to set the field yourself unless you want to override the default. ### `image_urls` — array, optional Reference images for image-to-image / multi-ref fusion. **Public HTTPS URLs only** — base64 / `data:` URIs are rejected at the gateway. Per-image constraints (from the upstream vendor doc): * Format: jpeg or png * Aspect ratio per image must be in `[1/3, 3]` * Each image ≤ 10 MB; total pixels ≤ 6000 × 6000 Upload to your own R2 / S3 / OSS / equivalent first, then pass the public URL. ### `output_format` — string, default `"jpeg"` Encoding for the returned files. * `jpeg` — small files, good for general use * `png` — needed for transparent backgrounds ### `sequential_image_generation` — string, default `"disabled"` Group-mode toggle. Two values: * `disabled` — single-image mode * `auto` — multi-image series mode When `n > 1`, the upstream auto-sets this to `"auto"`. Most callers should leave the field unset and let `n` drive the behavior. ### `sequential_image_generation_options` — object, optional Tuning for group mode. Only meaningful under `"auto"`. | Field | Type | Description | | ------------ | ------- | ----------------------------------------- | | `max_images` | integer | Cap on the number of images in the series | Example: ```json { "sequential_image_generation": "auto", "sequential_image_generation_options": { "max_images": 4 } } ``` ### `watermark` — boolean, default `false` Set `true` to add a Doubao watermark to the output. Off by default. *** ## Pricing Seedream 5.0 Lite charges a flat per-image rate at 2K and 3K. Multiply the per-image credit cost by `n` to size a batch. Failed and moderated requests are refunded automatically. The exact credit cost surfaces on the [model page](https://reapi.ai/models/seedream-5-0-lite) and through the estimator before submit. *** ## Response The poll envelope returns image URLs in `output.image_urls`: ```json { "id": "task_019dfd44b7fd74168541552a3260a623", "model": "doubao-seedream-5-0-lite", "status": "completed", "output": { "image_urls": [ "https://cdn.reapi.ai/...png" ] } } ``` URLs are valid for **72 hours**. Mirror to your own storage for longer retention. --- # Seedream 5.0 Pro (https://reapi.ai/docs/seedream-5-0-pro) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > ByteDance's flagship Doubao Seedream image model on reAPI. **1K and 2K** > resolution tiers, **text-to-image**, **single and multi-reference > image-to-image** (up to 10 reference images), and dependable **text > rendering** for posters, covers, and ad creative. Async-first: submit > returns a `task_id`; poll until ready. See current pricing on the > [model page](https://reapi.ai/models/seedream-5-0-pro). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-seedream-5-0-pro", "prompt": "a scarlet macaw on a mossy branch, cinematic god rays, magazine cover titled WILD BEAUTY", "aspect_ratio": "16:9", "quality": "high" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "doubao-seedream-5-0-pro", "prompt": "a scarlet macaw on a mossy branch, cinematic god rays", "aspect_ratio": "16:9", "quality": "high", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "doubao-seedream-5-0-pro", prompt: "a scarlet macaw on a mossy branch, cinematic god rays", aspect_ratio: "16:9", quality: "high", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "doubao-seedream-5-0-pro", "prompt": "a scarlet macaw on a mossy branch, cinematic god rays", "aspect_ratio": "16:9", "quality": "high", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "doubao-seedream-5-0-pro", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.image_urls` holds the generated image URL, valid for **72 hours**. Mirror to your own storage if you need it longer. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/images/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required `string`. Must be `doubao-seedream-5-0-pro` exactly. ### `prompt` — string, required Up to **4,000 characters**. Free-form text describing the image. Detailed prompts that name the **subject**, **composition**, **lighting**, and **style** consistently produce better results. Seedream 5.0 Pro renders in-image text well — put headline or logo copy directly in the prompt. ### `aspect_ratio` — string, required Output aspect ratio. Accepted values: * `1:1` * `4:3` * `3:4` * `16:9` * `9:16` * `2:3` * `3:2` ### `quality` — string, required Output resolution tier: * `basic` — 1K output * `high` — 2K output Seedream 5.0 Pro does not expose a 4K tier. Generated images do not include a visible watermark by default. ### `image_urls` — array, optional Reference images for image-to-image (1 image) or multi-reference fusion (up to **10** images). **Public HTTP(S) URLs only** — base64 / `data:` URIs are rejected at the gateway. Upload to your own R2 / S3 / OSS / equivalent first, then pass the public URL. ### `nsfw_checker` — boolean, optional Controls the final-image NSFW output check and defaults to `true`. Direct API requests may pass `false` to skip this additional check. The hosted Playground always keeps it enabled. When enabled, a flagged image is hidden and the task returns a content-policy error. Because the upstream generation already completed, that generation is still charged. Avoid submitting NSFW prompts when using the Playground. Seedream 5.0 Pro always returns **exactly one image** per call — there is no `n` parameter. Send multiple requests when you need multiple images. Group-image, web-search, and streaming options are not available on this model. *** ## Pricing Seedream 5.0 Pro charges the official **per-output-image rate**, banded by `quality` — the `high`/2K band costs more than `basic`/1K. For reference-image requests, the first input image is included and each additional input image (2nd through 10th) adds the official **¥0.02** reference surcharge (converted at the configured 6.8 RMB/USD rate). Provider failures and requests rejected before an image is generated are refunded. An image blocked by the final output check is still charged because generation already completed. ``` credits = ceil((output_price_usd + additional_reference_price_usd) × 1000) ``` where `1 credit = $0.001`. The exact per-image credit cost surfaces on the [model page](https://reapi.ai/models/seedream-5-0-pro) and reflects the current rate. There is no per-token or subscription component. *** ## Response The poll envelope returns the image URL in `output.image_urls`: ```json { "id": "task_019dfd44b7fd74168541552a3260a623", "model": "doubao-seedream-5-0-pro", "status": "completed", "output": { "image_urls": [ "https://cdn.reapi.ai/...jpg" ] } } ``` URLs are valid for **72 hours**. Mirror to your own storage for longer retention. *** ## Errors Failures use the standard envelope `{ error: { code, message, request_id } }`. See the [errors catalog](/docs/api/errors) for the full code list. Common cases: * Invalid parameters (bad `aspect_ratio` / `quality`, oversize `image_urls`) → `4xx` invalid-input. * A prompt or reference rejected before generation → content-policy error; the task is refunded. * A generated image blocked by the enabled output check → content-policy error (`80006`); the image is hidden and the completed generation remains charged. *** ## Tips * Choose `aspect_ratio` explicitly instead of relying on ratio wording in the prompt. * Multi-reference fusion keeps a character consistent — pass the same face / wardrobe references across a series. * Lean on Seedream 5.0 Pro's text rendering for posters, covers, and UI mockups; spell the exact words you want in quotes inside the prompt. *** ## Related * [Seedream 5.0 Lite](/docs/seedream-5-0-lite) — the lean, lower-cost tier * [Tasks reference](/docs/api/tasks) * [Errors catalog](/docs/api/errors) --- # Suno API (https://reapi.ai/docs/suno) import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; # Suno API The `suno-*` model family exposes the complete Suno music toolchain through one endpoint. Generate a song from a text idea or exact lyrics, then keep working on it: extend it, re-cover an uploaded track, layer vocals or instrumentals, mash two songs together, replace a section, separate stems, convert to WAV, extract MIDI, render a music video, or clone a singing voice. Current pricing for every operation is on the [Suno model page](/models/suno). ## Endpoints All 18 asynchronous operations share the audio task endpoint — the `model` field picks the operation: ```http POST /api/v1/audio/generations ``` Poll completion with: ```http GET /api/v1/tasks/{id} ``` Four synchronous helpers answer inline (no task lifecycle): ```http POST /api/v1/audio/suno/boost-style POST /api/v1/audio/suno/timestamped-lyrics POST /api/v1/audio/suno/persona POST /api/v1/audio/suno/check-voice ``` ## Quick example — generate a song ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "suno-music", "customMode": false, "instrumental": false, "version": "V5", "prompt": "A dreamy synthwave track about driving through a neon city at midnight" }' ``` ```python import requests, time headers = {"Authorization": "Bearer YOUR_API_KEY"} task = requests.post( "https://reapi.ai/api/v1/audio/generations", headers=headers, json={ "model": "suno-music", "customMode": False, "instrumental": False, "version": "V5", "prompt": "A dreamy synthwave track about driving through a neon city at midnight", }, ).json() while True: r = requests.get( f"https://reapi.ai/api/v1/tasks/{task['id']}", headers=headers ).json() if r["status"] in ("completed", "failed"): break time.sleep(5) print(r["output"]["tracks"]) ``` ```javascript const headers = { Authorization: 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json', }; const task = await fetch('https://reapi.ai/api/v1/audio/generations', { method: 'POST', headers, body: JSON.stringify({ model: 'suno-music', customMode: false, instrumental: false, version: 'V5', prompt: 'A dreamy synthwave track about driving through a neon city at midnight', }), }).then((r) => r.json()); let result; do { await new Promise((r) => setTimeout(r, 5000)); result = await fetch(`https://reapi.ai/api/v1/tasks/${task.id}`, { headers, }).then((r) => r.json()); } while (result.status === 'processing'); console.log(result.output.tracks); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "net/http" "time" ) const key = "YOUR_API_KEY" func main() { body, _ := json.Marshal(map[string]any{ "model": "suno-music", "customMode": false, "instrumental": false, "version": "V5", "prompt": "A dreamy synthwave track about driving through a neon city at midnight", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/audio/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+key) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var task struct { ID string `json:"id"` } json.NewDecoder(resp.Body).Decode(&task) for { time.Sleep(5 * time.Second) poll, _ := http.NewRequest("GET", "https://reapi.ai/api/v1/tasks/"+task.ID, nil) poll.Header.Set("Authorization", "Bearer "+key) pr, err := http.DefaultClient.Do(poll) if err != nil { panic(err) } var result struct { Status string `json:"status"` Output struct { Tracks []struct { ID string `json:"id"` URL string `json:"url"` Title string `json:"title"` } `json:"tracks"` } `json:"output"` } json.NewDecoder(pr.Body).Decode(&result) pr.Body.Close() if result.Status != "processing" { fmt.Printf("%+v\n", result.Output.Tracks) return } } } ``` One generation request returns **two tracks**. Each track carries an `id` you reuse as `audioId` in every track-referencing operation below. ## Modes: inspiration vs custom Generation-class operations (`suno-music`, `suno-upload-cover`, `suno-mashup`) run in one of two modes: * **`customMode: false` (inspiration)** — `prompt` (max 500 characters) describes the song idea; Suno writes the lyrics. * **`customMode: true` (custom)** — `prompt` is used **strictly as lyrics**; `style` and `title` become required. With `instrumental: true`, `prompt` is not needed. Character caps scale with `version`: `prompt` 3000 (V4) / 5000 (others), `style` 200 (V4) / 1000 (others), `title` 80 (100 on some extend variants). ## Versions `version` is required on generation-class operations: `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, `V5_5`. `suno-add-vocals` / `suno-add-instrumental` accept `V4_5PLUS` / `V5` / `V5_5` (default `V4_5PLUS`); `suno-sounds` accepts `V5` / `V5_5`. ## Referencing earlier work: `taskId` + `audioId` Operations that act on an existing song take: * `taskId` — **your reAPI task id** (`task_...`) of the source task. It must be your own completed task; reAPI resolves it internally. * `audioId` — the track id from that task's `output.tracks[].id`. Media inputs (`uploadUrl`, `uploadUrlList`, `voiceUrl`, `verifyUrl`) accept public HTTP(S) URLs only — no base64 / data URIs. ## Operation reference Every asynchronous operation posts to `/api/v1/audio/generations` and is selected by the `model` field; poll `/api/v1/tasks/{id}` for the result. The four synchronous helpers have their own routes and answer inline. ## Create ### Generate a song `POST /api/v1/audio/generations` · `model: "suno-music"` Generates a song from a text description — either a short idea the model turns into lyrics, or your own lyrics, style and title — and returns multiple finished audio variations. **Request** | Field | Type | Required | Notes | | --------------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-music`. | | `customMode` | boolean | yes | `false` = inspiration mode (describe an idea, the model writes the lyrics). `true` = custom mode (you supply style, title and — for vocal tracks — the exact lyrics). | | `instrumental` | boolean | yes | `true` generates a track with no lyrics. In custom mode it decides whether `prompt` is required; in inspiration mode it does not change which fields are required. | | `version` | string | yes | Model version. One of `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, `V5_5`. `V4` caps a track at \~4 min and the `V4_5*` line at \~8 min; `V5` / `V5_5` publish no length cap. Also selects the `prompt` / `style` character limits below. | | `prompt` | string | conditional | Inspiration mode: the core idea, max 500 characters — required, and the lyrics are written from it rather than matching it word for word. Custom mode: used verbatim as the sung lyrics; required when `instrumental` is `false`; max 3000 characters on `V4`, 5000 on every other version. | | `style` | string | conditional | Genre, mood or artistic direction (e.g. `Classical`, `Jazz, upbeat`). Required in custom mode; max 200 characters on `V4`, 1000 on every other version. Ignored in inspiration mode. | | `title` | string | conditional | Track title. Required in custom mode; max 80 characters on all versions. Ignored in inspiration mode. | | `negativeTags` | string | no | Comma-separated styles or traits to steer away from, e.g. `Heavy Metal, Upbeat Drums`. | | `vocalGender` | string | no | `m` or `f`. Only effective when `customMode` is `true`, and it biases the voice rather than guaranteeing it. | | `styleWeight` | number | no | How strictly the result adheres to `style`. `0`–`1`, up to 2 decimal places. | | `weirdnessConstraint` | number | no | How far the result may deviate creatively. `0`–`1`, up to 2 decimal places. | | `audioWeight` | number | no | Balance of audio features against the other inputs. `0`–`1`, up to 2 decimal places. | | `personaId` | string | no | Persona id or voice id to apply to the generated music. Only available when `customMode` is `true`. Persona ids come from `POST /api/v1/audio/suno/persona`; voice ids come from `suno-voice-generate`. | | `personaModel` | string | no | `style_persona` or `voice_persona` — which kind of persona `personaId` refers to. Only available on `V5` and `V5_5`. | **Response** — on completion, `output.audio_urls[]` holds one URL per generated variation (usually two). `output.tracks[]` carries the same items with metadata, index-aligned with `audio_urls`: `type` (`audio`), `url`, `id` (the track's audio id — pass it as `audioId` to extend, WAV, stem-separation, MIDI, music-video and timestamped-lyrics operations), `title`, `duration` in seconds, `tags` (comma-separated style tags), `lyrics` and `image_url` (cover art, rehosted alongside the audio). Only `url` is guaranteed — metadata keys are omitted when upstream returns them empty. **Notes** — the two modes have different required sets, and the API enforces them. Inspiration mode (`customMode: false`) needs only `prompt`, capped at 500 characters; `style` and `title` are ignored. Custom mode (`customMode: true`) always requires `style` and `title`, and additionally requires `prompt` when `instrumental` is `false` — an instrumental custom request is valid with just `style` and `title`. Character caps move with `version`: `prompt` 3000 on `V4` and 5000 elsewhere, `style` 200 on `V4` and 1000 elsewhere; `title` is 80 on every version. Pricing per generation is listed at [https://reapi.ai/models/suno](https://reapi.ai/models/suno). ### Generate lyrics `POST /api/v1/audio/generations` · `model: "suno-lyrics"` Writes song lyrics from a theme description and returns them as structured text — no audio is produced. **Request** | Field | Type | Required | Notes | | -------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `model` | string | yes | Must be `suno-lyrics`. | | `prompt` | string | yes | Description of the lyrics you want — theme, mood, style or story elements. Max 200 characters. More specific prompts yield more targeted lyrics. | **Response** — this task returns text, not audio: there is no `audio_urls` or `tracks`. On completion `output.result.lyrics[]` holds the generated variations (typically 2–3), each an object with `title` and `text`. The `text` body is formatted with standard section markers (`[Verse]`, `[Chorus]`, `[Bridge]`, …), so it can be passed straight into `suno-music` as `prompt` in custom mode. ```json { "output": { "result": { "lyrics": [ { "title": "Small Town Lights", "text": "[Verse]\n...\n\n[Chorus]\n..." }, { "title": "Back Then", "text": "[Verse]\n...\n\n[Chorus]\n..." } ] } } } ``` **Notes** — variations that the upstream model failed to produce are dropped rather than returned as empty entries, so `lyrics[]` can be shorter than the usual 2–3 items. If none survive, the task fails and the reservation is refunded. ### Generate a sound `POST /api/v1/audio/generations` · `model: "suno-sounds"` Generates a short sound or sound bed — background music, ambience, game SFX — with optional looping, tempo and key control, and returns audio. **Request** | Field | Type | Required | Notes | | ------------ | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-sounds`. | | `prompt` | string | yes | Description of the sound to generate. Max 500 characters. | | `version` | string | yes | Model version. `V5` or `V5_5` only — the older versions do not support sound generation. | | `soundLoop` | boolean | no | Generate the result as a seamless loop, for background music and ambient beds. Defaults to `false`. | | `soundTempo` | integer | no | Target tempo in BPM, `1`–`300`. Omit to let the model choose. | | `soundKey` | string | no | Musical key: `Cm`, `C#m`, `Dm`, `D#m`, `Em`, `Fm`, `F#m`, `Gm`, `G#m`, `Am`, `A#m`, `Bm`, `C`, `C#`, `D`, `D#`, `E`, `F`, `F#`, `G`, `G#`, `A`, `A#`, `B`. Omit for any key. | | `grabLyrics` | boolean | no | Capture lyric subtitles for the generated audio. Defaults to `false`. | **Response** — same shape as a song: `output.audio_urls[]` with one URL per generated variation, and `output.tracks[]` index-aligned with it, each entry carrying the same per-track fields — `type` (`audio`), `url`, `id`, `title`, `duration` in seconds, `tags`, `lyrics` and `image_url` (cover art) — with the empty ones omitted. ## Extend & rework ### Extend a track `POST /api/v1/audio/generations` · `model: "suno-extend"` Continues an existing track from a chosen time point, producing a new set of audio variants that keep the source track's style. **Request** | Field | Type | Required | Notes | | --------------------- | ------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-extend`. | | `defaultParamFlag` | boolean | yes | `true` — extend using the parameters in this request (`prompt`, `style`, `title`, `continueAt` all become required). `false` — inherit the source track's parameters; only `audioId` and `version` are needed. | | `audioId` | string | yes | The track to extend. Take it from the parent task's `output.tracks[].id`. | | `version` | enum | yes | One of `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, `V5_5`. Must match the source track's version. | | `prompt` | string | conditional | Required when `defaultParamFlag` is `true`. Describes how the music should continue or change across the extension. Max 3000 chars on `V4`, 5000 on every other version. | | `style` | string | conditional | Required when `defaultParamFlag` is `true`. Style of the extended audio; align it with the source track's style for the most consistent result. Max 200 chars on `V4`, 1000 on every other version. | | `title` | string | conditional | Required when `defaultParamFlag` is `true`. Title of the extended track. Max 80 chars on `V4` and `V4_5ALL`, 100 on every other version. | | `continueAt` | number | conditional | Required when `defaultParamFlag` is `true`. Seconds into the source track where the extension begins. Must be greater than 0 and less than the source track's duration (the upper bound is checked upstream). | | `negativeTags` | string | no | Styles or traits to keep out of the extension, e.g. `Heavy Metal, Upbeat Drums`. | | `vocalGender` | enum | no | `m` or `f`. Raises the probability of that vocal gender; it is not a guarantee. | | `styleWeight` | number | no | 0–1, up to 2 decimal places. Strength of adherence to `style`. | | `weirdnessConstraint` | number | no | 0–1, up to 2 decimal places. Controls experimental/creative deviation. | | `audioWeight` | number | no | 0–1, up to 2 decimal places. Balance of audio features against the other inputs. | | `personaId` | string | no | Persona ID or Voice ID to apply. Only takes effect when `defaultParamFlag` is `true`. | | `personaModel` | enum | no | `style_persona` or `voice_persona`. Only available on `V5` and `V5_5`. | **Response** — on completion, `output.audio_urls` holds the generated audio URLs and `output.tracks[]` carries one index-aligned entry per variant, each with `id` (pass this back as `audioId` in follow-up operations), `url`, `type` (`audio`), `title`, `duration` in seconds, `tags` (comma-separated style tags), `lyrics` and `image_url` (cover art). **Notes** — the `defaultParamFlag` matrix is strict: with `true`, all four of `prompt`, `style`, `title` and `continueAt` must be present, and the per-version character caps above apply; with `false`, everything except `audioId` and `version` is inherited from the source track. `continueAt` must be greater than 0. ### Cover an uploaded track `POST /api/v1/audio/generations` · `model: "suno-upload-cover"` Re-records audio you supply in a new style while keeping its core melody, returning the reworked variants. **Request** | Field | Type | Required | Notes | | --------------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `model` | string | yes | Must be `suno-upload-cover`. | | `uploadUrl` | string | yes | Public `http(s)` URL of the source audio. Maximum 8 minutes. Base64 and `data:` URIs are rejected. | | `customMode` | boolean | yes | `true` — supply your own `style`/`title` (and `prompt` when the result has vocals). `false` — only `prompt` is used and lyrics are generated from it. | | `instrumental` | boolean | yes | `true` produces a track with no lyrics. In custom mode it decides whether `prompt` is required; in non-custom mode it does not change which fields are required. | | `version` | enum | yes | One of `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, `V5_5`. | | `prompt` | string | conditional | Required in custom mode when `instrumental` is `false`, where it is used verbatim as the lyrics (max 3000 chars on `V4`, 5000 on every other version). Required in non-custom mode, where it is the core idea lyrics are written from (max 500 chars). | | `style` | string | conditional | Required in custom mode; the genre or style of the cover, e.g. `Jazz`, `Classical`. Max 200 chars on `V4`, 1000 on every other version. Leave empty in non-custom mode. | | `title` | string | conditional | Required in custom mode. Max 80 chars on `V4` and `V4_5ALL`, 100 on every other version. Leave empty in non-custom mode. | | `negativeTags` | string | no | Styles or traits to exclude from the cover. | | `vocalGender` | enum | no | `m` or `f`. Only effective when `customMode` is `true`, and only raises the probability of that vocal gender. | | `styleWeight` | number | no | 0–1, up to 2 decimal places. Strength of adherence to `style`. | | `weirdnessConstraint` | number | no | 0–1, up to 2 decimal places. Controls experimental/creative deviation. | | `audioWeight` | number | no | 0–1, up to 2 decimal places. Balance of audio features against the other inputs. | | `personaId` | string | no | Persona ID or Voice ID to apply. Only available when `customMode` is `true`. | | `personaModel` | enum | no | `style_persona` or `voice_persona`. Only available on `V5` and `V5_5`. | **Response** — on completion, `output.audio_urls` holds the cover's audio URLs and `output.tracks[]` carries one index-aligned entry per variant, each with `id`, `url`, `type` (`audio`), `title`, `duration` in seconds, `tags`, `lyrics` and `image_url` (cover art). **Notes** — the requirement matrix is `customMode` × `instrumental`: custom + instrumental needs `style` and `title`; custom + vocals needs `style`, `title` and `prompt`; non-custom needs only `prompt` (capped at 500 characters) regardless of `instrumental`, and `style`/`title` should be left empty. `uploadUrl` is always required and the audio behind it must not exceed 8 minutes. ### Extend an uploaded track `POST /api/v1/audio/generations` · `model: "suno-upload-extend"` Continues audio you supply from a chosen time point, returning a longer track that carries on the uploaded material's style. **Request** | Field | Type | Required | Notes | | --------------------- | ------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-upload-extend`. | | `uploadUrl` | string | yes | Public `http(s)` URL of the source audio. Maximum 8 minutes. Base64 and `data:` URIs are rejected. | | `defaultParamFlag` | boolean | yes | `true` — extend using the parameters in this request (`style`, `title` and `continueAt` become required, plus `prompt` when `instrumental` is `false`). `false` — reuse the uploaded audio's own parameters; on top of the always-required `uploadUrl`, `instrumental` and `version`, only `prompt` is needed. | | `instrumental` | boolean | yes | `true` extends without lyrics. When `defaultParamFlag` is `true` it decides whether `prompt` is required; when `false` it does not change which fields are required. | | `version` | enum | yes | One of `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, `V5_5`. Must match the source music's version. | | `continueAt` | number | conditional | Required when `defaultParamFlag` is `true`. Seconds into the uploaded audio where the extension begins. Must be greater than 0 and less than the uploaded audio's duration (the upper bound is checked upstream). | | `prompt` | string | conditional | Required when `defaultParamFlag` is `true` and `instrumental` is `false`, where it is used verbatim as the lyrics; also required when `defaultParamFlag` is `false`, where lyrics are generated from it. Max 3000 chars on `V4`, 5000 on every other version. | | `style` | string | conditional | Required when `defaultParamFlag` is `true`; e.g. `Jazz`, `Classical`, `Electronic`. Max 200 chars on `V4`, 1000 on every other version. | | `title` | string | conditional | Required when `defaultParamFlag` is `true`. Max 80 chars on `V4` and `V4_5ALL`, 100 on every other version. | | `negativeTags` | string | no | Styles to exclude from the extension. | | `vocalGender` | enum | no | `m` or `f`. Raises the probability of that vocal gender; it is not a guarantee. | | `styleWeight` | number | no | 0–1, up to 2 decimal places. Strength of adherence to `style`. | | `weirdnessConstraint` | number | no | 0–1, up to 2 decimal places. Controls experimental/creative deviation. | | `audioWeight` | number | no | 0–1, up to 2 decimal places. Balance of audio features against the other inputs. | | `personaId` | string | no | Persona ID or Voice ID to apply. Only available when `defaultParamFlag` is `true`. | | `personaModel` | enum | no | `style_persona` or `voice_persona`. Only available on `V5` and `V5_5`. | **Response** — on completion, `output.audio_urls` holds the extended audio URLs and `output.tracks[]` carries one index-aligned entry per variant, each with `id`, `url`, `type` (`audio`), `title`, `duration` in seconds, `tags`, `lyrics` and `image_url` (cover art). **Notes** — the requirement matrix is `defaultParamFlag` × `instrumental`: flag `true` + instrumental needs `style`, `title` and `continueAt`; flag `true` + vocals needs `style`, `title`, `prompt` and `continueAt`; flag `false` needs only `prompt` beyond the always-required `uploadUrl`, `instrumental` and `version` (everything else is taken from the uploaded audio). `continueAt` must be greater than 0, and unlike the cover operation there is no 500-character short-prompt mode — the per-version caps apply in both modes. ## Layer & combine ### Add vocals to a track `POST /api/v1/audio/generations` · `model: "suno-add-vocals"` Takes an audio file you host and sings a new vocal line over it, returning the layered tracks as audio URLs. **Request** | Field | Type | Required | Notes | | --------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-add-vocals`. | | `uploadUrl` | string | yes | Public HTTP(S) URL of the source audio to add vocals to. Base64 and `data:` URIs are rejected. | | `prompt` | string | yes | Lyric content and singing style to guide the vocal. Min 1 character. | | `style` | string | yes | Musical style for the vocal, e.g. `Jazz`. Min 1 character. | | `title` | string | yes | Track title, shown in players and used for the file name. Min 1 character. | | `negativeTags` | string | yes | Comma-separated styles or elements to keep out of the result, e.g. `heavy metal, strong drum beats`. Min 1 character. | | `version` | string | no | One of `V4_5PLUS`, `V5`, `V5_5`. Defaults to `V4_5PLUS`. | | `vocalGender` | string | no | `m` or `f`. Biases the voice; it raises the probability rather than guaranteeing the gender. | | `styleWeight` | number | no | Adherence to `style`. 0–1, up to 2 decimal places. | | `weirdnessConstraint` | number | no | Experimental / creative deviation. 0–1, up to 2 decimal places. | | `audioWeight` | number | no | Relative weight of the source audio's elements. 0–1, up to 2 decimal places. | **Response** — on completion, `output.audio_urls[]` holds the generated audio URLs and `output.tracks[]` carries one entry per track with `id`, `url`, `type` (`audio`), `title`, `duration` (seconds), `tags` (comma-separated style tags), `lyrics` and `image_url` (cover art). The two arrays are index-aligned, one entry per generated variant. `tracks[].id` is the `audioId` you pass to track-referencing operations. **Notes** — unlike the generate/extend operations, all five content fields (`prompt`, `style`, `title`, `negativeTags`, `uploadUrl`) are unconditionally required, and `version` is restricted to the three newest models: `V4`, `V4_5` and `V4_5ALL` are rejected. Pricing: [reapi.ai/models/suno](https://reapi.ai/models/suno). ```bash curl -X POST https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "suno-add-vocals", "uploadUrl": "https://example.com/music.mp3", "prompt": "A calm and relaxing piano track.", "style": "Jazz", "title": "Relaxing Piano", "negativeTags": "heavy metal, strong drum beats", "version": "V4_5PLUS" }' ``` ### Add instrumental to a track `POST /api/v1/audio/generations` · `model: "suno-add-instrumental"` Takes an audio file you host and generates an instrumental accompaniment for it, returning the layered tracks as audio URLs. **Request** | Field | Type | Required | Notes | | --------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-add-instrumental`. | | `uploadUrl` | string | yes | Public HTTP(S) URL of the source audio to accompany. Base64 and `data:` URIs are rejected. | | `tags` | string | yes | Styles to include, e.g. `relaxing, piano, soothing`. Defines the character of the accompaniment. Min 1 character. | | `title` | string | yes | Track title, shown in players and used for the file name. Min 1 character. | | `negativeTags` | string | yes | Comma-separated styles or elements to keep out of the result. Min 1 character. | | `version` | string | no | One of `V4_5PLUS`, `V5`, `V5_5`. Defaults to `V4_5PLUS`. | | `vocalGender` | string | no | `m` or `f`. Biases the voice; it raises the probability rather than guaranteeing the gender. | | `styleWeight` | number | no | Adherence to the requested style. 0–1, up to 2 decimal places. | | `weirdnessConstraint` | number | no | Experimental / creative deviation. 0–1, up to 2 decimal places. | | `audioWeight` | number | no | Relative weight of the source audio's elements. 0–1, up to 2 decimal places. | **Response** — same shape as add-vocals: `output.audio_urls[]` plus `output.tracks[]` with `id`, `url`, `type`, `title`, `duration`, `tags` and `lyrics` per track. **Notes** — this operation names the style field `tags`, not `style`; sending `style` is rejected. All four of `uploadUrl`, `tags`, `title` and `negativeTags` are unconditionally required, and `version` accepts only `V4_5PLUS`, `V5` and `V5_5`. Pricing: [reapi.ai/models/suno](https://reapi.ai/models/suno). ```bash curl -X POST https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "suno-add-instrumental", "uploadUrl": "https://example.com/music.mp3", "tags": "relaxing, piano, soothing", "title": "Relaxing Piano", "negativeTags": "heavy metal, strong drum beats", "version": "V4_5PLUS" }' ``` ### Mash up two tracks `POST /api/v1/audio/generations` · `model: "suno-mashup"` Combines exactly two audio files you host into one new piece, returning the remixed tracks as audio URLs. **Request** | Field | Type | Required | Notes | | --------------------- | --------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `model` | string | yes | Must be `suno-mashup`. | | `uploadUrlList` | string\[] | yes | Exactly 2 public HTTP(S) audio URLs. Fewer or more is rejected; base64 and `data:` URIs are rejected. | | `customMode` | boolean | yes | `true` unlocks the detailed controls (`style`, `title`, lyrics); `false` is the simple mode driven by `prompt` alone. | | `version` | string | yes | One of `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, `V5_5`. | | `instrumental` | boolean | no | Generate the mashup without lyrics. In custom mode it decides whether `prompt` is required; in non-custom mode it has no effect on required fields. | | `prompt` | string | no | Conditionally required — see Notes. In custom mode it is used verbatim as the lyrics; in non-custom mode it is the core idea and lyrics are written from it. | | `style` | string | conditional | Required in custom mode, ignored otherwise. Genre, mood or artistic direction. | | `title` | string | conditional | Required in custom mode, ignored otherwise. Max 80 characters on every version. | | `vocalGender` | string | no | `m` or `f`. Only takes effect when `customMode` is `true`. | | `styleWeight` | number | no | Adherence to `style`. 0–1, up to 2 decimal places. Only takes effect when `customMode` is `true`. | | `weirdnessConstraint` | number | no | Creative deviation. 0–1, up to 2 decimal places. Only takes effect when `customMode` is `true`. | | `audioWeight` | number | no | Weight of the source audio elements. 0–1, up to 2 decimal places. Only takes effect when `customMode` is `true`. | **Response** — `output.audio_urls[]` plus `output.tracks[]`, each track carrying `id`, `url`, `type`, `title`, `duration`, `tags` and `lyrics`. **Notes** — `uploadUrlList` must contain exactly two URLs. With `customMode: true`, `style` and `title` become required, and `prompt` is required too unless `instrumental` is `true`; the caps then depend on `version` — `prompt` up to 3000 characters on `V4` and 5000 on every other version, `style` up to 200 on `V4` and 1000 elsewhere, `title` 80 throughout. With `customMode: false`, `prompt` is optional but capped at 500 characters and the other content fields are ignored. Pricing: [reapi.ai/models/suno](https://reapi.ai/models/suno). ```bash curl -X POST https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "suno-mashup", "uploadUrlList": [ "https://example.com/audio1.mp3", "https://example.com/audio2.mp3" ], "customMode": true, "instrumental": false, "version": "V4_5PLUS", "prompt": "A calm and relaxing piano track with soft melodies", "style": "Jazz", "title": "Relaxing Piano" }' ``` ## Section editing ### Replace a section `POST /api/v1/audio/generations` · `model: "suno-replace-section"` Regenerates one time window inside an existing song from a new prompt and style, blending the replacement into the material before and after it, and returns the re-rendered track(s). **Request** | Field | Type | Required | Notes | | -------------- | ------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-replace-section`. | | `taskId` | string | conditional | Variant A. The reAPI task id (`task_...`) of the song you are editing. Required together with `audioId`; see Notes. | | `audioId` | string | conditional | Variant A. Identifies which track of that task to edit — take it from the parent task's `output.tracks[].id`. Required together with `taskId`. | | `uploadUrl` | string | conditional | Variant B. Public `http(s)` URL of your own audio file. Required together with `version`. Base64 / `data:` URIs are rejected. | | `version` | enum | conditional | Variant B. Model version used to render the replacement: `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, `V5_5`. Required together with `uploadUrl`. | | `prompt` | string | yes | Lyrics for the replaced segment. Min 1 char. | | `tags` | string | yes | Style tags for the replaced segment, e.g. `Jazz`. Min 1 char. | | `title` | string | yes | Title of the resulting song. Min 1 char. | | `negativeTags` | string | no | Styles to keep out of the replaced segment, e.g. `Rock`. Min 1 char. | | `infillStartS` | number | yes | Start of the replacement window, in seconds from the beginning of the track. `>= 0`. Must be less than `infillEndS`. Values are interpreted to 2-decimal precision (e.g. `10.50`). | | `infillEndS` | number | yes | End of the replacement window, in seconds. `>= 0`. Must be greater than `infillStartS`, and `infillEndS - infillStartS` must be between 6 and 60 seconds. | | `fullLyrics` | string | yes | The COMPLETE lyrics of the song after the edit — untouched sections plus the rewritten one — not just the replaced part. Min 1 char. | **Response** — on completion, `output.audio_urls[]` holds the URL of each rendered track. `output.tracks[]` carries the same audio index-aligned with per-track metadata: `type` (`"audio"`), `url`, `id` (pass this back as `audioId` in later track-referencing operations), `title`, `duration` (seconds), `tags`, and `lyrics`. **Notes** — the source is specified by exactly one of two mutually exclusive variants: **(A)** `taskId` + `audioId` to edit a track generated on reAPI, or **(B)** `uploadUrl` + `version` to edit audio you supply. Both halves of a variant must be present together, and mixing fields from the two variants in one request is rejected with a validation error — so is sending neither. `version` belongs to variant B only — sending it alongside `taskId` / `audioId` is what makes a request "mixed", so variant A must omit it and the replacement is rendered with the source track's own model. Two further limits apply to the window: it must span at least 6 and at most 60 seconds, and upstream additionally refuses a replacement longer than 50% of the original track's total duration. `fullLyrics` is what the whole song is re-rendered against, so passing only the new lines will drop the rest of the lyrics. ## Track assets These operations act on a track you already generated: they take the reapi `taskId` of a completed Suno task plus (usually) the `audioId` of one track inside it, and return a derived asset. Per-operation pricing: [https://reapi.ai/models/suno](https://reapi.ai/models/suno). ### Separate vocals and instrument stems `POST /api/v1/audio/generations` · `model: "suno-vocal-separation"` Splits one generated track into vocal/accompaniment or per-instrument stems and returns one audio URL per stem. **Request** | Field | Type | Required | Notes | | ---------- | ------ | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-vocal-separation`. | | `taskId` | string | yes | reapi task id (`task_...`) of a completed Suno task that produced the track. Min length 1. | | `audioId` | string | yes | The track inside that task to process. Copy it from the parent task's `output.tracks[].id`. Min length 1. | | `type` | enum | no | Separation mode. `separate_vocal` (default) splits into 2 stems — vocals + instrumental. `split_stem` splits into up to 12 stems (vocals, backing vocals, drums, bass, guitar, keyboard, strings, brass, woodwinds, percussion, synth, FX/other). `split_stem_advanced` does multi-stem separation and can target one specific instrument via `stemName`. | | `stemName` | enum | conditional | The single instrument track to extract. Only meaningful with `type: "split_stem_advanced"`, where it is required. 98 accepted values covering vocals, drums, guitars, keys, strings, brass, woodwinds, percussion and synths — e.g. `Lead Vocal`, `Backing Vocals`, `Drum Kit`, `Kick`, `Bass`, `Piano`, `Electric Guitar`, `Synth Pad`, `Brass Section`, `Violin`, `Flute`, `808`. | **Response** `output.audio_urls` holds one URL per separated stem, index-aligned with `output.tracks[]`. Each entry in `output.tracks[]` carries `type: "audio"`, `url`, and `label` naming the stem. When upstream returns per-stem records, `label` is the upstream stem group name and the track also carries `id` and `duration`; otherwise `label` comes from the fixed set `origin`, `instrumental`, `vocals`, `backing_vocals`, `drums`, `bass`, `guitar`, `piano`, `keyboard`, `percussion`, `strings`, `synth`, `fx`, `brass`, `woodwinds`. Stems that upstream did not produce are simply absent — the array length varies with the mode and the source material. **Notes** — `stemName` is rejected as missing only when `type` is `split_stem_advanced`; the other two modes ignore it. Separation quality depends on the mix: cleanly separated AI mixes yield the best stems. The per-stem `id` values returned here are what you pass as `audioId` to `suno-midi`. ### Convert a track to WAV `POST /api/v1/audio/generations` · `model: "suno-wav"` Re-renders one generated track as an uncompressed WAV file for professional editing. **Request** | Field | Type | Required | Notes | | --------- | ------ | -------- | ------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-wav`. | | `taskId` | string | yes | reapi task id (`task_...`) of the completed Suno task that produced the track. Min length 1. | | `audioId` | string | yes | Which track in that task to convert. Copy it from the parent task's `output.tracks[].id`. Min length 1. | **Response** `output.audio_urls` holds a single URL pointing at the WAV file. No `output.tracks[]` is emitted for this operation. **Notes** — WAV files are typically 5–10× larger than the MP3 equivalent, and processing time scales with the length of the source track. ### Generate MIDI from separated stems `POST /api/v1/audio/generations` · `model: "suno-midi"` Transcribes separated audio into structured MIDI note data (pitch, timing, velocity) per detected instrument. **Request** | Field | Type | Required | Notes | | --------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-midi`. | | `taskId` | string | yes | reapi task id (`task_...`) of a completed **vocal-separation** task — not a music-generation task. Min length 1. | | `audioId` | string | no | Restricts transcription to one separated stem; take the value from that separation task's `output.tracks[].id`. Omit to transcribe all separated stems. Min length 1. | **Response** A structured text result, not audio: there is no `audio_urls` or `tracks`. On completion `output.result.midi` holds a `state` string and an `instruments[]` array. Each instrument has a `name` and a `notes[]` array whose entries carry `pitch` (MIDI note number, 0–127), `start` and `end` (seconds), and `velocity` (0–1). **Notes** — Separation must run first; passing the task id of a plain music-generation task is not valid input for this operation. Not every instrument is detected — the result reflects what is actually present in the source stems, and upstream notes that separations run with `type: "split_stem"` can yield no note data at all. If upstream completes with no note data, the task is reported as failed rather than completing with an empty result. ### Create a music video `POST /api/v1/audio/generations` · `model: "suno-music-video"` Renders one generated track into an MP4 with visualizations plus optional artist and brand attribution. **Request** | Field | Type | Required | Notes | | ------------ | ------ | -------- | --------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-music-video`. | | `taskId` | string | yes | reapi task id (`task_...`) of the completed Suno task that produced the track. Min length 1. | | `audioId` | string | yes | Which track in that task to visualize. Copy it from the parent task's `output.tracks[].id`. Min length 1. | | `author` | string | no | Artist or creator name shown as a signature on the video cover. 1–50 characters. | | `domainName` | string | no | Website or brand shown as a watermark at the bottom of the video. 1–50 characters. | **Response** `output.video_urls` holds a single URL pointing at the rendered MP4. **Notes** — Render time varies with the length of the source track. ### Generate cover art `POST /api/v1/audio/generations` · `model: "suno-cover-image"` Generates cover images for a completed music task; usually returns two stylistic variants to choose from. **Request** | Field | Type | Required | Notes | | -------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-cover-image`. | | `taskId` | string | yes | reapi task id (`task_...`) of the completed music-generation task to illustrate. Min length 1. Note this operation targets the task as a whole — there is no `audioId`. | **Response** `output.image_urls` holds the generated cover images, typically two. **Notes** — A cover can be generated only once per source task; a second request for the same `taskId` is rejected upstream rather than producing new images. Submit it after the music task has completed. ## Voice cloning Cloning a singing voice is a three-step chain, and each step is its own billable task (see [pricing](https://reapi.ai/models/suno)): 1. **`suno-voice-validate`** — submit the source recording and the vocal segment to analyse. The completed task returns a *validation phrase*. 2. **`suno-voice-generate`** — have the person record themselves reading (ideally singing) that phrase, host the recording at a public URL, and submit it as `verifyUrl` together with the reapi `taskId` of the step-1 task. The completed task returns a `voiceId`. 3. **`suno-voice-regenerate`** — only needed when a validation phrase failed or expired. The `voiceId` from step 2 is then used in the generation operations that accept a persona: pass it as `personaId` with `personaModel: "voice_persona"`. ### Step 1 — Generate a validation phrase `POST /api/v1/audio/generations` · `model: "suno-voice-validate"` Analyses the vocal segment of a source recording and returns the phrase the speaker must read aloud to verify the voice. **Request** | Field | Type | Required | Notes | | ------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-voice-validate`. | | `voiceUrl` | string | yes | Public `http(s)` URL of the source recording. Base64 / `data:` payloads are rejected. | | `vocalStartS` | integer | yes | Start time, in seconds, of the vocal segment to extract. `0` or greater. | | `vocalEndS` | integer | yes | End time, in seconds, of the vocal segment. Must be greater than `vocalStartS`. | | `language` | string | no | Language of the generated phrase. Upstream documents `en`, `zh`, `es`, `fr`, `pt`, `de`, `ja`, `ko`, `hi`, `ru`. | ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "suno-voice-validate", "voiceUrl": "https://example.com/audio/source_voice.mp3", "vocalStartS": 0, "vocalEndS": 10, "language": "en" }' ``` **Response** — a structured text result. When the task completes, `output.result.validateInfo` holds the phrase text to be read, and `output.result.status` holds the upstream state that made it terminal (`wait_validating` while the phrase awaits the reader, `success` once the whole flow has finished). **Notes** — `vocalEndS` must be strictly greater than `vocalStartS`; equal or inverted values are rejected before the task is created. Keep the reapi task id (`task_...`) returned by this call: step 2 references it, and it is the only handle you have on the phrase — the upstream phrase id is never exposed. ### Step 2 — Create the custom voice `POST /api/v1/audio/generations` · `model: "suno-voice-generate"` Submits the reader's verification recording against a completed validation task and produces a reusable custom voice. **Request** | Field | Type | Required | Notes | | ------------------ | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-voice-generate`. | | `taskId` | string | yes | Your reapi task id (`task_...`) from step 1 (or from a step-3 regeneration). Must be your own task, in `completed` status, from the same surface, and from the voice flow. | | `verifyUrl` | string | yes | Public `http(s)` URL of the recording of the person reading the `validateInfo` phrase. Singing the phrase rather than speaking it produces a more accurate voice profile. Base64 / `data:` payloads are rejected. | | `voiceName` | string | no | Display name for the voice. | | `description` | string | no | Free-text description of the voice. | | `style` | string | no | Voice style, e.g. `Pop, Female Vocal`. | | `singerSkillLevel` | enum | no | One of `beginner`, `intermediate`, `advanced`, `professional`. Upstream default is `beginner`. | ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "suno-voice-generate", "taskId": "task_abc123", "verifyUrl": "https://example.com/audio/verify_read.mp3", "voiceName": "My Voice", "description": "created from uploaded voice", "style": "Pop, Female Vocal", "singerSkillLevel": "beginner" }' ``` **Response** — a structured text result: `output.result.voiceId`, the identifier of the finished custom voice. **Notes** — feed `voiceId` back into a generation call as `personaId`, together with `personaModel: "voice_persona"`. The persona fields only apply in custom mode (`customMode: true`), and `personaModel` is only available on `V5` and `V5_5`. The `taskId` reference is resolved and rejected before any charge, so a bad or unfinished parent task costs nothing. A clean a-cappella take of the verification recording gives the most accurate voice profile. ### Step 3 — Regenerate the validation phrase `POST /api/v1/audio/generations` · `model: "suno-voice-regenerate"` Asks upstream for a fresh validation phrase on an existing voice task, for when the previous phrase failed or expired. **Request** | Field | Type | Required | Notes | | -------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Must be `suno-voice-regenerate`. | | `taskId` | string | yes | Your reapi task id (`task_...`) of an earlier voice-flow task. Same ownership / `completed` / voice-family checks as step 2. | ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "suno-voice-regenerate", "taskId": "task_abc123" }' ``` **Response** — a structured text result carrying the NEW phrase: the task completes with `output.result.validateInfo` (and its `status`), the same shape step 1 returns. **Notes** — this reissues the validation phrase, it does not produce a voice. Record yourself reading the new phrase and send that recording to step 2 (`suno-voice-generate`) with this task's id as `taskId`. Use it when the earlier phrase expired or the reading was rejected. ## Synchronous helpers These four operations do not run on `/api/v1/audio/generations` and have no task lifecycle — they answer inline on the same HTTP response, so there is nothing to poll. Each has its own route, accepts only the fields listed below (unknown fields are rejected), and returns `id` (the audit task id recording this call, `task_...`), `credits` (the credits charged), plus its result fields. A failed call is refunded in full. Pricing: [reapi.ai/models/suno](https://reapi.ai/models/suno). ```bash curl -X POST https://reapi.ai/api/v1/audio/suno/boost-style \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"content":"Pop, Mysterious"}' ``` ### Boost music style `POST /api/v1/audio/suno/boost-style` Expands a short style description into a richer, generation-ready style prompt and returns the enhanced text inline. **Request** | Field | Type | Required | Notes | | --------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `content` | string | yes | Style description to enhance, min 1 character. Describe the music style you expect in concise, clear language — e.g. `Pop, Mysterious`. | **Response** — `result`: the enhanced style text. Feed it into the `style` field of a generation request. ### Timestamped lyrics `POST /api/v1/audio/suno/timestamped-lyrics` Returns word-level time-aligned lyrics for one track of a completed song task. **Request** | Field | Type | Required | Notes | | --------- | ------ | -------- | ------------------------------------------------------------------------------------------------------- | | `taskId` | string | yes | Your reapi task id (`task_...`) of the completed song task the track belongs to, min 1 character. | | `audioId` | string | yes | Identifier of the specific track, min 1 character. Take it from the parent task's `output.tracks[].id`. | **Response** * `alignedWords`: array of aligned words, each with `word` (the lyric token), `success` (boolean, whether that token aligned), `startS` / `endS` (word start and end time in seconds), and `palign` (alignment parameter). * `waveformData`: array of numbers for audio visualisation, or `null` when upstream omits it. * `hootCer`: lyrics alignment accuracy score, or `null`. * `isStreamed`: whether the source is streaming audio, or `null`. **Notes** — `taskId` must name a Suno-family task you own that has reached `completed`; a task that is still running, or one from outside the Suno family, is rejected before any charge. Which Suno operation produced it is not gated here — upstream expects a music-generating parent (song or extend) and answers for the rest. `waveformData` is delivered inline only — it is deliberately not kept in the audit row, so a later `GET /api/v1/tasks/{id}` on this call's `id` returns the other three fields plus `waveform_omitted: true`. ### Generate persona `POST /api/v1/audio/suno/persona` Analyses a segment of an existing track and creates a reusable persona, returning its `personaId`. **Request** | Field | Type | Required | Notes | | ------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `taskId` | string | yes | Your reapi task id (`task_...`) of the completed song task to analyse, min 1 character. | | `audioId` | string | yes | Identifier of the track to build the persona from, min 1 character. Take it from the parent task's `output.tracks[].id`. | | `name` | string | yes | Name for the persona, min 1 character — something that captures the musical style or character, e.g. `Electronic Pop Singer`. | | `description` | string | yes | Description of the persona's musical characteristics, style and personality, min 1 character. Be specific about genre, mood, instrumentation and vocal qualities. | | `vocalStart` | number | no | Start of the analysis segment in seconds, `>= 0`. Defaults to `0`. | | `vocalEnd` | number | no | End of the analysis segment in seconds, `>= 0`. Defaults to `30`. | | `style` | string | no | Supplementary style tag for the persona, min 1 character — e.g. `Electronic Pop`, `Jazz Trio`. | **Response** — `personaId`: the persona identifier, reusable in the `personaId` field of the song, extend, upload-cover and upload-extend operations. `name` and `description` echo the request (each `null` if upstream omits it). **Notes** — the analysis window is validated before charging: `vocalEnd - vocalStart` must be between 10 and 30 seconds inclusive, using the defaults `0` and `30` for whichever bound you omit. Setting only `vocalStart: 25` therefore fails (window is 5s), while `vocalStart: 25, vocalEnd: 40` succeeds. `taskId` must name a completed Suno task you own. ### Check voice availability `POST /api/v1/audio/suno/check-voice` Reports whether a custom voice produced by a completed voice task is ready to use. **Request** | Field | Type | Required | Notes | | --------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `task_id` | string | yes | Your reapi task id (`task_...`) of the completed voice task to check, min 1 character. This endpoint's field is snake\_case `task_id` — the rest of the surface is camelCase. | **Response** — `isAvailable`: boolean, whether the generated voice is available. **Notes** — `task_id` must resolve to a completed **voice-family** task you own — in practice the `suno-voice-generate` or `suno-voice-regenerate` task that produced the voice; a song task is rejected before any charge. ## Output schema Asynchronous results land on `GET /api/v1/tasks/{id}`: ```json { "id": "task_...", "status": "completed", "output": { "audio_urls": ["https://..."], "tracks": [ { "id": "track id — reuse as audioId", "url": "https://...", "title": "Midnight Drive", "duration": 128.5, "tags": "synthwave, dreamy", "lyrics": "..." } ] }, "error": null } ``` Music videos populate `output.video_urls`, cover art `output.image_urls`; lyric / MIDI / voice tasks return a structured text `output` (e.g. `{ "lyrics": [...] }`, `{ "midi": ... }`, `{ "voiceId": "..." }`, `{ "validateInfo": "..." }`). ## Pricing dimensions Every operation bills a flat rate per request — nothing scales with duration or output length. Generation-class operations (music, extend, covers, vocals, mashup) share one rate covering both returned tracks; section replacement, stem separation (three tiers by `type`), music video, sound effects, lyrics, WAV conversion, and the utility operations each have their own flat rate. Bill formula: `credits = price_usd × 1000` (1 credit = $0.001). Current rates: [Suno model page](/models/suno). ## Errors Failures use the standard envelope `{ "error": { "code", "message", "request_id" } }` — see the [error catalog](/docs/api/errors). Notable cases: content flagged by moderation returns a policy error (80006); malformed parameter combinations surface 80007 with the upstream reason; upstream generation failures (80003) are refunded automatically. ## Tips * Start in inspiration mode (`customMode: false`) — one prompt line is enough. Switch to custom mode when you need exact lyrics. * `style` reads best as comma-separated genre + mood + vocal tags (`"synthwave, dreamy, female vocal"`). Use the boost-style helper to expand a rough idea. * Save `output.tracks[].id` — every downstream operation needs it. * For extensions, pick `continueAt` a beat before the natural end of the source so the transition lands cleanly. * Instrumental-only? Set `instrumental: true` and skip lyrics entirely. ## Related * [Mureka V9 Song](/docs/mureka-v9-song) — lyrics-first song generation * [Music Video 1.0](/docs/music-video-1-0) — song + images → MV * [Vocal Remover](/docs/vocal-remover) — standalone stem separation --- # topaz-video-upscaler (https://reapi.ai/docs/topaz-video-upscaler) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Topaz Video Upscaler upscales and enhances a **source video** — restoring > detail and pushing resolution toward 4K. One async endpoint, two parameters: > a `video_url` and an `upscale_factor` (`"1"` / `"2"` / `"4"`). Billing is per > second of the source clip's server-probed length × the upscale tier. See > current pricing on the > [model page](https://reapi.ai/models/topaz-video-upscaler). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "topaz-video-upscaler", "video_url": "https://your-cdn.com/source-480p.mp4", "upscale_factor": "2" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "topaz-video-upscaler", "video_url": "https://your-cdn.com/source-480p.mp4", "upscale_factor": "2", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "topaz-video-upscaler", video_url: "https://your-cdn.com/source-480p.mp4", upscale_factor: "2", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "topaz-video-upscaler", "video_url": "https://your-cdn.com/source-480p.mp4", "upscale_factor": "2", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "topaz-video-upscaler", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the upscaled MP4 URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Request body ### `model` — required `string`. Must be `"topaz-video-upscaler"`. ### `video_url` — required `string`. Public HTTP(S) URL of the **source video** to upscale — MP4, MOV, or MKV, up to 50MB. The output preserves the source clip's duration and frame timing. The **billable second count is the source video's server-probed duration**, not a client estimate. **No `data:` URIs.** reApi rejects base64 inputs platform-wide. Upload to public storage (your own CDN, S3, R2…) and pass the URL. ### `upscale_factor` — string, default `"2"` How much each frame is enlarged. The factor also selects the per-second pricing tier. | Value | Behavior | Tier | | ----- | ----------------------------------------------- | ----------- | | `"1"` | Clean and restore detail at the same resolution | `1×` / `2×` | | `"2"` | Double each dimension (default) | `1×` / `2×` | | `"4"` | Enlarge 4× toward 4K | `4×` | `"1"` and `"2"` share one per-second rate; `"4"` is a higher tier. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "topaz-video-upscaler", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | *** ## Pricing Per-second × upscale tier. The billable second count is the source video's **server-probed** length — reApi measures the uploaded clip server-side rather than trusting a client value. The `1×` / `2×` factors share one per-second rate; `4×` is a higher tier. **Bill formula** (1 credit = $0.001): ``` billable_seconds = ceil(server_probed_source_seconds) bill_usd = per_second_usd(tier) × billable_seconds // tier from upscale_factor credits = ceil(bill_usd × 1000) ``` See current per-second rates for each tier on the [model page](https://reapi.ai/models/topaz-video-upscaler). Failed jobs refund automatically. A probe failure returns `400 PRICING_UNAVAILABLE` (code `30002`) with no charge. The playground's draft estimate may show a default before the upload finishes — the authoritative number is computed at submit, after the server probes the file. *** ## Validation errors All cases below return HTTP 400. Pattern-match on `code`, not `message` — message strings carry request-specific context and are not a stable contract. | Trigger | Code | Message (illustrative) | | ------------------------------------------------ | ------- | --------------------------------------------------------------- | | `video_url` missing | `20002` | `topaz-video-upscaler: video_url is required` | | `video_url` carrying a `data:` URI / non-public | `20003` | `topaz-video-upscaler: video_url must be a public http(s) URL` | | `upscale_factor` not one of `1` / `2` / `4` | `20003` | `topaz-video-upscaler: invalid upscale_factor (allowed: 1/2/4)` | | Source video probe fails (network / format) | `30002` | `Could not determine source video duration for billing: …` | | Source video too large / unsupported by upstream | `80007` | Provider rejected the request as invalid | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### Minimum request (2× default) ```json { "model": "topaz-video-upscaler", "video_url": "https://your-cdn.com/source-480p.mp4" } ``` ### Same-size cleanup (1×) ```json { "model": "topaz-video-upscaler", "video_url": "https://your-cdn.com/source-1080p-grainy.mp4", "upscale_factor": "1" } ``` ### Push to 4K (4×) ```json { "model": "topaz-video-upscaler", "video_url": "https://your-cdn.com/source-540p.mp4", "upscale_factor": "4" } ``` *** ## Tips * **Cost tracks the source clip.** A 6s source bills \~6 seconds; trim or compress long footage before submitting to cap spend. * **Pick the factor by need.** `1×` restores detail at the same size, `2×` is the balanced default, `4×` targets 4K from low-resolution sources. * **Mind the 50MB input cap.** Re-encode or split oversized clips; the upstream rejects files over the limit (`80007`), refunded automatically. * **Length is preserved.** Upscaling changes resolution and detail, not duration — a 10s input returns a 10s output. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) --- # Veo 3.1 (https://reapi.ai/docs/veo3-1) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Google's VEO 3.1 video model on reAPI. **Five channels** share one > endpoint and submit shape — pick the channel via `model`. > > | Channel | Bills | Notes | > | ------------------------- | -------------- | ------------------------------------- | > | `veo3.1-fast` | per generation | Image-to-video (≤ 3 refs), remix-able | > | `veo3.1-quality` | per generation | Frame-mode I2V only, remix-able | > | `veo3.1-lite` | per generation | Prompt-only — no images | > | `veo3.1-fast-official` | per second | First/last-frame I2V, audio, 4K | > | `veo3.1-quality-official` | per second | Premium per-second tier | > > 8-second outputs on alt channels (4 / 6 / 8 seconds on official) at > 720p / 1080p / 4K. Use the [remix endpoint](#remix) to extend Fast > or Quality clips to 15 seconds. See current pricing on the > [model page](https://reapi.ai/models/veo3-1). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "veo3.1-fast", "prompt": "A dolphin leaping through cobalt ocean waves at sunrise", "aspect_ratio": "16:9", "resolution": "720p" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "veo3.1-fast", "prompt": "A dolphin leaping through cobalt ocean waves at sunrise", "aspect_ratio": "16:9", "resolution": "720p", }, ) task_id = resp.json()["data"][0]["task_id"] ``` ```js const res = await fetch('https://reapi.ai/api/v1/videos/generations', { method: 'POST', headers: { Authorization: 'Bearer rk_live_xxx', 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'veo3.1-fast', prompt: 'A dolphin leaping through cobalt ocean waves at sunrise', aspect_ratio: '16:9', resolution: '720p', }), }); const { data } = await res.json(); const taskId = data[0].task_id; ``` ```go package main import ( "bytes" "encoding/json" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "veo3.1-fast", "prompt": "A dolphin leaping through cobalt ocean waves at sunrise", "aspect_ratio": "16:9", "resolution": "720p", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) _ = out } ``` ## Endpoint `POST /api/v1/videos/generations` Returns a `task_id` immediately. Poll `GET /api/v1/tasks/{task_id}` until `status` is `completed` to retrieve the video URL. ## Request fields ### Common (every channel) | Field | Type | Required | Notes | | -------------- | ------ | -------- | ------------------------------------ | | `model` | string | yes | One of the five channel ids above | | `prompt` | string | yes | ≤ 4000 chars; English recommended | | `aspect_ratio` | enum | no | `16:9` (default landscape) or `9:16` | | `resolution` | enum | no | `720p` (default), `1080p`, or `4k` | ### Alt channels (`veo3.1-fast`, `veo3.1-quality`, `veo3.1-lite`) | Field | Type | Notes | | ----------------- | --------- | ------------------------------------------------------ | | `duration` | int | Fixed at `8` upstream | | `image_urls` | string\[] | Up to 3 public http(s) URLs (Fast / Quality only) | | `generation_type` | enum | `frame` or `reference` (Quality channel: `frame` only) | | `enable_gif` | bool | Output GIF instead of mp4. Mutex with `1080p` / `4k` | `veo3.1-lite` rejects `image_urls` and `generation_type`. Send only `prompt` + the common fields. ### Official channels (`veo3.1-fast-official`, `veo3.1-quality-official`) | Field | Type | Notes | | ------------------- | ------ | -------------------------------------------------- | | `duration` | int | `4`, `6`, or `8` (default `8`) | | `negative_prompt` | string | What to avoid | | `first_frame_image` | string | Public http(s) URL — anchors opening frame | | `last_frame_image` | string | Requires `first_frame_image`; interpolation target | | `seed` | int | `0`–`4294967295` | | `sample_count` | int | `1`–`4` (default `1`) | | `generate_audio` | bool | Adds synthesized audio (audio pricing tier) | | `person_generation` | enum | `allow_adult` (default) or `disallow` | | `resize_mode` | enum | `pad` (default) or `crop` | | `enhance_prompt` | bool | Must be `true` if sent — omit to disable | **Image inputs are URLs only.** Every reference image / frame field rejects base64 and `data:` URIs at the gateway. Upload the image to any public HTTPS host first. ## Image-to-video — alt channel ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "veo3.1-fast", "prompt": "The cat slowly walks forward and looks around", "image_urls": ["https://example.com/cat.png"], "generation_type": "frame", "aspect_ratio": "16:9", "resolution": "720p" }' ``` ## Image-to-video — official channel (first / last frame) ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "veo3.1-quality-official", "prompt": "Smooth cinematic transition from the first frame to the last frame", "first_frame_image": "https://example.com/start.png", "last_frame_image": "https://example.com/end.png", "aspect_ratio": "16:9", "resolution": "1080p", "duration": 8, "generate_audio": true }' ``` ## Remix — extend an 8s clip to 15s `POST /api/v1/videos/{task_id}/remix` Available on `veo3.1-fast` and `veo3.1-quality` only. The path `task_id` is the reApi task id returned by the original generation; the source task must be in `completed` status. The `model` in the body must match the source task's model. ```bash curl https://reapi.ai/api/v1/videos/{TASK_ID}/remix \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "veo3.1-fast", "prompt": "The dolphin dives back into the wave and surfaces a moment later", "raw": false, "aspect_ratio": "16:9", "resolution": "720p" }' ``` | Field | Type | Notes | | -------------- | ------ | -------------------------------------------------------------------------------------- | | `model` | enum | `veo3.1-fast` or `veo3.1-quality` — must equal source | | `prompt` | string | Continuation prompt; ≤ 4000 chars | | `raw` | bool | `true` returns only the extension segment; `false` (default) returns the combined clip | | `aspect_ratio` | enum | Optional — same set as generations | | `resolution` | enum | Optional — same set as generations | The remix endpoint returns a fresh `task_id`. Poll `GET /api/v1/tasks/{task_id}` exactly like a generation. ## Polling ```bash curl https://reapi.ai/api/v1/tasks/{TASK_ID} \ -H "Authorization: Bearer rk_live_xxx" ``` Response while in flight: ```json { "code": 200, "data": { "id": "task_…", "status": "processing", "progress": 47 } } ``` Response on success: ```json { "code": 200, "data": { "id": "task_…", "status": "completed", "result": { "videos": [{ "url": ["https://cdn.reapi.ai/…/video.mp4"] }] } } } ``` Generated video URLs are rehosted to reApi's CDN — they don't expire with the upstream signed-URL window. --- # viduq3 (https://reapi.ai/docs/viduq3) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Vidu Q3 — async video generation. **Two variants** (`viduq3-pro`, > `viduq3-turbo`) share one endpoint and one parameter shape. Mode is > implicit: the number of `image_urls` you send picks **T2V**, **I2V**, or > **first/last-frame** transition. 1–16 second outputs at 540p / 720p / > 1080p, audio-on by default. See current pricing on the > [model page](https://reapi.ai/models/viduq3). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "viduq3-pro", "prompt": "A kitten playing piano, slow camera push-in", "duration": 8, "resolution": "1080p", "aspect_ratio": "16:9" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer rk_live_xxx", "Content-Type": "application/json", }, json={ "model": "viduq3-pro", "prompt": "A kitten playing piano, slow camera push-in", "duration": 8, "resolution": "1080p", "aspect_ratio": "16:9", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer rk_live_xxx", "Content-Type": "application/json", }, body: JSON.stringify({ model: "viduq3-pro", prompt: "A kitten playing piano, slow camera push-in", duration: 8, resolution: "1080p", aspect_ratio: "16:9", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "viduq3-pro", "prompt": "A kitten playing piano, slow camera push-in", "duration": 8, "resolution": "1080p", "aspect_ratio": "16:9", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer rk_live_xxx") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "viduq3-pro", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URL, valid for 7 days. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` Keys carry the active workspace's billing scope — there is no separate project header. *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Variants Both variants share one parameter shape; pick via `model`: | Variant | Speed | Resolutions | Notes | | -------------- | -------- | ------------------- | --------------------- | | `viduq3-pro` | standard | 540p / 720p / 1080p | Highest fidelity | | `viduq3-turbo` | faster | 540p / 720p / 1080p | Lower per-second cost | reAPI never silently substitutes one variant for another — what you send in `model` is what gets billed and forwarded. *** ## Mode routing `viduq3` picks its mode from the **count of `image_urls`** you send — there is no `mode` parameter: | `image_urls` count | Mode | What it does | | ------------------ | -------------- | --------------------------------------------- | | `0` (or omitted) | **T2V** | Generate from text. `aspect_ratio` allowed. | | `1` | **I2V** | Animate from a single starting frame. | | `2` | **First/Last** | Transition between two frames (first → last). | **Mutex rules.** * In T2V (no `image_urls`), `prompt` is **required**. * When `image_urls` is set (1 or 2 entries), `aspect_ratio` is **rejected** with `400` — the source frame's ratio decides the output ratio. * More than 2 `image_urls` is rejected with `400 image_urls accepts at most 2 entries`. *** ## Request body ### `model` — required `string`. One of `"viduq3-pro"` or `"viduq3-turbo"`. ### `prompt` — string, conditional Up to **2,000 characters**. Required in T2V (when `image_urls` is empty); optional in I2V and First/Last when at least one image is provided. Empty / whitespace-only prompts are treated as missing. **Failure modes.** * Empty / missing in T2V → `400 prompt is required when image_urls is empty (text-to-video)` (code `20002`). * Longer than 2,000 chars → `400 prompt exceeds 2000 characters (got N)` (code `20007`). ### `duration` — integer, default `5` Output length in seconds. Any integer in `[1, 16]`. Out-of-range → `400`. Drives pricing linearly: `ceil(per_second_usd × duration × 1000)` credits (1 credit = $0.001). ### `resolution` — string, default `"720p"` `540p` / `720p` / `1080p`. Drives pricing. Lowercase is canonical; uppercase forms (`"1080P"`) are accepted and normalized. ### `aspect_ratio` — string, T2V only Output ratio in T2V mode. One of: | Value | Shape | | ------ | --------------------- | | `16:9` | Landscape | | `9:16` | Portrait | | `4:3` | Traditional landscape | | `3:4` | Traditional portrait | | `1:1` | Square | **Only valid when `image_urls` is empty.** In I2V and First/Last modes the upstream derives the ratio from the source frame and rejects this field with `400 aspect_ratio is only allowed in text-to-video mode` (code `20003`). ### `image_urls` — string\[] Array of public HTTP(S) URLs. **0 to 2 entries**: * **0 entries** — pure text-to-video. * **1 entry** — image-to-video; the image is treated as the first frame. * **2 entries** — first/last-frame transition. The first URL is the starting frame; the second URL is the ending frame. **No `data:` URIs.** reAPI rejects base64 inputs platform-wide — every URL field on this endpoint must be a public HTTP(S) URL. Upload to your own object storage (S3, R2, OSS, …) and pass the URL. ### `audio` — boolean, default `true` When `true`, the model synthesizes an audio track (dialogue, sound effects) that plays alongside the generated video. Set to `false` for silent output. Audio generation does not change the per-second rate. ### `seed` — integer Reproducibility hint. Range `[-1, 4294967295]`. Same seed plus an otherwise identical request returns a similar (not bit-for-bit identical) result. Use `-1` (or omit) for full randomness. *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "viduq3-pro", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | `output.video_urls` URLs are valid for **7 days**. Re-host to your own storage if you need them longer. *** ## Validation errors All cases below return HTTP 400 with code `20003` unless noted. Pattern-match on `code`, not `message` — message strings carry request-specific context (field names, observed values, etc.) and are not a stable contract. | Trigger | Code | Message (illustrative) | | -------------------------------------------------- | ------- | --------------------------------------------------------------------------------------- | | `prompt` missing in T2V | `20002` | `viduq3: prompt is required when image_urls is empty (text-to-video)` | | `prompt` longer than 2,000 chars | `20007` | `viduq3: prompt exceeds 2000 characters (got N)` | | `image_urls` length > 2 | `20003` | `viduq3: image_urls accepts at most 2 entries, got N` | | `aspect_ratio` set with `image_urls` non-empty | `20003` | `viduq3: aspect_ratio is only allowed in text-to-video mode (image_urls must be empty)` | | `duration` outside `[1, 16]` | `20003` | `viduq3: duration must be 1-16 seconds, got N` | | Unknown `resolution` | `20003` | `viduq3: invalid resolution "X" (allowed: 540p / 720p / 1080p)` | | Unknown `aspect_ratio` | `20003` | `viduq3: invalid aspect_ratio "X" (allowed: 16:9 / 9:16 / 4:3 / 3:4 / 1:1)` | | `seed` outside `[-1, 4294967295]` | `20003` | `viduq3: seed must be in [-1, 4294967295], got N` | | `image_urls` carrying a `data:` URI or non-http(s) | `20003` | `viduq3: image_urls entries must be public http(s) URLs` | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### T2V — minimum request ```json { "model": "viduq3-pro", "prompt": "A little girl walking down a sunset coastal road" } ``` ### T2V — full parameters ```json { "model": "viduq3-pro", "prompt": "A kitten playing piano, slow camera push-in, cinematic warm tones", "duration": 8, "resolution": "1080p", "aspect_ratio": "16:9", "audio": true, "seed": 42 } ``` ### I2V — animate a single frame ```json { "model": "viduq3-pro", "prompt": "Bring the scene to life with a gentle camera dolly forward", "image_urls": ["https://your-cdn.com/first_frame.jpg"], "duration": 5, "resolution": "1080p" } ``` ### First/Last-frame transition ```json { "model": "viduq3-pro", "prompt": "Smooth motion from standing to seated", "image_urls": [ "https://your-cdn.com/standing.jpg", "https://your-cdn.com/seated.jpg" ], "duration": 8 } ``` ### Silent video — disable audio ```json { "model": "viduq3-pro", "prompt": "Sunset timelapse over the ocean", "duration": 10, "resolution": "1080p", "audio": false } ``` ### Turbo — cost-conscious ```json { "model": "viduq3-turbo", "prompt": "Waves crashing on a beach at sunset, wide shot", "duration": 5, "resolution": "720p" } ``` *** ## Choosing a mode | Need | Send | | ------------------------------------ | ---------------------------------------------------------------- | | Generate from text | `prompt` only (T2V) — `aspect_ratio` allowed | | Animate a still | `prompt + image_urls` (1 entry) (I2V) | | Smooth transition between two frames | `image_urls` (2 entries) (First/Last) | | Cut spend | Switch to `viduq3-turbo` or drop `resolution` to `720p` / `540p` | *** ## Polling pattern The task endpoint behaves identically to other video tasks — the only difference is the completed `output` shape (`video_urls` instead of `image_urls`). A pragmatic schedule: ``` 0–5 minutes: poll every 5s 5 min – 1 h: back off gradually toward 1 min ≥ 1 h: cap at 3 min between polls ``` A typical task completes in a few minutes. The worker's wall-clock cap is **48 hours**, comfortably above any realistic queue. *** ## Pricing Per-second × resolution. Mode does **not** change the rate. Turbo undercuts Pro at every tier. See current rates on the [Vidu Q3 model page](https://reapi.ai/models/viduq3). **Bill formula** (1 credit = $0.001): ``` credits = ceil(per_second_usd × duration × 1000) ``` Failed jobs refund automatically. *** ## Tips * **Prompt motion, not just scene.** "Slow push-in, warm tones, shallow depth of field" outperforms a pure noun-list of what's on screen. * **Sweet-spot duration: 5–10 seconds.** Below 5s motion looks choppy; above 10s the upstream wall-time grows fast. * **First-frame quality matters.** Subject centered, clear composition, no heavy filters — I2V output quality tracks input quality directly. * **Two frames need to make sense as endpoints.** First/Last works best when the two frames share enough subject and composition that the model can interpolate motion between them — wildly different shots produce abrupt transitions. * **Pick Turbo first if you're iterating.** It's roughly half the cost per second; lock the prompt on Turbo, then re-render the keeper on Pro at the resolution you'll ship. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # Vocal Remover API (https://reapi.ai/docs/vocal-remover) # Vocal Remover API Use `audio-stem-separator` with `stem: "vocals"` to isolate vocals and receive downloadable audio tracks through the universal task flow. ## Endpoint ```http POST /api/v1/audio/generations ``` Poll the returned task: ```http GET /api/v1/tasks/{id} ``` ## Example ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer $REAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "audio-stem-separator", "audio_url": "https://cdn.example.com/song.wav", "stem": "vocals", "encoder_format": "mp3" }' ``` ## Parameters | Field | Type | Required | Notes | | ------------------ | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Use `audio-stem-separator`. | | `audio_url` | URL | yes | Public HTTP(S) source audio URL. | | `stem` | enum | yes | Use `vocals` for this API page. | | `splitter` | enum | no | `auto`, `andromeda`, `perseus`, `orion`, `phoenix`, `lyra`, or `lynx`. `auto` is omitted upstream so the default engine is used. | | `extraction_level` | enum | no | `deep_extraction` or `clear_cut`. Defaults to `deep_extraction`. | | `multivocal` | string | no | `lead_back`. Only valid with `stem: "vocals"`. | | `dereverb_enabled` | boolean | no | Enable dereverb cleanup. | | `encoder_format` | enum | no | `mp3`, `wav`, `flac`, `aac`, or `ogg`. | ## Output Completed tasks return `output.audio_urls`. When labels are available, `output.tracks` includes `type`, `label`, and `url` for each track. Audio jobs are billed per rounded-up source minute. See current rate on the [Vocal Remover model page](https://reapi.ai/models/vocal-remover). --- # Voice Changer API (https://reapi.ai/docs/voice-changer) # Voice Changer API Use `audio-voice-change` to convert vocals with a configured voice pack. ## Endpoint ```http POST /api/v1/audio/generations ``` Poll completion with: ```http GET /api/v1/tasks/{id} ``` ## Example ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer $REAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "audio-voice-change", "audio_url": "https://cdn.example.com/source-vocal.wav", "voice_pack_id": "voice_pack_id_here", "accent": 1, "encoder_format": "mp3" }' ``` ## Parameters | Field | Type | Required | Notes | | -------------------- | ------- | -------- | --------------------------------------------------------- | | `model` | string | yes | Use `audio-voice-change`. | | `audio_url` | URL | yes | Public HTTP(S) source vocal URL. | | `voice_pack_id` | string | yes | Target voice pack id. | | `accent` | number | no | 0 to 1. Defaults to `1`. | | `tonality_reference` | enum | no | `source_file` or `voice_pack`. Defaults to `source_file`. | | `dereverb_enabled` | boolean | no | Enable dereverb cleanup. | | `encoder_format` | enum | no | `mp3`, `wav`, `flac`, `aac`, or `ogg`. | ## Output Completed tasks return `output.audio_urls` and, when available, labeled `output.tracks`. Audio jobs are billed per rounded-up source minute. See current rate on the [Voice Changer model page](https://reapi.ai/models/voice-changer). --- # Voice Cleaner API (https://reapi.ai/docs/voice-cleaner) # Voice Cleaner API Use `audio-voice-clean` for speech cleanup before publishing, transcription, voiceover preparation, or downstream editing. ## Endpoint ```http POST /api/v1/audio/generations ``` Poll completion with: ```http GET /api/v1/tasks/{id} ``` ## Example ```bash curl https://reapi.ai/api/v1/audio/generations \ -H "Authorization: Bearer $REAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "audio-voice-clean", "audio_url": "https://cdn.example.com/podcast.wav", "noise_cancelling_level": 1, "encoder_format": "mp3" }' ``` ## Parameters | Field | Type | Required | Notes | | ------------------------ | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `model` | string | yes | Use `audio-voice-clean`. | | `audio_url` | URL | yes | Public HTTP(S) source audio URL. | | `noise_cancelling_level` | integer | no | `0`, `1`, or `2`. Defaults to `0`. | | `splitter` | enum | no | `auto`, `andromeda`, `perseus`, `orion`, `phoenix`, `lyra`, or `lynx`. `auto` is omitted upstream so the default engine is used. | | `dereverb_enabled` | boolean | no | Enable dereverb cleanup. | | `encoder_format` | enum | no | `mp3`, `wav`, `flac`, `aac`, or `ogg`. | ## Output Completed tasks return `output.audio_urls` and, when available, labeled `output.tracks`. Audio jobs are billed per rounded-up source minute. See current rate on the [Voice Cleaner model page](https://reapi.ai/models/voice-cleaner). --- # wan-2-7-image (https://reapi.ai/docs/wan-2-7-image) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Alibaba's Wan image model on reAPI — one async endpoint for **generation and > editing**. Text-to-image, **image editing**, **multi-image reference fusion**, > **interactive region edits** (`bbox_list`), and **group series**. Two tiers: > `wan2.7-image` (1K / 2K) and `wan2.7-image-pro` (text-to-image up to **4K**). > Submit returns a `task_id`; poll until ready. See current pricing on the > [model page](https://reapi.ai/models/wan-2-7-image). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "wan2.7-image-pro", "prompt": "a flower shop with delicate windows and a beautiful wooden door, blossoms out front", "size": "16:9", "resolution": "2K", "n": 1 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "wan2.7-image-pro", "prompt": "a flower shop with delicate windows and a beautiful wooden door, blossoms out front", "size": "16:9", "resolution": "2K", "n": 1, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "wan2.7-image-pro", prompt: "a flower shop with delicate windows and a beautiful wooden door, blossoms out front", size: "16:9", resolution: "2K", n: 1, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "wan2.7-image-pro", "prompt": "a flower shop with delicate windows and a beautiful wooden door, blossoms out front", "size": "16:9", "resolution": "2K", "n": 1, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "wan2.7-image-pro", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.image_urls` holds the generated image URLs. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/images/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Tiers Two model ids share one parameter shape: | Model id | Tier | Resolution | | ------------------ | -------- | -------------------------------------------------------- | | `wan2.7-image` | Standard | 1K / 2K (all modes) | | `wan2.7-image-pro` | Pro | text-to-image up to 4K; editing and group modes up to 2K | Pick Pro for hero / print-grade detail and 4K; Standard for fast everyday work. ## Modes There is no `mode` field — the mode is implicit in the request shape: * **Text-to-image** — no `image_urls`. `prompt` is required. * **Editing / multi-image reference** — pass `image_urls`. `prompt` is optional (recommended). The output aspect ratio follows the **last** input image. * **Interactive region editing** — add `bbox_list` to target exact regions. * **Group series** — set `enable_sequential: true` for a consistent connected set; raises the `n` cap to 12. *** ## Request body ### `model` — string, required One of `wan2.7-image` or `wan2.7-image-pro`. ### `prompt` — string Up to **5,000 characters**. Required for text-to-image (no `image_urls`); optional but recommended in editing mode. ### `image_urls` — array, optional Reference images for editing / multi-image fusion. **Public HTTPS URLs only** — base64 / `data:` URIs are rejected at the gateway. Up to **9** images. Passing any image switches the request to editing mode. ### `n` — integer, default `1` Images per call. Range `[1, 4]` normally; up to `[1, 12]` when `enable_sequential` is `true`. Billed per generated image. ### `size` — string Output sizing. Polymorphic per the model: * a gear keyword — `1K` / `2K` / `4K` * an aspect ratio — `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` * a pixel value — `1024x1024` Pair an aspect ratio here with the quality gear in `resolution`. ### `resolution` — string Quality gear: `1K` / `2K` / `4K` (case-insensitive). **4K is `wan2.7-image-pro` text-to-image only.** In editing and group modes, and on the `wan2.7-image` (standard) tier, the maximum is 2K. ### `negative_prompt` — string, optional What to keep out of the image, e.g. `"blurry, distorted, low quality"`. ### `watermark` — boolean, default `false` Set `true` to add an AI-generated watermark to the bottom-right corner. ### `seed` — integer, optional Range `[0, 2147483647]`. The same seed with the same parameters yields a similar, stable result. ### `thinking_mode` — boolean, default `true` Enables extra reasoning for higher image quality. Only effective for text-to-image with no reference image and outside group mode; ignored otherwise. ### `enable_sequential` — boolean, default `false` Turns on group mode — a consistent, connected series in one call. Raises the `n` cap to 12. In group mode `thinking_mode` and `color_palette` do not apply. ### `bbox_list` — array, optional Interactive-edit regions. A list parallel to `image_urls` — one entry per input image — where each entry is a list of up to two boxes, and each box is `[x1, y1, x2, y2]` in absolute pixels with origin at the top-left. Use `[]` for an image you are not boxing. ```json { "image_urls": [ "https://example.com/clock.webp", "https://example.com/desk.webp" ], "bbox_list": [ [], [[989, 515, 1138, 681]] ] } ``` ### `color_palette` — array, optional Steer the image toward a custom palette. 3-10 items of `{ hex, ratio }` where `ratio` is a percentage string and all ratios sum to `100.00%`. Non-group mode only. ```json { "color_palette": [ { "hex": "#C2D1E6", "ratio": "23.51%" }, { "hex": "#636574", "ratio": "76.49%" } ] } ``` *** ## Pricing Wan 2.7 Image bills a flat rate **per successfully generated image**, independent of resolution and aspect ratio. Total charge is the per-image rate times `n`: ``` credits = ceil(per_image_usd × n × 1000) ``` where `1 credit = $0.001 USD`. The Pro tier carries a higher per-image rate than Standard. Failed and rejected requests are not charged. The exact per-image credit cost for each tier surfaces on the [model page](https://reapi.ai/models/wan-2-7-image) and through the playground estimator before submit. *** ## Response The poll envelope returns image URLs in `output.image_urls`: ```json { "id": "task_019dfd44b7fd74168541552a3260a623", "model": "wan2.7-image-pro", "status": "completed", "output": { "image_urls": [ "https://cdn.reapi.ai/...png" ] } } ``` For a group-mode request (`enable_sequential: true`, `n > 1`), `image_urls` holds the full series in order. Mirror the URLs to your own storage if you need long-term retention. *** ## Errors Failures return the standard reAPI envelope `{ error: { code, message, request_id } }`. Common cases: * Invalid input (out-of-range `n`, 4K requested in edit/group mode, a `bbox_list` whose length does not match `image_urls`, a non-HTTPS media URL) → `400`. * Insufficient credits → `402`. * Rate limited → `429`. See the full catalog at [/docs/api/errors](/docs/api/errors). *** ## Tips * The mode is decided by your inputs, not a flag — omit `image_urls` for pure generation, include it to edit. * For precise edits, prefer `bbox_list` over describing the location in the prompt — boxed regions composite with matched lighting and perspective. * For storyboards and comic panels, use group mode (`enable_sequential: true`) so the series stays on-model in one call instead of stitching separate requests. * Reach for `wan2.7-image-pro` at `resolution: "4K"` (text-to-image) when the asset goes to print or a retina display; use `wan2.7-image` for fast drafts. *** ## Related * [Image generation models](/docs/gpt-image-2) * [Seedream 5.0 Lite](/docs/seedream-5-0-lite) * [Tasks API](/docs/api/tasks) * [Error codes](/docs/api/errors) --- # wan-2-7-video (https://reapi.ai/docs/wan-2-7-video) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Wan 2.7 Video is a single umbrella model (`wan2.7-video`) that auto-routes by > request shape into **text-to-video**, **image-to-video**, > **reference-to-video**, and **video editing**. One async endpoint, 720P or > 1080P output, billed per second. See current pricing on the > [model page](https://reapi.ai/models/wan-2-7-video). ## Quick example ```bash curl https://reapi.ai/api/v1/videos/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "wan2.7-video", "prompt": "a paper boat drifting down a rain-soaked street at dusk, neon reflections, slow dolly-in, cinematic", "resolution": "1080P", "duration": 5 }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "wan2.7-video", "prompt": "a paper boat drifting down a rain-soaked street at dusk", "resolution": "1080P", "duration": 5, }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/videos/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "wan2.7-video", prompt: "a paper boat drifting down a rain-soaked street at dusk", resolution: "1080P", duration: 5, }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "wan2.7-video", "prompt": "a paper boat drifting down a rain-soaked street at dusk", "resolution": "1080P", "duration": 5, }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "wan2.7-video", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.video_urls` holds the generated MP4 URLs. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/videos/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. *** ## Modes There is no `mode` field. The umbrella model `wan2.7-video` infers the mode from **which inputs you send**: | Mode | Trigger | Notes | | ------------------ | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | | Text-to-video | `prompt` only | A prompt alone renders a clip. | | Image-to-video | `image_urls` / `image_with_roles` / `video_urls` (and `audio_url`) | Animate a still, set first/last frame, continue a clip, or drive motion with audio. | | Reference-to-video | `reference_image_urls` and/or `reference_video_urls` | Keeps your subjects while following a referenced performance; `reference_voice_urls` add per-subject audio. | | Video editing | `video_url` (the source clip) | Re-renders the source against the prompt; `audio_setting` controls the soundtrack. | The fields valid in each mode are mutually exclusive — sending, e.g., a reference field together with a `video_url` edit source is rejected as invalid. *** ## Parameters | Field | Type | Required | Default | Notes | | ---------------------- | --------- | -------- | ------- | ------------------------------------------------------------------------------- | | `model` | string | yes | — | Must be `"wan2.7-video"`. | | `prompt` | string | cond. | — | Up to 5000 chars. Required for text-to-video and reference-to-video. | | `negative_prompt` | string | no | — | Up to 500 chars. What to avoid. | | `image_urls` | string\[] | no | — | Public image URLs. 1 animates a still; 2 set first/last frame. Max 4. | | `image_with_roles` | object\[] | no | — | `[{ url, role }]` where role is `first_frame` or `last_frame`. Max 2. | | `video_urls` | string\[] | no | — | Continuation source. Public video URL. Max 1. | | `audio_url` | string | no | — | Public audio URL. Drives motion with an image input. | | `reference_image_urls` | string\[] | no | — | Reference subjects. Public image URLs. Up to 5. | | `reference_video_urls` | string\[] | no | — | Reference motion/action. Public video URLs. Up to 5. | | `reference_voice_urls` | string\[] | no | — | Per-subject voices. Public audio URLs. Count must equal `reference_image_urls`. | | `video_url` | string | no | — | Edit source. Public video URL. Routes to video editing. | | `audio_setting` | enum | no | — | Video editing only. `auto` or `origin`. | | `size` | enum | no | `16:9` | Aspect ratio: `16:9`, `9:16`, `1:1`, `4:3`, `3:4`. | | `resolution` | enum | no | `1080P` | `720P` or `1080P`. Scales the per-second rate. | | `duration` | integer | no | `5` | Seconds. Base modes 2–15; reference/edit modes cap lower (see below). | | `prompt_extend` | boolean | no | `true` | Expand a short prompt into a richer description before rendering. | | `watermark` | boolean | no | `false` | Add a watermark to the output. | | `seed` | integer | no | — | `>= 0`. Fixes the random seed for reproducible output. | **No `data:` URIs.** reApi rejects base64 inputs platform-wide. Upload media to public storage (your own CDN, S3, R2…) and pass the URL. ### Duration limits by mode | Mode | Allowed `duration` | | -------------------------------- | -------------------------------- | | Text-to-video / image-to-video | 2 – 15 seconds | | Reference-to-video (images only) | 2 – 15 seconds | | Reference-to-video (with videos) | 2 – 10 seconds | | Video editing | 0 (full source length) or 2 – 10 | *** ## Response envelope Submit and poll share the same shape — only `status` and `output` fill in over time. ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "wan2.7-video", "status": "completed", "created_at": 1735000000, "output": { "video_urls": ["https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.mp4"] }, "error": null } ``` | Field | Type | Notes | | ------------ | -------------- | ------------------------------------------------------- | | `id` | string | Task identifier — keep it for polling and audit | | `model` | string | Echo of the submitted `model` | | `status` | string | `processing` / `completed` / `failed` | | `created_at` | integer | Submission unix timestamp | | `output` | object \| null | `null` until completion. `output.video_urls` holds MP4s | | `error` | object \| null | Populated on `failed` — `{ code, message }` | *** ## Pricing Per-second × `resolution`. The mode does **not** change the rate — only the resolution does. `1080P` costs more per second than `720P`. For the input-billed modes (reference-to-video and video editing) reApi probes the uploaded clip **server-side** and folds input + output into the billable second count, rather than trusting a client value. Base text/image modes bill the requested output `duration`. **Bill formula** (1 credit = $0.001): ``` billable_seconds = ceil(server_probed_or_output_seconds) bill_usd = per_second_usd(resolution) × billable_seconds credits = ceil(per_second_usd × billable_seconds × 1000) ``` See current per-second rates for `720P` and `1080P` on the [model page](https://reapi.ai/models/wan-2-7-video). Failed jobs refund automatically. A probe failure on an input-billed mode returns `400 PRICING_UNAVAILABLE` (code `30002`) with no charge. The playground's draft estimate may show a default before an uploaded clip is probed — the authoritative number is computed at submit, after the server measures the file. *** ## Validation errors All cases below return HTTP 400. Pattern-match on `code`, not `message` — message strings carry request-specific context and are not a stable contract. | Trigger | Code | Message (illustrative) | | ------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------- | | `prompt` missing for text-to-video / reference-to-video | `20002` | `wan-2-7-video: prompt is required` | | Field invalid for the inferred mode | `20003` | `wan-2-7-video: video_urls is not valid in video editing` | | `duration` outside the mode's allowed range | `20003` | `wan-2-7-video: duration must be 2-15 seconds` | | `reference_voice_urls` count != `reference_image_urls` | `20003` | `wan-2-7-video: reference_voice_urls length must equal reference_image_urls length` | | A media field carrying a `data:` URI | `20003` | `wan-2-7-video: must be a public http(s) URL` | | Source clip probe fails (network / format) | `30002` | `Could not determine source video duration for billing: …` | | Provider rejected the request as invalid | `80007` | Provider rejected the request as invalid | The full envelope is `{ "error": { "code", "message", "request_id" } }` — see [Errors catalog](/docs/api/errors) for the wire format and request\_id correlation tips. *** ## Recipes ### Text-to-video ```json { "model": "wan2.7-video", "prompt": "a paper boat drifting down a rain-soaked street at dusk", "resolution": "1080P", "duration": 5 } ``` ### Image-to-video (animate a still) ```json { "model": "wan2.7-video", "prompt": "the subject turns to camera and smiles softly", "image_urls": ["https://your-cdn.com/portrait.png"], "resolution": "1080P", "duration": 5 } ``` ### Reference-to-video ```json { "model": "wan2.7-video", "prompt": "apply the reference choreography to the new character", "reference_image_urls": ["https://your-cdn.com/subject.png"], "reference_video_urls": ["https://your-cdn.com/dance-6s.mp4"], "resolution": "1080P", "duration": 6 } ``` ### Video editing ```json { "model": "wan2.7-video", "prompt": "restyle the clip with warm cinematic color grading", "video_url": "https://your-cdn.com/source-8s.mp4", "audio_setting": "origin", "duration": 0 } ``` *** ## Tips * **Let the inputs pick the mode.** There is no `mode` flag — send a prompt for text-to-video, add `image_urls` for image-to-video, `reference_*` for reference-to-video, or `video_url` to edit. Don't mix fields across modes. * **Match `duration` to the mode.** Base modes allow 2–15s; reference-with-video and editing cap at 10s, and editing accepts `0` for the full source length. * **Resolution drives cost.** `720P` is the cheaper run; switch to `1080P` for the final take. The mode does not change the per-second rate. * **Keep `reference_voice_urls` aligned.** Their count must equal the number of `reference_image_urls`, one voice per subject. * **Prompt the motion, not just the scene.** Describing the action ("turns and waves, smooth and continuous") sharpens text-to-video and image-to-video results. *** ## Related * [Errors catalog](/docs/api/errors) * [Authentication](/docs/api/authentication) * [Quickstart](/docs/api/quickstart) --- # z-image (https://reapi.ai/docs/z-image) import { Callout } from 'fumadocs-ui/components/callout'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; > Alibaba's Tongyi Z-Image-Turbo on reAPI — fast, low-cost **text-to-image** > with accurate **bilingual (English + Chinese) text rendering** and > photorealistic output. Submit returns a `task_id`; poll until ready. See > current pricing on the [model page](https://reapi.ai/models/z-image). ## Quick example ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "z-image", "prompt": "a poster that reads OPENING SOON in bold type, warm tones", "aspect_ratio": "3:4" }' ``` ```python import requests resp = requests.post( "https://reapi.ai/api/v1/images/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "model": "z-image", "prompt": "a poster that reads OPENING SOON in bold type, warm tones", "aspect_ratio": "3:4", }, timeout=30, ) print(resp.json()) ``` ```js const r = await fetch("https://reapi.ai/api/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "z-image", prompt: "a poster that reads OPENING SOON in bold type, warm tones", aspect_ratio: "3:4", }), }); console.log(await r.json()); ``` ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { body, _ := json.Marshal(map[string]any{ "model": "z-image", "prompt": "a poster that reads OPENING SOON in bold type, warm tones", "aspect_ratio": "3:4", }) req, _ := http.NewRequest("POST", "https://reapi.ai/api/v1/images/generations", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ### Submit response ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "z-image", "status": "processing", "created_at": 1735000000 } ``` Poll `GET /api/v1/tasks/{id}` (see the [Tasks](/docs/api/tasks) reference) until `status === "completed"`. The completed payload's `output.image_urls` holds the generated image URL. *** ## Authentication Every call needs a Bearer token. Generate keys at [reapi.ai/settings/apikeys](https://reapi.ai/settings/apikeys). ```http Authorization: Bearer YOUR_API_KEY ``` *** ## Endpoint ```http POST /api/v1/images/generations GET /api/v1/tasks/{id} ``` Submission is async. The POST returns immediately with a `task_id`; the task endpoint returns the same envelope until completion. Polling does not consume credits. Z-Image is **text-to-image only** — there is no image input. Each request produces **exactly one image** (no `n` parameter). *** ## Request body ### `model` — string, required Must be `z-image`. ### `prompt` — string, required Up to **1,000 characters**. Put any text you want rendered in the image inside quotes for best results. ### `aspect_ratio` — string, default `1:1` One of `1:1`, `4:3`, `3:4`, `16:9`, `9:16`. There is no width/height or resolution control. ### `nsfw_checker` — boolean, optional, default `false` Enables upstream content moderation. Off by default. *** ## Pricing Z-Image bills a flat rate **per generated image**, independent of aspect ratio. Each request produces one image: ``` credits = ceil(per_image_usd × 1000) ``` where `1 credit = $0.001 USD`. It is one of the lowest per-image rates on the platform. Failed and rejected requests are not charged. The exact per-image credit cost surfaces on the [model page](https://reapi.ai/models/z-image) and through the playground estimator before submit. *** ## Response The poll envelope returns the image URL in `output.image_urls`: ```json { "id": "task_019dfd44b7fd74168541552a3260a623", "model": "z-image", "status": "completed", "output": { "image_urls": [ "https://cdn.reapi.ai/...jpg" ] } } ``` Generated URLs expire — mirror them to your own storage if you need long-term retention. *** ## Errors Failures return the standard reAPI envelope `{ error: { code, message, request_id } }`. Common cases: * Invalid input (prompt over 1000 characters, an unsupported `aspect_ratio`) → `400`. * Insufficient credits → `402`. * Rate limited → `429`. See the full catalog at [/docs/api/errors](/docs/api/errors). *** ## Tips * Put the literal text you want rendered **in the prompt, in quotes** — Z-Image is tuned for legible English and Chinese typography. * It is text-to-image only — to edit an existing image, use a model that accepts an `image_url`. * For volume work (social graphics, e-commerce), Z-Image's flat low price makes it well-suited to batching many single-image requests. *** ## Related * [Image generation models](/docs/gpt-image-2) * [Qwen Image 2](/docs/qwen-image-2) * [Tasks API](/docs/api/tasks) * [Error codes](/docs/api/errors) --- # Authentication (https://reapi.ai/docs/api/authentication) ## Bearer token Send your API key as a Bearer token on every request: ```http Authorization: Bearer rk_live_xxxxxxxxxxxxxxxx ``` This matches the OpenAI scheme — most OpenAI clients work by changing `base_url` and `api_key`. ## Create a key 1. Sign in at [reapi.ai](https://reapi.ai). 2. Go to **Dashboard → API Keys**. 3. Click **Create new key**, give it a name (e.g. `production-server`). 4. Copy the key. **It is shown only once** — store it in a secret manager. You can create as many keys as you like (e.g. one per environment, one per service). ## Revoke a key Revoke compromised keys immediately on the dashboard. Pending tasks created with the key continue to completion (and bill credits), but no new requests can be made. ## Key prefixes | Prefix | Environment | | ------------- | -------------------------------------------------------- | | `rk_live_...` | Production | | `rk_test_...` | Test (no credit deduction, mock responses) — coming soon | ## Storing keys **Don't** commit keys to git or paste them in chat. Use a secret manager: * **Local dev**: `.env.local` (in `.gitignore`) * **Vercel**: Environment Variables * **AWS / GCP**: Secrets Manager / Secret Manager * **Docker**: Docker secrets or `--env-file` ## Errors | HTTP | `code` | Cause | Fix | | ---- | ------- | ------------------------------------------- | ---------------------------------------------------------------------------------------- | | 401 | `10001` | No `Authorization` header | Add the header | | 401 | `10002` | Header isn't `Bearer ` | Use `Bearer ` | | 401 | `10003` | Key invalid / typo | Check the dashboard | | 401 | `10004` | Key has been revoked | Mint a new key | | 401 | `10005` | Sign-in required (session-cookie path only) | Use API-key auth, or sign in | | 403 | `10006` | Origin not in allow-list (browser-only) | Only relevant for session-cookie auth from the browser; API-key requests aren't affected | | 402 | `30001` | Balance below request cost | Buy credits or wait for monthly refresh | Full list: [Errors](/docs/api/errors). --- # Balance (https://reapi.ai/docs/api/balance) `GET /api/v1/balance` returns the current credit balance for the credentials making the request. Use it to show remaining credits in your own dashboard, or to check a key has funds before submitting work. Reading this endpoint **does not consume credits**. ## GET /api/v1/balance ### Request ```http GET /api/v1/balance Authorization: Bearer rk_live_xxx ``` No body and no query parameters. ### Response `200 OK`: ```json { "balance": 12500 } ``` ### Response fields | Field | Type | Description | | --------- | ------- | ------------------------------------------------------------- | | `balance` | integer | Current credit balance. Integer credits, `1 credit = $0.001`. | ### Errors | HTTP | `code` | When | | ---- | ----------------- | ---------------------------------------------------------------- | | 401 | `10001` – `10005` | Auth missing / malformed / invalid / revoked | | 429 | `50001` | Per-user rate limit exceeded — retry after `Retry-After` seconds | | 500 | `60099` | Unexpected server error | Full list: [Errors](/docs/api/errors). --- # Errors (https://reapi.ai/docs/api/errors) ## Error format Every error response carries a JSON body in this shape: ```json { "error": { "code": 20002, "message": "Missing required parameter", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` | Field | Description | | ------------ | ------------------------------------------------------------------------------------------------------------- | | `code` | 5-digit numeric code. The leading digit is the category (1xxxx auth, 2xxxx validation, …). | | `message` | Human-readable explanation. May embed request-specific context (parameter names, balance, etc.). | | `request_id` | Unique per request. **Optional** — present whenever the gateway has assigned one; include in support tickets. | The HTTP status code reflects the *category* (401 / 400 / 402 / 429 / 500 / 502 / 503 / 504); the `code` field gives you the precise reason. For `failed` tasks, the same envelope is returned inside the polling response under `error` — see the model docs' Response section. ## Code catalog ### 1xxxx — Authentication (HTTP 401 / 403) | `code` | HTTP | Cause | | ------- | ---- | -------------------------------------------- | | `10001` | 401 | Missing `Authorization` header | | `10002` | 401 | `Authorization` header is not `Bearer ` | | `10003` | 401 | API key invalid | | `10004` | 401 | API key has been revoked | | `10005` | 401 | Sign-in required (session-auth surfaces) | | `10006` | 403 | Request origin not allowed | ### 2xxxx — Validation (HTTP 400) | `code` | Cause | | ------- | ------------------------------------------------- | | `20001` | Request body is not a JSON object | | `20002` | Required parameter missing — `message` says which | | `20003` | Parameter value invalid (type / range / enum) | | `20004` | `model` not supported on this endpoint | | `20005` | `size` not supported by this model | | `20006` | `quality` not supported by this model | | `20007` | `prompt` exceeds maximum length | ### 3xxxx — Billing (HTTP 402 / 400) | `code` | HTTP | Cause | | ------- | ---- | --------------------------------------- | | `30001` | 402 | Insufficient credits | | `30002` | 400 | Cannot determine pricing for this model | ### 4xxxx — Resource (HTTP 404) | `code` | Cause | | ------- | ------------------------------------------ | | `40001` | Task not found, or belongs to another user | ### 5xxxx — Rate limit (HTTP 429) | `code` | Cause | | ------- | --------------------------------------- | | `50001` | Rate limit exceeded — see `Retry-After` | ### 6xxxx — Server internal (HTTP 500) | `code` | Cause | | ------- | ------------------------------------------- | | `60001` | Failed to persist task — credits refunded | | `60002` | Failed to start workflow — credits refunded | | `60099` | Generic internal error | ### 7xxxx — Capacity (HTTP 503) | `code` | Cause | | ------- | ------------------------------------ | | `70001` | Workflow service unavailable — retry | | `70002` | Database unavailable | ### 8xxxx — Workflow execution (returned inside the polling response body when `status="failed"`) > **HTTP status for `GET /api/v1/tasks/{id}` is always `200` when the task is > found.** The codes below appear only inside `error.code` of the response > body — they are *never* the HTTP response status. | `code` | Cause | | ------- | ---------------------------------------------------- | | `80001` | Upstream submission failed (5xx / network on submit) | | `80002` | Polling timeout (wall-clock cap reached) | | `80003` | Upstream returned a terminal failure | | `80004` | Upstream completed but returned no URLs | | `80005` | Failed to persist generated files | | `80006` | Content policy violation | | `80007` | Upstream rejected the input as invalid | | `80008` | Task canceled | The 8xxxx codes are written to the task by the worker; polling returns them under `error.code` once `status="failed"`. ## Recommended handling ```python import requests, time def safe_call(method, url, **kwargs): for attempt in range(3): r = requests.request(method, url, **kwargs) body = r.json() if r.status_code == 200: return body if r.status_code == 429: time.sleep(int(r.headers.get('Retry-After', '5'))) continue if r.status_code in (502, 503, 504): time.sleep(2 ** attempt) continue raise RuntimeError( f"{body['error']['code']}: {body['error']['message']}" ) raise RuntimeError("max retries exceeded") ``` ### What to retry vs not | HTTP | Retry? | | ----------------------- | ------------------------------ | | 200 | n/a | | 400 / 401 / 402 / 404 | ❌ Fix the request | | 429 | ✅ With `Retry-After` | | 500 — `60001` / `60002` | ⚠️ Credits refunded, re-submit | | 500 — `60099` | ✅ Idempotent retry safe | | 502 / 503 / 504 | ✅ Exponential backoff | ## Support When reporting an issue, include: * The `request_id` from the response * The full request URL + method * Approximate timestamp (UTC) Email: [support@reapi.ai](mailto:support@reapi.ai) --- # Overview (https://reapi.ai/docs/api) ## Base URL ``` https://reapi.ai/api/v1 ``` All endpoints accept and return JSON. The API mirrors OpenAI's conventions where it makes sense — many existing OpenAI clients work by changing only `base_url`. ## Authentication Every request must carry an API key as a Bearer token: ```http Authorization: Bearer rk_live_xxxxxxxxxxxx ``` Create keys in your [dashboard](https://reapi.ai/dashboard/api-keys). See [Authentication](/docs/api/authentication) for full details. ## Asynchronous tasks (image, video) Generation calls are **asynchronous**. The pattern is: 1. **POST** the model endpoint (e.g. `/api/v1/images/generations`) → returns a `task_id` immediately. 2. **GET** `/api/v1/tasks/{task_id}` periodically until `status` is `completed` or `failed`. ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ │ POST │ → │processing│ → │ completed│ │ /images/ │ └──────────┘ │ failed │ │generations│ └──────────┘ └──────────┘ │ ▼ output / error ``` Recommended polling cadence: **1 request every 1–2 seconds**. For details see [Tasks](/docs/api/tasks). Per-model request schemas are on each model's page in the **Models** sidebar. ## Credits Each call deducts credits from your balance. Failed tasks are **automatically refunded** by the worker the moment the workflow ends in failure — atomically, before any poll observes the `failed` status. Refund is one-shot; re-polling never refunds twice. Pricing per model is configured in your account dashboard. ## Idempotency reAPI does **not** deduplicate by `Idempotency-Key`. Every successful HTTP POST to a generation endpoint creates a new task and charges credits — by design, so no upstream provider call is ever silently skipped. If you need retry safety, generate the same payload only once on your side or rely on the natural recovery path: when a task fails, credits are refunded automatically and you can resubmit. The `Idempotency-Key` header is currently accepted and recorded for telemetry but does **not** alter request behavior. Don't rely on it to prevent duplicate charges. ## Rate limits Requests are limited **per user**, in 1-second windows. The default is **10 requests / second / user**. When exceeded, you get HTTP `429` with code `50001` and a `Retry-After` header. Polling `GET /api/v1/tasks/{id}` shares the same limit, so don't poll faster than once every 1–2 seconds per task. ## Response format Successful responses are JSON of the resource type. Errors follow a standard shape: ```json { "error": { "code": 20002, "message": "Both `model` and `prompt` are required", "request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b" } } ``` `code` is a 5-digit numeric identifier (see [Errors](/docs/api/errors) for the full catalog). `request_id` is unique per call — include it in support requests. --- # Quickstart (https://reapi.ai/docs/api/quickstart) ## 1. Get an API key Sign up at [reapi.ai](https://reapi.ai), then go to **Dashboard → API Keys → Create new key**. Copy it now — you won't see it again. ``` rk_live_xxxxxxxxxxxxxxxxxxxxxxx ``` ## 2. Submit a generation task ```bash curl https://reapi.ai/api/v1/images/generations \ -H "Authorization: Bearer rk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2", "prompt": "a cute red panda eating bamboo, photorealistic", "size": "1:1" }' ``` Response (immediately): ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gpt-image-2", "status": "processing", "created_at": 1735000000 } ``` ## 3. Poll until done ```bash curl https://reapi.ai/api/v1/tasks/task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e \ -H "Authorization: Bearer rk_live_xxx" ``` Repeat every 1–2 seconds until `status` is `completed`: ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gpt-image-2", "status": "completed", "created_at": 1735000000, "output": { "image_urls": [ "https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png" ] }, "error": null } ``` That's it. Your image is at `output.image_urls[0]`. ## Full example (Node.js) ```js const KEY = process.env.REAPI_KEY; async function generate(prompt) { const submit = await fetch('https://reapi.ai/api/v1/images/generations', { method: 'POST', headers: { 'Authorization': `Bearer ${KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gpt-image-2', prompt, }), }).then(r => r.json()); const taskId = submit.id; while (true) { await new Promise(r => setTimeout(r, 1500)); const task = await fetch(`https://reapi.ai/api/v1/tasks/${taskId}`, { headers: { 'Authorization': `Bearer ${KEY}` }, }).then(r => r.json()); if (task.status === 'completed') return task.output.image_urls; if (task.status === 'failed') throw new Error(task.error?.message ?? 'failed'); } } console.log(await generate('a cute red panda')); ``` ## Python ```python import os, time, requests KEY = os.environ['REAPI_KEY'] HEAD = {'Authorization': f'Bearer {KEY}'} submit = requests.post( 'https://reapi.ai/api/v1/images/generations', headers=HEAD, json={ 'model': 'gpt-image-2', 'prompt': 'a cute red panda', }, ).json() task_id = submit['id'] while True: time.sleep(1.5) task = requests.get(f'https://reapi.ai/api/v1/tasks/{task_id}', headers=HEAD).json() if task['status'] == 'completed': print(task['output']['image_urls']) break if task['status'] == 'failed': raise RuntimeError(task['error']) ``` ## Next steps * [API overview](/docs/api) — full conventions * [Tasks](/docs/api/tasks) — `GET /api/v1/tasks/{id}` polling reference * [gpt-image-2 model card](/docs/gpt-image-2) — capabilities + pricing * [Errors](/docs/api/errors) — error code reference --- # Tasks (https://reapi.ai/docs/api/tasks) Generation on reAPI is **asynchronous**. Every submission endpoint — `/api/v1/images/generations`, `/api/v1/videos/generations`, and any future `/api/v1/audio/generations` — returns a task id, and you poll `GET /api/v1/tasks/{id}` until the task reaches a terminal state. This page is the canonical reference for the polling endpoint. The request shape, status values, error codes, polling cadence, and refund semantics are the same regardless of which submission endpoint produced the task; only the contents of `output` differ by media kind. ## GET /api/v1/tasks/\{id} Retrieve the current state of a task. ### Request ```http GET /api/v1/tasks/{id} Authorization: Bearer rk_live_xxx ``` `{id}` is the `id` returned by the submitting POST. Polling **does not consume credits**. ### Response `200 OK` — image task example: ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "model": "gpt-image-2", "status": "completed", "created_at": 1735000000, "output": { "image_urls": [ "https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/0.png", "https://cdn.reapi.ai/media/tasks/018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e/1.png" ] }, "error": null } ``` `200 OK` — video task example: ```json { "id": "task_01k9s419324drezfbwnsvxyr6h", "model": "doubao-seedance-2.0", "status": "completed", "created_at": 1762853430, "output": { "video_urls": [ "https://cdn.reapi.ai/media/tasks/01k9s419324drezfbwnsvxyr6h/0.mp4" ] }, "error": null } ``` ### Status values | Status | Meaning | | ------------ | ---------------------------------------------------------------- | | `processing` | Submitted, provider is generating | | `completed` | Done — `output` populated | | `failed` | Provider returned an error — `error` populated, credits refunded | ### Output shape The shape of `output` depends on the media kind of the task: | Media kind | Field | Type | | ---------- | ------------ | --------- | | Image | `image_urls` | string\[] | | Video | `video_urls` | string\[] | | Audio | `audio_urls` | string\[] | Some video models add an extra `last_frame_url` (string) when the request opted into a return-last-frame capability. URLs returned in `output` are rehosted to reAPI's CDN. If you need long-term archival, copy them to your own storage as soon as the task completes — bucket lifecycle policies are configured per-deployment and not guaranteed by this contract. ### Errors | HTTP | `code` | When | | ---- | ----------------- | ------------------------------------------------------------------------ | | 401 | `10001` – `10005` | Auth missing / invalid / revoked | | 404 | `40001` | Task doesn't exist or belongs to another user | | 429 | `50001` | Per-user request rate limit exceeded — retry after `Retry-After` seconds | ## Polling pattern Recommended: ``` attempt 1: wait 2s attempt 2: wait 2s ... the worker keeps a task alive up to a wall-clock cap before it self-reports an 80002 timeout: 1 hour for image and audio, 48 hours for video. Most tasks finish far sooner (image/audio usually under a minute, video in minutes), so size your client-side give-up to your own tolerance, not the cap. ``` The polling endpoint is cached for **5 seconds** while a task is in-flight, so polling faster than every 2–3 seconds returns the same state and just consumes rate-limit budget. Video tasks routinely take several minutes; pace your polling accordingly. ## Refund behavior Failed tasks are **automatically refunded** by the worker the moment the workflow ends in failure — the credit return happens atomically with the status flip, before any poll observes it. Refund is one-shot: re-polling a `failed` task never refunds twice. A failed task surfaces the failure code under `error`: ```json { "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e", "status": "failed", "output": null, "error": { "code": 80006, "message": "Request violates content policy" } } ``` The `code` here is one of the 8xxxx workflow-execution codes — see [Errors → 8xxxx](/docs/api/errors#8xxxx--workflow-execution-returned-in-polling-response-when-statusfailed).