Media API
POST
/omni/media/v1/images/generations/tasksImage generation
Image generation runs in two steps: create a task (202 + task id), then poll until the status is terminal and download the signed URL. Point your client at the media base URL https://api.atptoken.ai/omni/media/v1 and authenticate with a project atp- key. The gateway routes your unified model to an image provider (e.g. gpt-image-2); confirm names with GET /v1/models. The flow matches video generation.
- Output is written to object storage and returned as a signed edge URL (
https://media-<env>.atptoken.ai/v/...) with a 30-minute TTL — never inline base64. Fetch it promptly. - Requests are refused with
402 insufficient_quotawhen the project balance is ≤ 0.
Check the model with the same key first
Media availability depends on the environment and project. Call GET https://api.atptoken.ai/v1/models first; a model absent from that response is not available to that key.
Create a task
curl https://api.atptoken.ai/omni/media/v1/images/generations/tasks \
-H "Authorization: Bearer atp-..." -H "Content-Type: application/json" \
-H "Idempotency-Key: img-job-001" \
-d '{ "model": "gpt-image-2", "prompt": "a watercolor cat", "size": "1024x1024", "quality": "high", "n": 1 }'
# → 202 { "id": "img_..." }| Field | Type | Description |
|---|---|---|
| model | string · Req | unified image model (`image` pool) |
| prompt | string · Req | text prompt |
| size | string | model-specific; OpenAI images commonly use `1024x1024` |
| quality | string | forwarded to OpenAI-dialect upstreams (e.g. `high` / `medium`) |
| n | integer | number of images, 1–4 (default `1`) |
Reuse the same Idempotency-Key when retrying a create after a network failure; use a fresh key for a genuinely new task.
Poll until terminal
Poll every 3–8 seconds:
curl https://api.atptoken.ai/omni/media/v1/images/generations/tasks/img_... \
-H "Authorization: Bearer atp-..."
# → { "status": "succeeded", "data": [ { "url": "https://media-prod.atptoken.ai/v/image/...png?exp=...&sig=..." } ], "usage": { "prompt_tokens": 37, "completion_tokens": 7024, "total_tokens": 7061 } }statustransitionsqueued→running→succeeded/failed/cancelled/expired.- A succeeded task's
data[].urlis a signed URL with a 30-minute TTL; after expiry the task still reportssucceededwithexpired: trueand a nullurl— download promptly (re-create to regenerate). usagereports token usage for billing transparency; afailedtask carries a structurederrorobject.
| Method | Path | Action |
|---|---|---|
| POST | /omni/media/v1/images/generations/tasks | create |
| GET | /omni/media/v1/images/generations/tasks/{id} | poll |
| GET | /omni/media/v1/images/generations/tasks | list |
| DELETE | /omni/media/v1/images/generations/tasks/{id} | cancel |
Python example
A minimal create-and-poll flow:
import os, time, requests
BASE = "https://api.atptoken.ai/omni/media/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['ATP_API_KEY']}",
"Content-Type": "application/json",
}
resp = requests.post(
f"{BASE}/images/generations/tasks",
headers={**HEADERS, "Idempotency-Key": "img-job-001"},
json={
"model": "gpt-image-2",
"prompt": "a watercolor cat",
"size": "1024x1024",
"quality": "high",
"n": 1,
},
timeout=60,
)
resp.raise_for_status()
task_id = resp.json()["id"]
while True:
task = requests.get(
f"{BASE}/images/generations/tasks/{task_id}", headers=HEADERS, timeout=60
).json()
if task["status"] in ("succeeded", "failed", "cancelled", "expired"):
break
time.sleep(5)
if task["status"] == "succeeded":
for i, item in enumerate(task["data"]):
image = requests.get(item["url"], timeout=120).content # signed URL, 30-min TTL
with open(f"result_{i}.png", "wb") as f:
f.write(image)
else:
raise RuntimeError(task.get("error"))Errors
400
missing `model` or `prompt`.
402
`insufficient_quota`: project balance ≤ 0; top up and retry (don't hammer).
404
task not found or not owned by this project (poll).
422
the model has no image provider.
502
upstream generation failed.