Quick start
Three steps and you're sending requests.
-
1
Grab an API key
Visit the homepage — a key is automatically generated for your IP. Keys are bound to that IP.
-
2
Point your OpenAI SDK at us
Override
base_urland you're done — everything else is identical to OpenAI. -
3
Pick any model
From
gpt-5toveo-3. See the full catalog.
# Returns OpenAI-shaped { "data": [{ "url": "https://…/video.mp4" }] } curl "https://your-apiarium.example.com/v1/videos/generations" \ -H "Authorization: Bearer api-xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "model": "veo-3", "prompt": "a red apple rotating on white, studio lighting", "duration_seconds": "8", "resolution": "1080p", "size": "16:9" }'
Authentication
Every request to /v1/* needs a Bearer token.
Authorization: Bearer api-xxxxxxxxxxxxxxxx
- 🔒 Each key is bound to one IP address. Requests from a different network are rejected with HTTP 401.
- ⏱️ Default rate limit: 4 RPM per key. The master key bypasses limits.
- 🪪 Lose your key? Visit the homepage again — your IP will get the same key back.
Base URL
All endpoints below are relative to:
https://your-apiarium.example.com
↑ this page auto-detects the running host
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/models | List all available model aliases |
| POST | /v1/chat/completions | Chat with any text/image/video model |
| POST | /v1/completions | Legacy text completions |
| POST | /v1/images/generations | Image generation (gpt-image-*, gemini-3-image*) |
| POST | /v1/videos/generations | Video generation (veo-3, veo-3-fast, veo-3.1-fast) |
| GET | /v1/keys/me | Get / auto-generate the key bound to your IP |
| GET | /health | Health check |
Models catalog
Live snapshot from GET /v1/models. Click any tile to copy the model id.
Chat completions
Drop-in replacement for POST https://api.openai.com/v1/chat/completions. Streaming via "stream": true works out of the box.
{
"model": "gpt-5",
"messages": [
{"role": "user", "content": "Hello"}
],
"stream": true,
"temperature": 0.7
}
{
"id": "chatcmpl-…",
"object": "chat.completion",
"model": "gpt-5",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hi! How can I help?"
},
"finish_reason": "stop"
}]
}
Veo 3 — video
Dedicated endpoint:
POST /v1/videos/generations.
Models:
veo-3,
veo-3-fast,
veo-3.1-fast.
Returns an OpenAI-style payload: {"data": [{"url": "https://…/video.mp4"}]}.
You can also send model: "veo-3" to
/v1/chat/completions — the assistant message will then
contain the bare MP4 URL — but the dedicated endpoint is more ergonomic.
Supported parameters
| Field | Type | Default | Notes |
|---|---|---|---|
| messages[].content | string | — | The video prompt. We flatten all user/system turns into one string. |
| duration_seconds | "4" | "6" | "8" | "8" | Even seconds only. Longer = more credits. |
| resolution | "720p" | "1080p" | "720p" | 1080p costs more. |
| aspect_ratio | "16:9" | "9:16" | "16:9" | Landscape or portrait. |
| image_url | string | — | Image-to-video: seed frame that gets animated. |
{
"model": "veo-3",
"prompt": "a red apple rotating on white, studio lighting",
"duration_seconds": "8",
"resolution": "1080p",
"size": "16:9"
}
{
"created": 1779570172,
"data": [{
"url": "https://…/video.mp4",
"revised_prompt": "a red apple rotating on white…"
}]
}
400 with a clear error.
Gemini 3 — image
Dedicated endpoint:
POST /v1/images/generations.
Models:
gemini-3-image,
gemini-3-flash-image,
gemini-3.1-flash-image.
Append -pro to any of them for the higher-quality variant (~2 min).
Supported parameters
| Field | Type | Default | Notes |
|---|---|---|---|
| prompt | string | — | Image description. |
| size | aspect or WxH | "1024x1024" | Accepts ratios (1:1, 16:9, 9:16, 4:3, 3:4) or OpenAI sizes (1024x1024, 1792x1024, …). |
| n | integer | 1 | Repeated entries in data[]; upstream still produces one URL. |
{
"model": "gemini-3-image",
"prompt": "a glass of orange juice on a sunny kitchen counter",
"size": "1:1"
}
{
"created": 1779570172,
"data": [{
"url": "https://…/image.png",
"revised_prompt": "a glass of orange juice…"
}]
}
Gemini 3 — text (RAG)
Models: gemini-3,
gemini-3-flash,
gemini-3-pro.
These route to Gemini Hub's RAG-grounded /query endpoint. For free-form chat without a knowledge base, prefer
gemini-2.5-pro, gemini-3.1-pro or one of the GPT/Claude aliases.
gpt-image-1 / gpt-image-2
Same endpoint as Gemini 3 image:
POST /v1/images/generations.
Just swap the model id.
{
"model": "gpt-image-1",
"prompt": "a watercolor of Istanbul rooftops",
"n": 1,
"size": "1024x1024"
}
Errors & limits
| Status | Meaning | Fix |
|---|---|---|
| 401 | IP mismatch or missing/invalid key | Hit /v1/keys/me from your real IP. |
| 403 | VPN / proxy detected | Disable VPN, retry. |
| 429 | Rate limit exceeded (4 RPM) | Back off & retry; content field shows wait time. |
| 502 | Upstream provider unreachable | Try again or pick another model. |
SDK examples
from openai import OpenAI client = OpenAI( base_url="https://your-apiarium.example.com/v1", api_key="api-xxxxxxxxxxxxxxxx", ) # 1) chat chat = client.chat.completions.create( model="gpt-5", messages=[{"role": "user", "content": "hi"}], ) print(chat.choices[0].message.content) # 2) image (Gemini 3 or gpt-image) img = client.images.generate( model="gemini-3-image", prompt="a glass of orange juice on a sunny kitchen counter", size="1:1", ) print(img.data[0].url) # 3) video (Veo 3) — /v1/videos/generations import httpx vid = httpx.post( "https://your-apiarium.example.com/v1/videos/generations", headers={"Authorization": "Bearer api-xxxxxxxxxxxxxxxx"}, json={"model": "veo-3", "prompt": "a red apple rotating on white", "duration_seconds": "8", "resolution": "1080p", "size": "16:9"}, timeout=600, ).json() print(vid["data"][0]["url"])
import OpenAI from "openai"; const BASE_URL = "https://your-apiarium.example.com"; const API_KEY = "api-xxxxxxxxxxxxxxxx"; const client = new OpenAI({ baseURL: `${BASE_URL}/v1`, apiKey: API_KEY, }); // 1) image — uses the OpenAI SDK's images.generate const img = await client.images.generate({ model: "gemini-3-image", prompt: "a glass of orange juice on a sunny kitchen counter", size: "1:1", }); console.log(img.data[0].url); // 2) video — bypass the SDK, hit /v1/videos/generations directly const vid = await fetch(`${BASE_URL}/v1/videos/generations`, { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "veo-3", prompt: "a serene mountain sunset timelapse", duration_seconds: "8", resolution: "1080p", size: "16:9", }), }).then(r => r.json()); console.log(vid.data[0].url);