# chatgpt2api 异步生图 API 文档 / Async Image Generation API

> 在线版 / Online: <https://img.2capi.com/api-doc> ｜ 本文档 / This doc: <https://img.2capi.com/api.md>

面向外部工具、Apifox、脚本使用。推荐**异步接口**：先提交任务拿到 `task_id` 和 `poll_url`，再轮询结果。

For external tools, Apifox and scripts. Prefer the **async endpoints**: submit a task to get a `task_id` and `poll_url`, then poll.

---

## 1. 基础地址 / Base URL

```
https://img.2capi.com
```

## 2. 鉴权 / Authentication

所有接口需在请求头携带 API Key。Key 在 <https://img.2capi.com/api-doc> 生成，列表中会显示明文并提供复制按钮。

All endpoints need an API Key header. Generate it at <https://img.2capi.com/api-doc>; the list shows the plain key with a copy button.

```
Authorization: Bearer c2a_xxx
```

---

## 3. 接口总览 / Endpoints

| 方法 / Method | 路径 / Path | 说明 / Description |
| --- | --- | --- |
| `POST` | `/api/image-tasks/generations` | 提交异步生图（文生图 / 图生图）/ Async generate (text/image-to-image) |
| `POST` | `/api/image-tasks/edits` | 提交异步编辑（multipart）/ Async edit (multipart) |
| `GET`  | `/api/image-tasks?ids=<task_id>` | 轮询状态与结果 / Poll status & result |
| `POST` | `/v1/images/generations` | OpenAI 同步兼容（易超时，不推荐对外）/ Sync-compatible |

> **为什么用异步？/ Why async?** 同步接口会等真实生图完成（常需数十秒到数分钟），客户端易超时；异步接口提交后立即返回任务 ID。
> The sync endpoint blocks until done and clients often time out; async returns a task ID immediately.

---

## 4. 调用流程 / Workflow

1. **生成 API Key** — 在 `/api-doc` 点击生成并复制 / Generate and copy at `/api-doc`.
2. **提交异步任务** — `POST /api/image-tasks/generations`，返回 `poll_url`，不等待生图 / returns `poll_url` without waiting.
3. **轮询结果** — `GET /api/image-tasks?ids=<task_id>`，直到 `succeeded`/`failed`/`cancelled`.

---

## 5. 提交异步任务 / Submit Async Task

### 5.1 文生图 / Text-to-image

```bash
curl -X POST "https://img.2capi.com/api/image-tasks/generations" \
  -H "Authorization: Bearer c2a_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "client_task_id": "demo-image-001",
    "prompt": "请生成一张图片：一只橘猫坐在月光窗台上，水彩风格，只输出图片。",
    "model": "gpt-image-2-5.5",
    "n": 1
  }'
```

### 5.2 图生图（JSON + base64）/ Image-to-image

传 `image_base64`，接口会先上传参考图再提交任务 / Pass `image_base64`; reference uploaded first.

```bash
curl -X POST "https://img.2capi.com/api/image-tasks/generations" \
  -H "Authorization: Bearer c2a_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "client_task_id": "demo-edit-001",
    "prompt": "请生成一张图片：参考这张图，改成赛博朋克夜景风格，只输出图片。",
    "model": "gpt-image-2-5.5",
    "n": 1,
    "image_base64": "iVBORw0KGgo..."
  }'
```

### 5.3 编辑图（multipart）/ Edit (multipart)

直接上传本地 `reference.png`，提交后仍用 `poll_url` 轮询 / Upload a local file; still poll via `poll_url`.

```bash
curl -X POST "https://img.2capi.com/api/image-tasks/edits" \
  -H "Authorization: Bearer c2a_xxx" \
  -F "client_task_id=demo-edit-002" \
  -F "prompt=请生成一张图片：把参考图改成水彩插画风格，只输出图片" \
  -F "model=gpt-image-2-5.5" \
  -F "n=1" \
  -F "image=@reference.png"
```

### 5.4 高清 2K / 4K / High-resolution

加 `size`（宽高比）、`resolution`（清晰度）。**2K/4K 仅高级用户**，普通用户返回 `403 premium_required`.

Add `size` and `resolution`. **2K/4K is premium-only**; standard users get `403 premium_required`.

```bash
curl -X POST "https://img.2capi.com/api/image-tasks/generations" \
  -H "Authorization: Bearer c2a_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "client_task_id": "demo-hd-001",
    "prompt": "请生成一张图片：雪山日出，超广角风光大片，只输出图片。",
    "model": "gpt-image-2-5.5",
    "n": 1,
    "size": "16:9",
    "resolution": "2k"
  }'
```

---

## 6. 轮询任务 / Poll the Task

```bash
curl -X GET "https://img.2capi.com/api/image-tasks?ids=demo-image-001" \
  -H "Authorization: Bearer c2a_xxx"
```

轮询间隔建议 3-8 秒，直到终态 / Poll every 3-8s until a terminal state.

---

## 7. 请求参数 / Request Fields

| 字段 / Field | 类型 | 必填 | 说明 / Description |
| --- | --- | --- | --- |
| `prompt` | string | 是 / Yes | 生图提示词 / Generation prompt |
| `model` | string | 否 / No | `gpt-image-2` 或 / or `gpt-image-2-5.5` |
| `n` | int | 否 / No | 数量 1-4；带参考图建议 `n=1` / Count 1-4 |
| `client_task_id` | string | 否 / No | 自定义任务 ID，便于轮询去重 / Custom task ID |
| `size` | string | 否 / No | 宽高比，见第 8 节 / Aspect ratio, see §8 |
| `resolution` | string | 否 / No | 清晰度，见第 8 节 / Clarity, see §8 |
| `image_base64` | string | 否 / No | 图生图参考图（仅 generations）/ Reference (generations) |
| `image` | file | 否 / No | 编辑图参考文件（仅 edits）/ Reference file (edits) |

---

## 8. 宽高比与清晰度 / Size & Resolution

### `size`（宽高比 / Aspect ratio）

留空为自动 / Empty = auto。

| 标准值 / Value | 别名 / Aliases |
| --- | --- |
| `1:1` | `square`, `1024x1024`, `2048x2048`, `4096x4096` |
| `16:9` | `1792x1024` |
| `9:16` | `1024x1792` |
| `4:3` | `3:2`, `landscape`, `1536x1024` |
| `3:4` | `2:3`, `portrait`, `1024x1536` |

### `resolution`（清晰度 / Clarity）

| 标准值 / Value | 说明 / Description |
| --- | --- |
| `1k`（默认 / default） | 标准通道，比例靠提示词生效 / Standard channel |
| `2k` | 高清，**仅高级用户** / High-res, **premium only** |
| `4k` | 超高清，**仅高级用户** / Ultra, **premium only** |

> `1k` 走标准通道；`2k`/`4k` 走高清（Codex）通道，按精确像素输出 / exact pixel sizes.

### 2K / 4K 实际像素 / Actual pixel sizes

| 宽高比 / Ratio | 2K | 4K |
| --- | --- | --- |
| `1:1` | 2048×2048 | 2048×2048 |
| `16:9` | 2048×1152 | 3840×2160 |
| `9:16` | 1152×2048 | 2160×3840 |
| `4:3` | 2048×1536 | 3072×2304 |
| `3:4` | 1536×2048 | 2304×3072 |

---

## 9. 响应示例 / Responses

### 提交返回 / Submit response

```json
{
  "task_id": "demo-image-001",
  "poll_url": "/api/image-tasks?ids=demo-image-001",
  "task": { "id": "demo-image-001", "status": "queued", "model": "gpt-image-2-5.5", "n": 1 }
}
```

### 成功轮询返回 / Successful poll response

```json
{
  "items": [
    {
      "id": "demo-image-001",
      "status": "succeeded",
      "result": { "data": [ { "b64_json": "...", "file_id": "sed:file_xxx" } ] },
      "gallery_task": {
        "public_image_id": "img_xxx",
        "image_url_public": "https://img.2capi.com/api/public/images/img_xxx.png"
      }
    }
  ]
}
```

> **取图建议 / How to get the image**：优先读 `gallery_task.image_url_public`，公开 URL 可重复访问、不暴露 API Key；需原始二进制则解码 `result.data[].b64_json`。
> Prefer `gallery_task.image_url_public`; for raw bytes decode `result.data[].b64_json`.

---

## 10. 错误码 / Error Codes

| 状态码 / Status | error_code | 说明 / Meaning |
| --- | --- | --- |
| `400` | `image_size_invalid` | 宽高比非法 / Invalid `size` |
| `400` | `image_resolution_invalid` | 清晰度非法 / Invalid `resolution` |
| `401` | — | Authorization 缺失或 API Key 错误 / Missing or invalid key |
| `403` | `premium_required` | 2K/4K 需高级用户 / Premium required |
| `429` | `image_task_limited` | 并发或每分钟次数超限 / Rate limited |
| `502` | — | 上游生成失败，看 `error_code`/`upstream_status` / Upstream failed |

---

## 11. 同步兼容接口 / Sync-compatible Endpoint

```bash
curl -X POST "https://img.2capi.com/v1/images/generations" \
  -H "Authorization: Bearer c2a_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "请生成一张图片：一只橘猫坐在月光窗台上，水彩风格，只输出图片。", "model": "gpt-image-2-5.5", "n": 1 }'
```

> 兼容 OpenAI 客户端，会等真实生图完成才返回，**很多客户端会超时**，不建议对外主用；同样支持 `size` 和 `resolution`。
> OpenAI-compatible but blocks until ready and clients often time out. Also supports `size`/`resolution`.

---

## 12. 完整 Python 示例 / Full Python Example

提交异步任务、轮询成功、保存图片到 `async_image_result.png`。使用前替换 `API_KEY`。

Submit, poll, and save the image to `async_image_result.png`. Replace `API_KEY` before use.

```python
from __future__ import annotations

import base64
import json
import time
import urllib.error
import urllib.request

BASE_URL = "https://img.2capi.com"
API_KEY = "c2a_xxx"  # 替换成你的固定 API Key / Replace with your API key
MODEL = "gpt-image-2-5.5"
PROMPT = "请生成一张图片：一只橘猫坐在月光窗台上，水彩风格，只输出图片。"
TASK_ID = f"api_demo_{int(time.time())}"

if not API_KEY or API_KEY == "c2a_xxx":
    raise SystemExit("请先把 API_KEY 替换成你的 c2a_xxx 固定 Key")


def request_json(method: str, path: str, body: dict | None = None) -> dict:
    data = None if body is None else json.dumps(body, ensure_ascii=False).encode("utf-8")
    headers = {"Accept": "application/json", "Authorization": f"Bearer {API_KEY}"}
    if body is not None:
        headers["Content-Type"] = "application/json"
    request = urllib.request.Request(BASE_URL + path, data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(request, timeout=60) as response:
            return json.loads(response.read().decode("utf-8") or "{}")
    except urllib.error.HTTPError as exc:
        raw = exc.read().decode("utf-8", errors="replace")
        if exc.code == 429 and "image_task_limited" in raw:
            raise SystemExit("当前固定 Key 所属用户已有图片任务处理中，请等待完成后重试。") from exc
        raise RuntimeError(f"HTTP {exc.code}: {raw}") from exc


submit = request_json(
    "POST",
    "/api/image-tasks/generations",
    {"client_task_id": TASK_ID, "prompt": PROMPT, "model": MODEL, "n": 1},
)
poll_url = submit.get("poll_url") or f"/api/image-tasks?ids={TASK_ID}"
print("submitted:", json.dumps(submit, ensure_ascii=False))

deadline = time.time() + 360
task = {}
while time.time() < deadline:
    result = request_json("GET", poll_url)
    items = result.get("items") or []
    task = items[0] if items else {}
    status = task.get("status")
    print("status:", status)
    if status in {"succeeded", "failed", "cancelled"}:
        break
    time.sleep(6)

if task.get("status") != "succeeded":
    raise SystemExit(f"任务失败：{json.dumps(task, ensure_ascii=False)}")

image = ((task.get("result") or {}).get("data") or [{}])[0]
with open("async_image_result.png", "wb") as file:
    file.write(base64.b64decode(image.get("b64_json") or ""))

print("saved:", "async_image_result.png")
gallery_task = task.get("gallery_task") or {}
print("gallery_image_url:", gallery_task.get("image_url_public"))
print("说明：优先读 image_url_public，公开图片地址可重复访问，不暴露 API Key。")
```

---

> 文档随接口更新 / Doc updated alongside the API · chatgpt2api
