# Edit an image

> Change one thing on an image and keep the rest, on the whole image or an area, or erase what an area covers.

Source: https://developers.mnml.ai/docs/edits

`POST https://api.mnml.ai/v2/edits`

## Example request

**curl**

```bash
curl -X POST https://api.mnml.ai/v2/edits \
  -H "Authorization: Bearer $MNML_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "job_id": "10482",
    "prompt": "Replace the cladding with dark brick",
    "region": {
      "box": {
        "x": 0.12,
        "y": 0.3,
        "width": 0.5,
        "height": 0.45
      }
    }
  }'
```

**TypeScript**

```ts
const res = await fetch("https://api.mnml.ai/v2/edits", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.MNML_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "job_id": "10482",
    "prompt": "Replace the cladding with dark brick",
    "region": {
      "box": {
        "x": 0.12,
        "y": 0.3,
        "width": 0.5,
        "height": 0.45
      }
    }
  }),
});

const data = await res.json();
```

**Python**

```python
import os, requests

res = requests.post(
    "https://api.mnml.ai/v2/edits",
    headers={"Authorization": f"Bearer {os.environ['MNML_API_KEY']}"},
    json={
      "job_id": "10482",
      "prompt": "Replace the cladding with dark brick",
      "region": {
        "box": {
          "x": 0.12,
          "y": 0.3,
          "width": 0.5,
          "height": 0.45
        }
      }
    },
)

data = res.json()
```

## Example response (202)

```json
{
  "success": true,
  "data": {
    "id": "10483",
    "status": "queued",
    "charged_usd": 0.099,
    "credits_charged": 10,
    "replayed": false,
    "notes": []
  }
}
```

Returns `202` straight away with the job and what it charged. Poll [GET /v2/jobs/{id}](https://developers.mnml.ai/docs/jobs) for the result; a job that fails is refunded. An edit is $0.099 and an erase $0.099, whichever engine made the image.

## Choosing the area

- A `region`: a box or a polygon in fractions of the image, drawn at the image’s own size, so it means the same on any resolution.
- A `mask`: a black-and-white PNG the size of the image, white where to change, sent like the image (a file, a link or base64).
- Neither: an edit changes the whole image. An erase always needs an area.

## Headers

- `Authorization` (string, required): `Bearer mk_live_…`: your API key. See [Authentication](https://developers.mnml.ai/docs/authentication).
- `Content-Type` (string, required): `application/json`, or `multipart/form-data` to send a file.
- `Idempotency-Key` (string): Your own key, 1 to 255 visible ASCII characters. A retry with the same key and request within 24 hours returns the first answer instead of running again.

## Body

- `kind` (string, default `edit`): `edit` changes what the prompt names. `erase` removes what the area covers and fills in the background. Values: `edit`, `erase`.
- `prompt` (string): What to change, in plain words. Required for an edit; an erase takes none.
- `image` (string): The JPEG, PNG or WebP to work on, up to 15 MB: a public `https://` link we fetch, a `data:image/…;base64,` URI, or bare base64. With multipart form data, attach the file itself (`-F image=@house.jpg`). Send one of `image` or `job_id`.
- `job_id` (string): A finished job of yours: work on its output without downloading it first.
- `engine` (string, default `v4.6-ultra`): The engine whose edit runs. An erase takes none.
- `mode` (string, default `exterior`): What the image shows. An erase takes none. Values: `exterior`, `interior`, `masterplan`, `plan`, `landscape`, `product`, `text-to-render`.
- `references` (string | object[]): Images whose style, materials, mood or geometry to follow, up to 15. Each is just the image (a link or base64, or with multipart a `references` file part, repeated), or an object, `{ image | job_id, mode }`, that also sets its `mode`. How many an engine takes is `capabilities.max_references` in [GET /v2/engines](https://developers.mnml.ai/docs/engines).
  - `image` (string): The reference image: a public `https://` link we fetch, a `data:image/…;base64,` URI, or bare base64. With multipart form data, attach the file itself. Send one of `image` or `job_id`.
  - `job_id` (string): The reference image, as a finished job of yours.
  - `mode` (string, default `style`): What to take from it: its `style`, a `material`, the `atmosphere`, the `color` or the `geometry`. `auto` lets the engine decide. Values: `auto`, `style`, `material`, `atmosphere`, `color`, `geometry`.
- `region` (object): The area to change, as a `box` or a `polygon`, in 0–1 fractions of the image from its top-left corner. Leave it out to edit the whole image.
  - `box` (object): A rectangle.
    - `x` (number, required): Its left edge, 0–1 of the image’s width.
    - `y` (number, required): Its top edge, 0–1 of the image’s height.
    - `width` (number, required): Its width, 0–1 of the image’s width.
    - `height` (number, required): Its height, 0–1 of the image’s height.
  - `polygon` (number[][]): Any outline, as `[[x, y], …]` points in the same 0–1 fractions.
- `mask` (string): The area as a mask: a PNG the size of the image, white where to change, black where to keep. a public `https://` link we fetch, a `data:image/…;base64,` URI, or bare base64. With multipart form data, attach the file itself. Send `region` or `mask`, not both.
- `webhook_url` (string): A public `https://` URL to send this job’s settle event to, signed like every [webhook](https://developers.mnml.ai/docs/webhooks), on top of your account’s endpoints.

## Response

On success (`202`): Started. Poll GET /v2/jobs/{id} for the result. The JSON is `{ "success": true, "data": … }`, and inside `data`:

- `id` (string, required): The job. Read it at [GET /v2/jobs/{id}](https://developers.mnml.ai/docs/jobs).
- `status` (string, required): The job’s status when it was accepted, usually `queued`. Values: `queued`, `processing`, `succeeded`, `failed`, `canceled`.
- `charged_usd` (number, required): What this call charged, in US dollars. A job that fails is refunded.
- `replayed` (boolean, required): True when this is the stored answer to an earlier identical request with the same `Idempotency-Key`: nothing ran or was charged again. See [Idempotency](https://developers.mnml.ai/docs/idempotency).
- `notes` (string[], required): What was accepted but not applied, in plain words: a setting that does not fit the engine, a seed it does not take. Empty when everything applied.

**Response headers (5)**

- `X-Request-Id` (string): This request, for support and the console log.
- `RateLimit-Limit` (integer): Requests this key may make per minute.
- `RateLimit-Remaining` (integer): Requests left in the current minute.
- `RateLimit-Reset` (integer): Seconds until the current minute resets.
- `Idempotent-Replayed` (string): Present, as `true`, when this is the stored answer to an earlier request.

## Status codes

| Status | Meaning |
| --- | --- |
| 202 | Started. Poll GET /v2/jobs/{id} for the result. |
| 401 | The API key is missing, malformed, unknown or revoked. |
| 402 | The balance does not cover this call. |
| 409 | The Idempotency-Key was reused for a different request, or is still in progress. |
| 429 | A limit was reached: requests per minute, or a daily or concurrency limit. |
| Other | Any other error, in the same envelope. |

Every error answers `{ "success": false, "error": { "code", "message" } }`. What each code means, and what to do, is on [Errors](https://developers.mnml.ai/docs/errors).
