> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apiyi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Справочник по API редактирования изображений

> Справочник по API редактирования изображений MAI-Image 2.6 с интерактивным Playground — загрузка эталонного изображения с инструкцией, слияние двух изображений через image + image2, загрузка файлов только через multipart/form-data

<Info>
  Интерактивный Playground справа поддерживает загрузку локальных изображений. Введите свой API-ключ в поле **Authorization** (формат: `Bearer sk-xxx`), выберите файл `image`, заполните `prompt` и `model` и отправьте запрос.
</Info>

<Warning>
  **🔴 Этот эндпоинт принимает только загрузку файлов `multipart/form-data`**

  Отправка JSON на `/v1/images/edits` (с `image` в виде URL, data URI или чистого base64) возвращает 400:

  ```text theme={null}
  request Content-Type isn't multipart/form-data
  ```

  **URL изображений не поддерживаются в качестве входных данных.** Если у вас есть только URL, сначала скачайте его на свой сервер, а затем загрузите файл. Для загрузки файла хостинг изображений не требуется — просто отправьте локальный файл.
</Warning>

<Tip>
  **Сценарий использования**: эта страница предназначена для редактирования референсного изображения или объединения двух изображений. Чтобы генерировать только по тексту, используйте [Text-to-Image API](/ru/api-capabilities/mai-image/text-to-image).
</Tip>

<Warning>
  **⚠️ Для двух изображений имена полей должны быть `image` + `image2`, а не `image[]`**

  При использовании двух референсных изображений назовите первое поле `image`, а второе — `image2`. Повторение `image[]`, повторение `image` или добавление поля `mask` вернут ошибку 400 `File must be attached in a form field with a name starting with 'image'`.

  Это означает, что отправка нескольких изображений через OpenAI SDK с помощью `client.images.edit(image=[f1, f2])` **не работает** (он отправляет `image[]`). Редактирование одного изображения через SDK работает корректно.
</Warning>

<Info>
  **Те же запрещенные параметры, что и для text-to-image**: не отправляйте `response_format`, `seed` или `negative_prompt` (400). Ответ всегда `data[0].b64_json` (PNG).
</Info>

## Примеры кода

### Python (OpenAI SDK · одно изображение)

```python theme={null}
from openai import OpenAI
import base64

client = OpenAI(
    api_key="sk-your-api-key",
    base_url="https://api.apiyi.com/v1",
    timeout=180.0
)

# images.edit uses a multipart file upload under the hood; do not pass response_format
resp = client.images.edit(
    model="MAI-Image-2.6-Flash",
    image=open("teaset.jpg", "rb"),
    prompt="Change the teapot to a deep cobalt blue glaze, keep everything else identical"
)

with open("edited.png", "wb") as f:
    f.write(base64.b64decode(resp.data[0].b64_json))
```

### Python (requests · одно изображение)

```python theme={null}
import base64
import os
import requests

# Pass the file via files=; requests sets multipart/form-data and the boundary for you
# Do not use json=, and do not set Content-Type by hand
with open("teaset.jpg", "rb") as fp:
    response = requests.post(
        "https://api.apiyi.com/v1/images/edits",
        headers={"Authorization": f"Bearer {os.environ['APIYI_API_KEY']}"},
        data={
            "model": "MAI-Image-2.6",
            "prompt": "Change the teapot to a deep cobalt blue glaze, keep everything else exactly the same"
        },
        files={"image": ("teaset.jpg", fp, "image/jpeg")},
        timeout=180
    )
response.raise_for_status()

with open("edited.png", "wb") as f:
    f.write(base64.b64decode(response.json()["data"][0]["b64_json"]))
```

### Python (слияние двух изображений · image + image2)

```python theme={null}
import base64
import os
import requests

files = {
    "image": ("scene.jpg", open("scene.jpg", "rb"), "image/jpeg"),     # image 1
    "image2": ("person.jpg", open("person.jpg", "rb"), "image/jpeg"),  # image 2: field name is image2
}

response = requests.post(
    "https://api.apiyi.com/v1/images/edits",
    headers={"Authorization": f"Bearer {os.environ['APIYI_API_KEY']}"},
    data={
        "model": "MAI-Image-2.6",
        "prompt": "Have the person from image 2 sit at the table in image 1, arranging the tea set, natural light, photorealistic"
    },
    files=files,
    timeout=180
)
response.raise_for_status()

with open("fused.png", "wb") as f:
    f.write(base64.b64decode(response.json()["data"][0]["b64_json"]))
```

### cURL

```bash theme={null}
# Single-image edit: -F means multipart/form-data, @ uploads a local file
curl -X POST "https://api.apiyi.com/v1/images/edits" \
  -H "Authorization: Bearer sk-your-api-key" \
  -F "model=MAI-Image-2.6-Flash" \
  -F "prompt=Change the teapot to a deep cobalt blue glaze, keep everything else identical" \
  -F "image=@teaset.jpg" \
  | python3 -c "import sys,json,base64; open('edited.png','wb').write(base64.b64decode(json.load(sys.stdin)['data'][0]['b64_json']))"
```

```bash theme={null}
# Two-image fusion with the canvas changed to 1536×1024
curl -X POST "https://api.apiyi.com/v1/images/edits" \
  -H "Authorization: Bearer sk-your-api-key" \
  -F "model=MAI-Image-2.6" \
  -F "prompt=Have the person from image 2 sit at the table in image 1, arranging the tea set" \
  -F "width=1536" \
  -F "height=1024" \
  -F "image=@scene.jpg" \
  -F "image2=@person.jpg"
```

### Node.js (fetch + FormData)

```javascript theme={null}
import fs from 'node:fs';

const form = new FormData();
form.append('model', 'MAI-Image-2.6-Flash');
form.append('prompt', 'Replace the background with a snowy pine forest at night, keep the person unchanged');
form.append('image', new Blob([fs.readFileSync('./photo.jpg')]), 'photo.jpg');
// Second reference image: form.append('image2', ...)

const resp = await fetch('https://api.apiyi.com/v1/images/edits', {
    method: 'POST',
    // Do not set Content-Type by hand; FormData adds the boundary
    headers: { 'Authorization': `Bearer ${process.env.APIYI_API_KEY}` },
    body: form,
    signal: AbortSignal.timeout(120000)
});

const data = await resp.json();
fs.writeFileSync('edited.png', Buffer.from(data.data[0].b64_json, 'base64'));
```

## Справочник параметров

| Параметр | Тип | Обязательный | По умолчанию | Описание |
| - | - | - | - | - |
| `model` | string | ✅ | — | `MAI-Image-2.6` (\$0.12/изображение) или `MAI-Image-2.6-Flash` (\$0.06/изображение), **с учётом регистра** |
| `prompt` | string | ✅ | — | Инструкция по редактированию. Укажите, что нужно изменить, а что должно остаться без изменений |
| `image` | file | ✅ | — | Файл референсного изображения (первое) |
| `image2` | file | ❌ | — | Второе референсное изображение (для объединения двух изображений) |
| `width` / `height` | integer | ❌ | По пропорциям оригинала | Размер на выходе, те же правила, что и для text-to-image; другое соотношение сторон **меняет композицию** изображения |
| `n` | integer | ❌ | `1` | Количество изображений. **Работает на этом эндпоинте**, тарифицируется за каждое изображение |
| ~~`mask`~~ | — | — | — | **Не поддерживается**; возвращает 400 |
| ~~`response_format`~~ / ~~`seed`~~ / ~~`negative_prompt`~~ | — | — | — | **Возвращают 400** |

<Info>
  **Размер на выходе, если параметр опущен**: результат сохраняет соотношение сторон оригинала с привязкой к значениям, кратным 16, например, при входном разрешении 1344×756 на выходе будет 1360×768. Для локальных правок, где необходимо сохранить композицию, не передавайте `width` / `height`.
</Info>

## Результаты редактирования и составление prompt

Эндпоинт редактирования **сохраняет композицию, цвета и детали оригинала** и изменяет только то, что указано в prompt:

<Frame>
  <img src="https://mintcdn.com/apiyillc/_zXMTnA1u6gpoDyM/images/mai-image-edit-teaset.jpg?fit=max&auto=format&n=_zXMTnA1u6gpoDyM&q=85&s=c86dc86c5aadf0173e19102433c01f49" alt="Пример редактирования с помощью MAI-Image-2.6-Flash: цвет чайника изменен с кремового на кобальтово-синий, все остальное без изменений" width="1048" height="532" data-path="images/mai-image-edit-teaset.jpg" />
</Frame>

| Prompt | Результат |
| - | - |
| ✅ `Change the teapot to a deep cobalt blue glaze, keep everything else exactly the same` | Меняется только цвет чайника; надписи и другие объекты остаются попиксельно идентичными |
| ✅ `Turn this photo into a watercolor painting, keep the composition` | Стиль перерисован, композиция сохранена |
| ✅ `Have the person from image 2 sit at the table in image 1` | Слияние двух изображений: изображение 1 задает сцену, изображение 2 — человека |
| ⚠️ `Make it look better` | Слишком неконкретно; масштаб изменений непредсказуем |

<Tip>
  Для слияния двух изображений ссылайтесь на `image` / `image2` как на «image 1 / image 2» в prompt. В наших тестах **сохранение сходства людей лишь умеренное** (черты лица могут смещаться), поэтому сначала проверьте работу на небольшой выборке, если важно портретное сходство.
</Tip>

## Формат ответа

```json theme={null}
{
  "created": 1791000788,
  "data": [
    {
      "b64_json": "iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAAADwf7zU..."
    }
  ],
  "usage": {
    "prompt_tokens": 1000,
    "total_tokens": 1000,
    "input_tokens": 1000,
    "output_tokens": 0
  }
}
```

<Warning>
  **Поля ответа**

  * `b64_json` — это **обычный base64 без префикса `data:`**, который декодируется в PNG.
  * При `n > 1` массив `data` содержит несколько элементов; не считывайте только `data[0]`.
  * `url` и `revised_prompt` не возвращаются.
</Warning>

<Info>
  **Не сверяйте тарификацию с `usage`**: он содержит плейсхолдеры (`prompt_tokens` всегда равен 1000 × количество изображений). Редактирование **стоит столько же**, сколько text-to-image, и тарифицируется за каждое изображение; определяющим является счет в консоли APIYI.
</Info>


## OpenAPI

````yaml api-reference/mai-image-edit-openapi-en.yaml POST /v1/images/edits
openapi: 3.1.0
info:
  title: MAI-Image 2.6 Image Editing API
  description: >
    Microsoft MAI-Image 2.6 image generation — image editing endpoint.


    - **The request must be `multipart/form-data` (file upload)**; JSON or image
    URLs return 400

    - Single-image editing and two-image fusion (field names `image` + `image2`)

    - No mask support; do not send `response_format` / `seed` /
    `negative_prompt`

    - Flat per-image pricing, same as text-to-image; `n` works on this endpoint
    and is billed per image


    **Authentication**: add `Authorization: Bearer YOUR_API_KEY` to the request
    headers


    **Get an API key**: create a token in the [APIYI
    console](https://api.apiyi.com/token)
  version: 1.0.0
servers:
  - url: https://api.apiyi.com
    description: Primary endpoint
security:
  - bearerAuth: []
paths:
  /v1/images/edits:
    post:
      tags:
        - Image Editing
      summary: 'Image editing: edit a reference image or fuse two images'
      description: >
        Edit an uploaded reference image, or fuse two images, from a text
        instruction with MAI-Image 2.6.


        - **Must use `multipart/form-data`**. Sending `application/json` returns
          400: `request Content-Type isn't multipart/form-data`
        - The second reference image's field is `image2`; repeated `image[]`,
        repeated `image`, or a `mask` field all return 400

        - Without `width` / `height` the output follows the original's ratio; a
        different aspect ratio recomposes the image
      operationId: editMaiImage
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/MaiImageEditRequest'
            encoding:
              image:
                contentType: image/png, image/jpeg, image/webp
              image2:
                contentType: image/png, image/jpeg, image/webp
      responses:
        '200':
          description: Image generated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageResponse'
        '400':
          description: >-
            Not multipart/form-data, invalid field names, invalid parameters, or
            blocked by moderation
        '401':
          description: Unauthorized - invalid API key
        '429':
          description: Rate limit exceeded or insufficient balance
        '500':
          description: No image file field in the request (`image is required`)
      security:
        - bearerAuth: []
components:
  schemas:
    MaiImageEditRequest:
      type: object
      required:
        - model
        - prompt
        - image
      properties:
        model:
          type: string
          description: Model ID (case-sensitive)
          enum:
            - MAI-Image-2.6-Flash
            - MAI-Image-2.6
          default: MAI-Image-2.6-Flash
        prompt:
          type: string
          description: >-
            Edit instruction. State what to change and that everything else
            stays the same
          example: >-
            Change the teapot to a deep cobalt blue glaze, keep everything else
            identical
        image:
          type: string
          format: binary
          description: >-
            Reference image file (the first one, "image 1" in the prompt). png /
            jpg / webp
        image2:
          type: string
          format: binary
          description: >-
            Optional second reference image ("image 2" in the prompt), for
            two-image fusion
        width:
          type: integer
          description: >-
            Optional output width. Same rules as text-to-image: each side ≥ 768,
            width × height ≤ 2,359,296, sent together with `height`
          minimum: 768
        height:
          type: integer
          description: Optional output height, same rules as `width`
          minimum: 768
        'n':
          type: integer
          description: Number of images. Works on this endpoint, billed per image
          minimum: 1
          default: 1
          example: 1
    ImageResponse:
      type: object
      properties:
        created:
          type: integer
          description: Creation timestamp
          example: 1791000788
        data:
          type: array
          description: Image results; length equals `n`
          items:
            type: object
            properties:
              b64_json:
                type: string
                description: 'Plain base64 image data (PNG, no data: prefix)'
        usage:
          type: object
          description: >-
            **Placeholder values, not for billing reconciliation.**
            `prompt_tokens` is always `1000 × images`
          properties:
            prompt_tokens:
              type: integer
              example: 1000
            total_tokens:
              type: integer
              example: 1000
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key from the APIYI console

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.