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

# Edit an Image with AI

> Change, restyle, or combine existing images with a text instruction

This guide shows you how to edit an existing image through the AI Studio image endpoint. There is no separate edit endpoint: you send the image (or images) you want to change as `referenceImageUrls` together with an instruction, and the model returns a new image. The same request shape covers replacing objects, changing backgrounds, restyling, and combining elements from several pictures.

## What You Will Build

<CardGroup cols={2}>
  <Card title="Targeted Changes" icon="pen">
    Replace, remove, or add an element while keeping the rest of the picture
  </Card>

  <Card title="Restyling" icon="palette">
    Turn a photo into an illustration, a sketch, or a different look
  </Card>

  <Card title="Composition" icon="object-group">
    Combine a subject from one image with the setting of another
  </Card>

  <Card title="Consistent Outputs" icon="clone">
    Produce variations of a product shot that keep the product identical
  </Card>
</CardGroup>

## Before You Begin

Make sure you have:

* A [Pictory API key](https://app.pictory.ai/api-access)
* Node.js or Python installed on your machine
* The required packages installed
* Publicly accessible URLs for the images you want to edit

<CodeGroup>
  ```bash npm theme={null}
  npm install axios
  ```

  ```bash pip theme={null}
  pip install requests
  ```
</CodeGroup>

## Which Models Can Edit

| Model | Reference Images | Aspect Ratio on Edits | AI Credits per Image |
| - | - | - | - |
| `nanobanana2` | Up to 4 | Honored | 8 |
| `nanobanana-lite2` | Up to 4 (served by `nanobanana2`) | Honored | 4 |
| `nanobanana-pro` | Up to 4 | Honored | 14 |
| `seedream3.0` | Up to 4 | Honored | 2 |
| `nanobanana` | Up to 4 | Follows the reference | 4 |
| `nova-canvas` | 1 | Follows the reference | 4 |

<Note>
  `flux-schnell` cannot edit. Sending reference images to it returns a `400` with the code `IMAGE_EDITING_NOT_SUPPORTED`. The [Get Model Capabilities](/api-reference/ai-studio/get-models) endpoint reports `editing` and `referenceImages.max` per model.
</Note>

## Step-by-Step Guide

### Step 1: Set Up Your Request

Send the image to edit as the first reference and write the instruction as the prompt. For a plain edit, one reference is enough. To bring in an element from another picture, add it as a second reference and refer to it by position in the prompt.

<CodeGroup>
  ```javascript Node.js theme={null}
  import axios from "axios";

  const API_BASE_URL = "https://api.pictory.ai/pictoryapis";
  const API_KEY = "YOUR_API_KEY"; // Replace with your actual API key

  // Edit an existing image
  const imageRequest = {
    prompt: "Replace the blue sofa in the first image with a tan leather armchair, keeping the lighting, floor, and everything else unchanged",
    model: "nanobanana2",
    aspectRatio: "16:9",
    referenceImageUrls: [
      "https://example.com/images/living-room.png"
    ]
  };
  ```

  ```python Python theme={null}
  import requests
  import time

  API_BASE_URL = "https://api.pictory.ai/pictoryapis"
  API_KEY = "YOUR_API_KEY"  # Replace with your actual API key

  # Edit an existing image
  image_request = {
      "prompt": "Replace the blue sofa in the first image with a tan leather armchair, keeping the lighting, floor, and everything else unchanged",
      "model": "nanobanana2",
      "aspectRatio": "16:9",
      "referenceImageUrls": [
          "https://example.com/images/living-room.png"
      ]
  }
  ```
</CodeGroup>

<Tip>
  Edits are sent verbatim by default, which suits a precise instruction such as "replace X with Y": the enhancer is designed to make creative prompts richer and can add detail you did not ask for. Set `enhancePrompt: true` when you want the model to interpret a loose brief.
</Tip>

### Step 2: Submit the Image Generation Request

Send the request to the AI Studio image generation endpoint.

<CodeGroup>
  ```javascript Node.js theme={null}
  async function editImage() {
    try {
      console.log("Submitting image edit request...");

      const response = await axios.post(
        `${API_BASE_URL}/v1/aistudio/images`,
        imageRequest,
        {
          headers: {
            "Content-Type": "application/json",
            Authorization: API_KEY,
          },
        }
      );

      const jobId = response.data.data.jobId;
      console.log("Image edit started.");
      console.log("Job ID:", jobId);

      return jobId;
    } catch (error) {
      console.error("Error submitting request:", error.response?.data || error.message);
      throw error;
    }
  }
  ```

  ```python Python theme={null}
  def edit_image():
      try:
          print("Submitting image edit request...")

          response = requests.post(
              f"{API_BASE_URL}/v1/aistudio/images",
              json=image_request,
              headers={
                  "Content-Type": "application/json",
                  "Authorization": API_KEY
              }
          )
          response.raise_for_status()

          job_id = response.json()["data"]["jobId"]
          print("Image edit started.")
          print(f"Job ID: {job_id}")

          return job_id

      except requests.exceptions.RequestException as error:
          print(f"Error submitting request: {error}")
          raise
  ```
</CodeGroup>

### Step 3: Poll for the Result

Check the job status at regular intervals until the edited image is ready.

<CodeGroup>
  ```javascript Node.js theme={null}
  async function waitForImage(jobId) {
    console.log("\nPolling for image edit result...");

    while (true) {
      const response = await axios.get(
        `${API_BASE_URL}/v1/jobs/${jobId}`,
        {
          headers: { Authorization: API_KEY },
        }
      );

      const data = response.data;
      const status = data.data.status;
      console.log("Status:", status);

      if (status === "completed") {
        console.log("\nImage edited successfully!");
        console.log("Image URL:", data.data.url);
        console.log("AI Credits Used:", data.data.aiCreditsUsed);
        return data;
      }

      if (status === "failed") {
        throw new Error("Image edit failed: " + JSON.stringify(data));
      }

      // Wait 15 seconds before polling again
      await new Promise(resolve => setTimeout(resolve, 15000));
    }
  }

  // Run the complete workflow
  editImage()
    .then(jobId => waitForImage(jobId))
    .then(result => console.log("\nDone!"))
    .catch(error => console.error("Error:", error));
  ```

  ```python Python theme={null}
  def wait_for_image(job_id):
      print("\nPolling for image edit result...")

      while True:
          response = requests.get(
              f"{API_BASE_URL}/v1/jobs/{job_id}",
              headers={"Authorization": API_KEY}
          )
          response.raise_for_status()

          data = response.json()
          status = data["data"]["status"]
          print(f"Status: {status}")

          if status == "completed":
              print("\nImage edited successfully!")
              print(f"Image URL: {data['data']['url']}")
              print(f"AI Credits Used: {data['data']['aiCreditsUsed']}")
              return data

          if status == "failed":
              raise Exception(f"Image edit failed: {data}")

          # Wait 15 seconds before polling again
          time.sleep(15)

  # Run the complete workflow
  if __name__ == "__main__":
      job_id = edit_image()
      result = wait_for_image(job_id)
      print("\nDone!")
  ```
</CodeGroup>

## Understanding the Parameters

| Parameter | Type | Required | Default | Description |
| - | - | - | - | - |
| `prompt` | string | Yes | - | The edit instruction. Must be between 5 and 5,000 characters. |
| `referenceImageUrls` | array | Yes for an edit | - | 1 to 4 publicly accessible image URLs; the first is the image being edited. |
| `model` | string | No | `seedream3.0` | Any model from the table above. |
| `aspectRatio` | string | No | `1:1` | Honored only on models marked so above; otherwise the output follows the reference. |
| `enhancePrompt` | boolean | No | `false` | Off by default, so the instruction is sent verbatim (recommended for edits). Set to `true` to enhance it. |
| `trainingPreset` | string | No | - | `sales-training`, `product-training`, or `soft-skills-training`. Applied during enhancement, so it always turns enhancement on, even when `enhancePrompt` is `false`. |
| `webhook` | string | No | - | A URL to receive a POST notification when the job completes. |

## Common Edits

| Goal | Prompt pattern | References |
| - | - | - |
| Replace an object | "Replace the \[object] with \[new object], keep everything else unchanged" | 1 |
| Change the background | "Keep the person exactly as they are and place them in \[new setting]" | 1 |
| Restyle | "Render the first image as a watercolor illustration" | 1 |
| Add an element from another image | "Put the \[item] from the second image on the table in the first image" | 2 |
| Product variations | "Show the product from the first image on a marble counter with morning light" | 1 |

## Tips for Editing

* **Say what stays.** Models change more than you ask unless told otherwise. "Keep the background, lighting, and framing unchanged" is worth the words.
* **Refer to images by position.** "The first image", "the second image" maps to the order of `referenceImageUrls`.
* **Match the aspect ratio.** On models that honor `aspectRatio` for edits, send the source image's ratio unless you want a crop or extension.
* **Chain edits.** The edited image's URL can be the reference for the next edit, so complex changes can be done in small, controllable steps.

## Next Steps

* [Generate Image from Reference](/guides/ai-studio/image-from-reference) for creative generation guided by references
* [Generate Video from First Frame](/guides/ai-studio/video-from-first-frame) to animate the edited image
* [Generate Image API Reference](/api-reference/ai-studio/generate-image) for the complete parameter documentation


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