Content-Type: application/json
Tạo ảnh qua một
entrypoint duy nhất.
API bất đồng bộ tương thích kiểu OpenAI Images/APIMart, được điều phối qua pool worker Codex, retry có giới hạn và xuất kết quả bằng URL public từ orchestrator.
OpenAPI 3.1 cho client tích hợp
Spec machine-readable nằm tại /openapi.json.
Contract này cover public /v1 submit, task polling, output download,
Bearer auth, Idempotency-Key, X-Request-Id, lỗi có cấu trúc,
rate limit, signed output URL, API key admin surface và webhook delivery.
/v1/images/generations
Validate request, tạo job nội bộ và trả task ID ngay. Việc chọn worker, tạo từng output, retry và lưu artifact tiếp tục chạy bất đồng bộ.
Không phải kết quả ảnh cuối cùng.
Poll bằng task ID vừa nhận.
Một request, ba bước
Submit
Gửi prompt vào POST /v1/images/generations.
Poll
Dùng task_id với GET /v1/tasks/{task_id}.
Consume
Đọc URL tại data.result.images[*].url[*].
Xác thực Bearer theo scope
Tạo credential trong API Keys. Secret bắt đầu bằng
gpi_live_, chỉ được trả một lần và được lưu dưới dạng SHA-256 digest.
Bearer gpi_live_••••••••••••
required*
| Scope | Cho phép |
|---|---|
images:write | Submit image generation |
tasks:read | Đọc trạng thái và kết quả task |
outputs:read | Tải bytes ảnh từ output URL của cùng API client |
admin:read | Đọc console/management endpoints và output URL |
admin:write | Ghi console/management endpoints và grant toàn bộ scope |
*Ở local/dev, endpoint tương thích chạy không cần auth nếu chưa có active managed key, không cấu hình
PUBLIC_API_TOKENS/API_BEARER_TOKEN và không bật
ORCHESTRATOR_REQUIRE_API_AUTH. Production bật require-auth từ startup và yêu cầu
API_BEARER_TOKEN để bootstrap. Admin route được khóa khi có active admin-scoped key,
legacy token hoặc require-auth; output URL được khóa khi có legacy token, require-auth hoặc active managed key grant
outputs:read/admin access. Managed key chỉ đọc output của cùng API client trừ admin scope.
Console đổi Bearer token sang cookie session HttpOnly
qua /v1/auth/session; write request dùng cookie phải gửi x-gpt-image-csrf: 1.
Key hết hạn/revoke không tự giữ route ở trạng thái locked.
Từ scoped API key đến file output
Key cần các scope images:write, tasks:read và outputs:read trên cùng API client.
Client curl trong repo submit task, replay cùng Idempotency-Key, poll đến terminal state
và tải URL đầu tiên về file.
export GPT_IMAGE_BASE_URL=http://localhost:8022
export GPT_IMAGE_API_KEY=gpi_live_...
export GPT_IMAGE_OUTPUT_FILE=output.png
bash examples/curl/quick-integration.sh
Client copy-paste tương đương nằm ở examples/typescript/client.ts và
examples/python/client.py. Cả hai hỗ trợ createImageTask,
getTask, waitForTask, downloadOutput,
Idempotency-Key, X-Request-Id và lỗi có cấu trúc.
Body parameters
modelstringrequired*Model tạo ảnh. Giá trị duy nhất được hỗ trợ là gpt-image-2.
gpt-image-2promptstringrequiredMô tả ảnh cần tạo. Chuỗi sau khi trim không được rỗng.
nintegerSố output. Orchestrator tách thành từng worker call để retry độc lập.
Default:1 · Range: 1..4sizestringTỉ lệ preset, auto, hoặc kích thước pixel trực tiếp tối đa 8192x8192.
1:1resolutionstringTier dùng để ánh xạ tỉ lệ sang pixel.
Enum:1k · 2k · 4k · Default: 1kimage_urlsstring[]Ảnh tham chiếu dạng URL HTTP(S) hoặc base64 data URI hợp lệ. Khi có phần tử, request chạy như image-to-image.
Maximum:16 itemsactionstringOverride chế độ dispatch nội bộ. Dùng generate cho reference-guided generation, hoặc edit cho edit/mask workflow.
edit khi có image_urls, ngược lại generatequality / background / output_formatCác tùy chọn tạo ảnh giống console. output_format nhận png, jpeg, jpg, hoặc webp.
mask_image / input_fidelityDùng cho edit workflow. mask_image phải là URL/data URI ảnh hợp lệ và cần action=edit.
official_fallbackbooleanĐược nhận để tương thích contract. Hiện chưa thay đổi routing hoặc retry policy của hệ thống.
Default:falseẢnh tham chiếu đổi cách dispatch
Chỉ cần thêm image_urls, orchestrator chuyển action nội bộ từ generate sang
edit và đưa các phần tử vào reference_images của worker. Nếu client gửi
action=generate, các ảnh vẫn được giữ làm reference-guided generation.
action = generate
action = edit
- URL phải dùng scheme
httphoặchttpsvà có host hợp lệ. - Data URI phải bắt đầu bằng
data:image/, chứa markerbase64và decode được. - Khi image-to-image không truyền
size, orchestrator giữsize = nullthay vì ép về 1:1. - Có thể trộn URL và data URI trong cùng một request.
15 tỉ lệ × 3 tier
Preset dưới đây là mapping thực tế trước khi request được chuyển cho worker.
| Ratio | 1K | 2K | 4K |
|---|---|---|---|
| 1:1 | 1024×1024 | 2048×2048 | 2880×2880 |
| 3:2 | 1536×1024 | 2048×1360 | 3520×2336 |
| 2:3 | 1024×1536 | 1360×2048 | 2336×3520 |
| 4:3 | 1024×768 | 2048×1536 | 3312×2480 |
| 3:4 | 768×1024 | 1536×2048 | 2480×3312 |
| 5:4 | 1280×1024 | 2560×2048 | 3216×2576 |
| 4:5 | 1024×1280 | 2048×2560 | 2576×3216 |
| 16:9 | 1536×864 | 2048×1152 | 3840×2160 |
| 9:16 | 864×1536 | 1152×2048 | 2160×3840 |
| 2:1 | 2048×1024 | 2688×1344 | 3840×1920 |
| 1:2 | 1024×2048 | 1344×2688 | 1920×3840 |
| 3:1 | 1881×836 | 3072×1024 | 3840×1280 |
| 1:3 | 887×1774 | 1024×3072 | 1280×3840 |
| 21:9 | 2016×864 | 2688×1152 | 3840×1648 |
| 9:21 | 864×2016 | 1152×2688 | 1648×3840 |
/v1/tasks/{task_id}
Trả snapshot hiện tại của job, progress, lỗi hoặc danh sách URL kết quả.
Đọc kết quả
data.result.images[0].url[0]
status- Trạng thái public của task.
progress0khi pending,10..99khi processing,100khi kết thúc.created- Unix timestamp lúc job được tạo.
completed- Unix timestamp khi completed hoặc failed.
actual_time- Thời gian thực thi tính bằng giây khi task đã kết thúc.
estimated_time- Giá trị ước tính hiện tại:
100giây. result.images- Các artifact thành công; mỗi item có mảng
urlvà RFC3339expires_atkhi signed URL được bật. Signed URL hợp lệ không cần Bearer; URL không có signature cần same-clientoutputs:read, admin scope hoặc legacy bootstrap token.
Signed URL không làm lộ API key
Completed task mặc định trả URL orchestrator có expires và signature.
Backend có thể đưa nguyên URL này cho browser, mobile app hoặc downstream service. HMAC-SHA256 bind
job id, validated file name, expiry và client id; request hết hạn hoặc bị sửa bị reject trước khi đọc RustFS.
{
"url": [
"https://api.example.com/v1/jobs/550e8400-e29b-41d4-a716-446655440000/outputs/output-1.png?expires=1783341296&signature=example-signature"
],
"expires_at": "2026-07-06T12:34:56Z"
}
Default TTL là một giờ và không vượt quá retention expiry. URL hết hạn trả
403 signed_url_expired; URL bị sửa trả 403 invalid_signed_url.
Bearer/cookie có same-client outputs:read vẫn tải được canonical URL không có query; admin và legacy bootstrap token giữ quyền đọc global.
Dùng dedicated 32-byte OUTPUT_URL_SIGNING_KEY; set
OUTPUT_SIGNED_URLS_ENABLED=0 để dùng Bearer-only access.
Quản lý tenant và policy theo client
Managed API key thuộc về một API client. Install cũ được backfill vào default client; khi
POST /v1/api-keys không truyền client_id, key mới dùng default client để giữ tương thích.
curl -X POST http://localhost:8022/v1/clients \
-H 'Authorization: Bearer <admin-token>' \
-H 'Content-Type: application/json' \
-d '{
"name": "partner-a",
"policy": {
"rate_limit_per_minute": 120,
"max_concurrent_jobs": 4,
"daily_image_quota": 1000,
"allowed_providers": ["codex"],
"allowed_models": ["gpt-image-2"],
"max_n": 4,
"output_retention_days": 30
}
}'
Admin dùng GET/POST /v1/clients để list/tạo client và
DELETE /v1/clients/{client_id} để disable. Disabled client không thể submit job public.
Rate limit của managed key được bucket theo client; provider, model, max_n, concurrent job và
daily image quota được kiểm tra trước khi enqueue ở /v1/images/generations và Vertex-compatible route.
Với Vertex-compatible route, allowed_models có thể là full resource path hoặc model id ngắn như
gemini-2.5-flash-image.
Daily quota dùng usage ledger append-only cho ảnh billable đã hoàn tất, cộng reservation của job queued/running.
Retention dùng output_retention_days trong policy snapshot; default là 30 ngày.
Export usage theo client
Public image job ghi usage ledger append-only sau khi biết trạng thái cuối của từng output. Event lưu client, API key, job, task id, output index, provider/model, status, image count, token counters, web-search requests, duration và timestamp. Prompt, ảnh tham chiếu, Bearer token và credential provider không được lưu trong ledger.
/v1/usage?from=&to=&client_id=
Admin có admin:read dùng endpoint này để export mọi client hoặc filter theo
client_id. Managed client có tasks:read dùng
/v1/usage/self?from=&to= và chỉ thấy event của chính client gắn với API key.
from inclusive, to exclusive; mặc định là 24 giờ gần nhất.
{
"from": "2026-07-06T00:00:00Z",
"to": "2026-07-07T00:00:00Z",
"events": [{
"task_id": "task_550e8400-e29b-41d4-a716-446655440000",
"output_index": 1,
"event_type": "output.completed",
"provider": "codex",
"image_model": "gpt-image-2",
"status": "succeeded",
"image_count": 1,
"total_tokens": 150,
"web_search_requests": 1
}]
}
Nhận event khi task kết thúc
Admin tạo endpoint bằng POST /v1/webhooks. Response trả
signing_secret đúng một lần; các route list/revoke, event log, delivery log và replay nằm ở
/v1/webhooks, /v1/webhook-events và /v1/webhook-deliveries.
{
"id": "evt_550e8400e29b41d4a716446655440000",
"type": "task.completed",
"created": 1776748726,
"task_id": "task_550e8400-e29b-41d4-a716-446655440000",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"task": {
"id": "task_550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"result": {
"images": [
{
"url": ["https://api.example.com/v1/jobs/550e8400-e29b-41d4-a716-446655440000/outputs/output-1.png?expires=1783341296&signature=example-signature"],
"expires_at": "2026-07-06T12:34:56Z"
}
]
}
}
}
}
| Header | Ý nghĩa |
|---|---|
X-GPT-Image-Webhook-Id | Event id evt_.... |
X-GPT-Image-Webhook-Timestamp | Unix timestamp dùng trong signature. |
X-GPT-Image-Webhook-Signature | sha256=<hex-hmac> trên bytes timestamp + body. |
Events: task.completed, task.failed, task.partial_failed,
output.ready. Delivery retry dùng bounded exponential backoff; hết retry sẽ mark
failed và có thể replay thủ công. Payload chỉ chứa output URL public, không chứa base64,
Bearer token, worker auth state hoặc credential blob. HTTPS public target là mặc định; registration chặn
local/private, link-local và Docker/internal host, còn delivery revalidate DNS, chặn hostname resolve về
private/local IP, pin public socket address đã validate và tắt proxy cho delivery client đó trừ khi bật
WEBHOOK_ALLOW_LOCAL_TARGETS=1 cho dev.
Webhook delivery không follow redirect.
Lỗi có cấu trúc
{
"code": 400,
"error": {
"code": 400,
"message": "prompt is required",
"type": "invalid_request",
"request_id": "client-request-123"
}
}
| HTTP | Trường hợp | type thường gặp |
|---|---|---|
| 400 | JSON/body, model, size, prompt hoặc image URL không hợp lệ | invalid_request |
| 401 | Thiếu, sai hoặc hết hạn credential | unauthorized |
| 403 | API key thiếu scope hoặc signed output URL invalid/expired | forbidden |
| 404 | Task ID hợp lệ nhưng không tồn tại | not_found |
| 409 | Idempotency-Key được reuse với body khác | idempotency_conflict |
| 410 | Output đã hết retention hoặc bị cleanup | output_expired |
| 429 | Rate limit credential | rate_limited |
| 5xx | Provider quota/auth/rejection hoặc orchestrator failure | provider_quota_limited, provider_auth_failed, provider_rejected, internal_error |
Taxonomy ổn định: invalid_request, unauthorized, forbidden,
not_found, output_expired, idempotency_conflict, rate_limited,
worker_unavailable, provider_quota_limited,
provider_auth_failed, provider_rejected, timeout,
internal_error.
Analytics theo worker/account
Console có view Analytics đọc GET /v1/analytics qua cùng origin. Endpoint này
tổng hợp telemetry vận hành từ job/attempt đã persist: số image calls, reported input/output/image tokens, usage-limit errors,
web-search requests, failed/retry attempts, model mix, latency và ledger tối đa 200 attempt gần nhất.
Mỗi worker/account có tổng riêng; account hint luôn được redacted.
GET /v1/analytics?from=2026-06-19T00:00:00Z&to=2026-06-20T00:00:00Z&bucket=15m&worker_id=worker-1
from/to là RFC3339, bucket nhận 5m,
15m, 30m, hour, 6h, 12h
hoặc day, và worker_id=all hoặc bỏ trống để xem toàn bộ fleet.
Token chỉ được cộng khi Codex trả usage trong response thành công; call lỗi vẫn được đếm nhưng có thể không có token.
Worker selection & retry
Client không chọn worker. Orchestrator chọn account đang online, đã login và còn slot; mỗi output được
theo dõi riêng. Retry bị giới hạn bởi JOB_MAX_RETRIES và backoff bởi
JOB_RETRY_BACKOFF_MS. Nếu không có worker online, đã login và còn slot trước
WORKER_QUEUE_TIMEOUT_SECS, job fail có cấu trúc worker_unavailable.
Input edit/reference sai được trả về ngay.
Ưu tiên worker khác thay vì lặp ngay worker bị giới hạn.
Chỉ output lỗi có khả năng retry được chạy lại.
Giới hạn thực tế
Quota API được cập nhật atomic trong PostgreSQL, dùng chung giữa các orchestrator. Response 429 luôn kèm Retry-After.
Contract được đối chiếu trực tiếp với implementation Rust hiện tại.