# Hướng dẫn API v1 — IMG Studio

> Tài liệu công khai cho người dùng và AI agent. Dùng API để tạo hoặc chỉnh sửa **1 ảnh mỗi request** từ n8n, Make, script, OpenAI SDK hay ứng dụng ngoài. API video và webhook chưa được hỗ trợ.

- Trang HTML: `https://imgstudio.site/docs/api`
- Markdown cho AI agent: `https://imgstudio.site/docs/api.md`
- Base URL: `https://imgstudio.site`
- OpenAI-compatible base URL: `https://imgstudio.site/api/v1`

## 1. Bắt đầu nhanh cho AI agent

Nếu bạn là AI agent đang thiết lập kết nối thay người dùng, hãy làm theo thứ tự:

1. Yêu cầu người dùng tự tạo API key tại `https://imgstudio.site/billing`. Không yêu cầu họ gửi key vào chat công khai.
2. Lưu key trong biến môi trường hoặc secret manager, ví dụ `IMG_STUDIO_API_KEY`. Không ghi key vào source code, URL hay log.
3. Gọi `GET /api/v1/providers` hoặc `GET /api/v1/models` để lấy ID model thật. Không tự đoán ID từ tên hiển thị.
4. Tạo một `Idempotency-Key` mới cho mỗi tác vụ; khi retry cùng tác vụ phải giữ nguyên key đó.
5. Đặt timeout HTTP từ 300 giây vì quá trình tạo ảnh chạy đồng bộ.
6. Khi thành công, tải file ngay. Media thường chỉ được lưu khoảng 6 giờ; URL có chữ ký của API OpenAI-compatible hết hạn sau khoảng 10 phút.
7. Không tự retry lỗi `400`, `401`, `402`, `403`, `404`, `409` hoặc `410`. Với `202`, chờ rồi gọi lại bằng cùng idempotency key. Với `429` hoặc lỗi `5xx` tạm thời, retry có backoff và giữ nguyên key.

Có hai giao thức:

- **API gốc**: rõ nhất cho n8n, Make và HTTP script. Dùng `provider_id`, bắt buộc `Idempotency-Key`.
- **OpenAI-compatible**: phù hợp với OpenAI SDK hoặc công cụ cho nhập custom base URL. Dùng `model`; server ưu tiên `Idempotency-Key`, sau đó `X-Request-ID`, và tự sinh nếu cả hai đều thiếu.

## 2. Tạo API key và xác thực

1. Đăng nhập IMG Studio.
2. Vào **Nạp tiền / API key** tại `https://imgstudio.site/billing`.
3. Bấm **Tạo API key** và sao chép ngay; key chỉ hiện một lần, có dạng `img_...`.
4. Có thể thu hồi key tại cùng trang. Mỗi tài khoản có tối đa 5 key đang hoạt động.

Mặc định chỉ admin hoặc tài khoản đã từng nạp tiền thật được tạo API key. Đây là gate chống lạm dụng lúc tạo key; quyền model và số dư vẫn được kiểm riêng khi gọi API.

Mọi request API phải có header:

```http
Authorization: Bearer img_xxxxxxxx
```

Ví dụ dùng biến môi trường:

```bash
export IMG_STUDIO_API_KEY="img_xxxxxxxx"
```

## 3. API gốc

### 3.1. Lấy danh sách model

```http
GET /api/v1/providers
Authorization: Bearer <API_KEY>
```

Response:

```json
{
  "providers": [
    {
      "id": "uuid-provider",
      "name": "Tên model trên IMG Studio",
      "is_default": true,
      "supports_generate": true,
      "supports_edit": true,
      "supports_transparent_background_generate": true,
      "supports_transparent_background_edit": true,
      "max_edit_images": 3,
      "max_resolution": "4K"
    }
  ]
}
```

- Dùng `id` làm `provider_id` trong request tạo hoặc sửa ảnh.
- Chỉ gọi endpoint sửa ảnh khi `supports_edit` là `true`.
- Chỉ dùng `background: "transparent"` khi capability tương ứng với thao tác là `true`.
- Không gửi nhiều hơn `max_edit_images` ảnh nguồn.
- Danh sách chỉ gồm model mà tài khoản hiện được phép nhìn thấy; quyền sử dụng còn có thể phụ thuộc việc tài khoản đã nạp tiền.

### 3.2. Tạo ảnh

```http
POST /api/v1/images/generate
Authorization: Bearer <API_KEY>
Content-Type: application/json
Idempotency-Key: <chuỗi duy nhất, tối đa 120 ký tự>
```

Body:

```json
{
  "prompt": "a cat sitting on a windowsill, soft morning light",
  "provider_id": "uuid-provider",
  "aspect_ratio": "1:1",
  "resolution": "1K",
  "quality": "standard",
  "background": "opaque"
}
```

| Field | Bắt buộc | Mặc định | Giá trị |
|---|---:|---|---|
| `prompt` | Có | — | Mô tả ảnh |
| `provider_id` | Có | — | `id` từ `/api/v1/providers` |
| `aspect_ratio` | Không | `1:1` | `1:1`, `3:2`, `4:3`, `16:9`, `2:3`, `3:4`, `9:16` |
| `resolution` | Không | `1K` | `1K`, `2K`, `4K` |
| `quality` | Không | `standard` | `standard`, `high` |
| `background` | Không | `opaque` | `opaque` hoặc `transparent`; chỉ dùng `transparent` khi `supports_transparent_background_generate` là `true` |
| `count` | Không | `1` | Chỉ nhận `1` |

Response thành công `200`:

```json
{
  "id": "uuid-image",
  "status": "completed",
  "prompt": "...",
  "provider_name": "...",
  "model": "...",
  "aspect_ratio": "1:1",
  "resolution": "1K",
  "quality": "standard",
  "cost_vnd": 100,
  "balance_vnd": 9900,
  "url": "/api/v1/images/uuid-image/file",
  "created_at": "2026-01-01T00:00:00.000Z",
  "reused": false
}
```

`url` là đường dẫn tương đối. Ghép với `https://imgstudio.site` và gửi cùng Bearer header để tải file.

### 3.3. Chỉnh sửa ảnh

Endpoint này nhận `multipart/form-data`, không nhận JSON:

```http
POST /api/v1/images/edit
Authorization: Bearer <API_KEY>
Idempotency-Key: <chuỗi duy nhất, tối đa 120 ký tự>
Content-Type: multipart/form-data; boundary=...
```

| Field form | Bắt buộc | Mặc định | Ghi chú |
|---|---:|---|---|
| `images` | Có | — | Gửi một hoặc nhiều lần cùng tên field; không vượt `max_edit_images` |
| `prompt` | Có | — | Mô tả thay đổi cần thực hiện |
| `provider_id` | Có | — | `id` từ `/api/v1/providers`; model phải có `supports_edit: true` |
| `aspect_ratio` | Không | `auto` | `auto` giữ tỷ lệ hỗ trợ gần nhất với ảnh đầu tiên; cũng nhận các tỷ lệ của endpoint tạo ảnh |
| `resolution` | Không | `1K` | `1K`, `2K`, `4K` |
| `quality` | Không | `standard` | `standard`, `high` |
| `background` | Không | `opaque` | `opaque` hoặc `transparent`; chỉ dùng `transparent` khi `supports_transparent_background_edit` là `true` |

Tổng dung lượng toàn bộ ảnh nguồn tối đa 9.5MB mỗi request. Response thành công có cùng cấu trúc với endpoint tạo ảnh.

### 3.4. Lấy metadata và file ảnh

```http
GET /api/v1/images/{id}
Authorization: Bearer <API_KEY>
```

```http
GET /api/v1/images/{id}/file
Authorization: Bearer <API_KEY>
```

- Chỉ chủ ảnh hoặc admin được truy cập.
- File mặc định giữ định dạng đã lưu, thường là WebP.
- Thêm `?format=jpg` để nhận JPEG.
- Hãy tải và lưu file vào nơi bền vững ngay sau khi tạo; media của user thường được tự xóa sau khoảng 6 giờ.

## 4. OpenAI-compatible API

Dùng base URL:

```text
https://imgstudio.site/api/v1
```

Các endpoint:

```http
GET /api/v1/models
POST /api/v1/images/generations
POST /api/v1/images/edits
Authorization: Bearer <API_KEY>
```

### 4.1. Danh sách model

`GET /api/v1/models` trả format OpenAI và thêm `name`, `aliases`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "uuid-provider",
      "name": "Tên model trên IMG Studio",
      "aliases": ["model-alias"],
      "object": "model",
      "created": 1767225600,
      "owned_by": "img-studio",
      "supports_transparent_background_generate": true,
      "supports_transparent_background_edit": true
    }
  ]
}
```

Dùng chính xác `id` hoặc một giá trị trong `aliases` làm `model`. `name` chỉ để hiển thị. Nếu `aliases` rỗng, dùng `id`.

### 4.2. Tạo ảnh

```json
{
  "model": "uuid-provider",
  "prompt": "minimal product photo of a ceramic cup",
  "size": "1024x1024",
  "n": 1,
  "quality": "standard",
  "background": "opaque",
  "response_format": "url"
}
```

| Field | Mặc định | Ghi chú |
|---|---|---|
| `model` | — | Bắt buộc; dùng `id` hoặc `alias` từ `/models` |
| `prompt` | — | Bắt buộc |
| `n` | `1` | Chỉ hỗ trợ `1` |
| `size` | `1024x1024` | Xem bảng dưới |
| `quality` | `standard` | `auto`, `low`, `medium`, `standard` → standard; `high`, `hd` → high |
| `background` | `opaque` | `opaque` hoặc `transparent`; kiểm tra `supports_transparent_background_generate` trong `/models` trước khi dùng `transparent` |
| `response_format` | `url` | `url` hoặc `b64_json` |

| Size | Tỷ lệ / bậc |
|---|---|
| `auto`, `1024x1024` | `1:1`, `1K` |
| `1536x1024` | `4:3`, `2K` |
| `1024x1536` | `3:4`, `2K` |
| `1792x1024` | `16:9`, `2K` |
| `1024x1792` | `9:16`, `2K` |
| `3840x3840` | `1:1`, `4K` |
| `3840x2880` | `4:3`, `4K` |
| `2880x3840` | `3:4`, `4K` |
| `3840x2160` | `16:9`, `4K` |
| `2160x3840` | `9:16`, `4K` |

Response `url` trả URL tuyệt đối có chữ ký, không cần Bearer khi tải và hết hạn sau khoảng 10 phút. `b64_json` trả bytes ảnh dạng base64.

### 4.3. Chỉnh sửa ảnh

Dùng `client.images.edit(...)` hoặc `POST /api/v1/images/edits` với `multipart/form-data`:

- Ảnh nguồn: field `image`, `image[]` hoặc `images`.
- Các field còn lại: `model`, `prompt`, `size`, `quality`, `background`, `response_format`, `n=1`.
- `background` mặc định là `opaque`; chỉ dùng `transparent` khi `supports_transparent_background_edit` trong `/models` là `true`.
- `mask` chưa được hỗ trợ.
- Giới hạn model và số ảnh nguồn giống API gốc.

### 4.4. Idempotency

Nên gửi một header ổn định cho mọi lần retry cùng tác vụ:

```http
Idempotency-Key: <request-id>
```

Hoặc:

```http
X-Request-ID: <request-id>
```

Server ưu tiên `Idempotency-Key`. Nếu thiếu cả hai, server tự sinh ID để tương thích SDK, nhưng request gửi lại sau timeout có thể bị coi là tác vụ mới và trừ tiền thêm lần nữa. Nếu đổi `background` hoặc bất kỳ nội dung request nào để tạo một tác vụ khác, phải dùng key mới; retry cùng tác vụ phải giữ nguyên key cũ.

## 5. Ví dụ hoàn chỉnh

### 5.1. curl — API gốc

```bash
# Lấy model
curl -s https://imgstudio.site/api/v1/providers \
  -H "Authorization: Bearer $IMG_STUDIO_API_KEY"

# Tạo ảnh
curl -s https://imgstudio.site/api/v1/images/generate \
  -H "Authorization: Bearer $IMG_STUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-$(date +%s)" \
  -d '{
    "prompt": "minimal product photo of a ceramic cup",
    "provider_id": "PASTE_PROVIDER_ID",
    "aspect_ratio": "1:1",
    "resolution": "1K"
  }'

# Chỉnh sửa ảnh; curl tự đặt multipart boundary
curl -s https://imgstudio.site/api/v1/images/edit \
  -H "Authorization: Bearer $IMG_STUDIO_API_KEY" \
  -H "Idempotency-Key: edit-001" \
  -F "images=@input.png" \
  -F "prompt=đổi nền thành bãi biển hoàng hôn" \
  -F "provider_id=PASTE_PROVIDER_ID" \
  -F "resolution=1K"
```

### 5.2. Python — OpenAI SDK

```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["IMG_STUDIO_API_KEY"],
    base_url="https://imgstudio.site/api/v1",
    timeout=300.0,
)

models = client.models.list()
model_id = models.data[0].id

result = client.images.generate(
    model=model_id,
    prompt="minimal product photo of a ceramic cup",
    size="1024x1024",
    n=1,
    response_format="b64_json",
    extra_headers={"Idempotency-Key": "python-create-001"},
)

with open("output.webp", "wb") as output:
    import base64
    output.write(base64.b64decode(result.data[0].b64_json))
```

### 5.3. JavaScript — OpenAI SDK

```javascript
import fs from "node:fs";
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.IMG_STUDIO_API_KEY,
  baseURL: "https://imgstudio.site/api/v1",
  timeout: 300_000,
});

const models = await client.models.list();
const model = models.data[0].id;
const result = await client.images.generate(
  {
    model,
    prompt: "minimal product photo of a ceramic cup",
    size: "1024x1024",
    n: 1,
    response_format: "b64_json",
  },
  { headers: { "Idempotency-Key": "js-create-001" } },
);

fs.writeFileSync("output.webp", Buffer.from(result.data[0].b64_json, "base64"));
```

## 6. n8n, Make và ứng dụng ngoài

### n8n

1. Dùng node **HTTP Request**, method `POST`.
2. URL: `https://imgstudio.site/api/v1/images/generate`.
3. Header `Authorization`: `Bearer img_...`.
4. Header `Idempotency-Key`: một ID ổn định của lần chạy, ví dụ `{{$execution.id}}`.
5. Body JSON gồm `prompt`, `provider_id` và các tùy chọn.
6. Đặt timeout 300 giây.
7. Node tiếp theo tải `https://imgstudio.site{{ $json.url }}` bằng cùng Bearer header và lưu binary ngay.

Với edit, chọn body **Form-Data**, đặt file binary vào field `images`; không tự đặt header `Content-Type` vì n8n cần tự thêm multipart boundary.

### Make

Dùng module **HTTP > Make a request** với cùng URL và headers. Tạo ảnh dùng body type JSON; sửa ảnh dùng multipart/form-data. Đặt một ID của bundle hoặc execution vào `Idempotency-Key`, sau đó tải `url` trả về bằng request có Bearer header.

### Photoshop và phần mềm desktop

Có thể tích hợp IMG Studio qua plugin hoặc script gọi HTTP API. Plugin nên lưu API key trong secure storage của ứng dụng, gọi danh sách model trước và tải file kết quả ngay. Việc cài plugin cụ thể phụ thuộc phiên bản Photoshop và công nghệ plugin mà khách đang dùng.

## 7. Mã lỗi và retry

| HTTP | Ý nghĩa | Xử lý |
|---:|---|---|
| `200` | Thành công | Lưu response và tải file ngay |
| `202` | Cùng idempotency key đang được xử lý | Chờ khoảng 1.5–3 giây rồi gọi lại cùng key |
| `400` | Thiếu field, giá trị sai, model không hỗ trợ thao tác | Sửa request; không retry nguyên trạng |
| `401` | Thiếu, sai hoặc đã thu hồi API key | Kiểm tra Bearer key |
| `402` | Số dư không đủ | Nạp tiền; không retry tự động |
| `403` | Không có quyền hoặc model đang bị khóa | Chọn model được phép hoặc nạp tiền |
| `404` | Model, ảnh hoặc file không tồn tại | Làm mới danh sách model; ảnh có thể đã hết retention |
| `409` | Tác vụ với idempotency key này đã thất bại | Chỉ dùng key mới sau khi đã quyết định tạo một tác vụ mới |
| `410` | Ảnh bị xóa trước khi tác vụ hoàn tất | Không retry tác vụ cũ; kiểm tra lịch sử và tạo tác vụ mới nếu cần |
| `413` | Tổng ảnh nguồn vượt 9.5MB | Giảm kích thước hoặc số ảnh nguồn |
| `429` | Vượt giới hạn theo user/model hoặc hệ thống bận | Backoff, giữ nguyên idempotency key |
| `500` | Lỗi provider/server | Retry có backoff bằng cùng key; đọc message để biết trạng thái hoàn tiền |

Rate limit không phải một con số chung cho mọi model. Hệ thống chia lane theo nhóm model; lane thường là 3 tác vụ/phút/user, một số model nhanh có giới hạn cao hơn, còn một số model khan hiếm thấp hơn. Client nên chạy tuần tự hoặc concurrency thấp và xử lý `429` thay vì giả định RPM cố định.

## 8. Giá, đầu ra và bảo mật

- Giá phụ thuộc model, thao tác và độ phân giải; `cost_vnd` trong response thành công là số tiền thực tế của tác vụ.
- Đầu ra `4K` cộng phụ phí cố định 150đ/ảnh. Hệ thống có thể hậu xử lý để đạt bậc đầu ra yêu cầu trong khi vẫn giữ request upstream trong giới hạn thật của model.
- Chỉnh sửa có thể có giá khác tạo ảnh.
- Provider hoặc hậu xử lý lỗi sau khi trừ tiền sẽ kích hoạt quy trình hoàn tiền; đọc message lỗi để biết đã hoàn hay đang cần admin kiểm tra.
- Không hỗ trợ video, batch nhiều ảnh đầu ra hoặc webhook async trong API v1 hiện tại.
- Không đưa API key vào frontend public, mobile bundle, URL query, source control, ảnh chụp màn hình hoặc log.
- Nếu key lộ, thu hồi ngay tại `https://imgstudio.site/billing` và tạo key mới.
