Multi-turn Editing and Targeted Retouching
On this page
Updated November 3, 2026. Based on the Image Editing page, the Image Prompting Guide, and the xAI Images API reference: the
/v1/images/editsendpoint has nomaskparameter—neither in the reference nor in thexai-sdk1.21.0—contrary to what the previous version claimed. Retouching is targeted via the prompt, and a zone is protected pixel-perfect by a mask applied locally, after editing. Sources: Image Editing · Image Prompting Guide · Images API.
Chaining Edits
Image editing becomes truly powerful when you chain multiple modifications. The principle, described by xAI, is simple: the output of one edit becomes the input of the next, allowing you to start from a base image then add details, adjust the style, or correct, turn after turn.
import requests
import os
headers = {
"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}",
"Content-Type": "application/json"
}
def edit_image(image_url, prompt):
"""Edits an image and returns the result URL."""
response = requests.post(
"https://api.x.ai/v1/images/edits",
headers=headers,
json={
"model": "grok-imagine-image",
"prompt": prompt,
"image": {"url": image_url}
}
)
response.raise_for_status()
return response.json()["data"][0]["url"]
# Turn 1: modify the background
url_tour1 = edit_image(
"https://exemple.com/portrait.jpg",
"Replace the background with a modern office overlooking the city. "
"Keep the same person, pose, and framing."
)
# Turn 2: adjust the lighting
url_tour2 = edit_image(
url_tour1,
"Make the light warm and dim, like late afternoon. "
"Keep the same person, decor, and framing."
)
# Turn 3: add an element
url_tour3 = edit_image(
url_tour2,
"Place an open laptop on the desk, in front of the person. "
"Keep the same person, lighting, and framing."
)
print(f"Final result: {url_tour3}")
Best Practices for Multi-turn Editing
The xAI guide advises editing when the subject and layout are already good and only one to three details need changing; if the subject itself is wrong, it is better to regenerate. Each turn starts with the modification, then states in one sentence what does not move: the subject, the angle, the framing, the object placement. Two formulations fail according to the guide: one opening with “keep everything,” which changes almost nothing, and one copying a full prompt, which recomposes the scene—the subject drifts, an object doubles, or it changes into a neighboring object.
Order turns from general to specific: background, composition, and ambiance first, accessories and fine corrections next, so a late major change does not undo the small retouches.
Two safety precautions complete the method. Download each intermediate result as soon as it is produced: URLs are temporary, and losing turn 3 of a series of five forces you to restart from turn 2. And inspect each step before chaining: a defect introduced at turn 1—a distorted finger, an inconsistent shadow—ends up in all subsequent turns, since each starts from the previous image.
Targeting a Zone via the Prompt
The API takes no mask: the prompt targets. Designate the part to modify as precisely as possible—by name, position, material—and name what must remain identical.
url_chapeau = edit_image(
url_tour3,
"Replace the person's cap with a wide-brimmed straw hat. "
"Keep the same face, hairstyle, decor, and framing."
)
When a correction does not take, the guide recommends changing words rather than repeating the same request, designating the part of the image to correct and what it should show. To assemble multiple images—a product in a decor, a character from one image to another—editing accepts up to five source images (lesson 7).
Protecting a Zone Pixel-perfect: The Local Mask
If a part of the image must not move a pixel—a logo, a face, text—apply the mask locally, after editing: you keep the original zone and take from the edit only what lies outside this zone. With Pillow, Image.composite(image1, image2, mask) copies image1 where the mask is white and keeps image2 where it is black:
from PIL import Image, ImageDraw
original = Image.open("original.jpg").convert("RGB")
edite = Image.open("edite.jpg").convert("RGB").resize(original.size)
# Mask: white = take edit, black = keep original
masque = Image.new("L", original.size, 255)
draw = ImageDraw.Draw(masque)
draw.rectangle([40, 40, 360, 160], fill=0) # protected zone, e.g., a logo
resultat = Image.composite(edite, original, masque)
resultat.save("resultat.jpg")
The three images must have the same size. Resizing assumes the edit kept the source aspect ratio: verify it, or enforce it with the request’s aspect_ratio parameter. The mask does not prevent the model from touching the zone; it allows you to restore it afterward.
Complete Editing Pipeline
Here is an example of a structured pipeline, keeping the history of each turn:
class ImageEditor:
def __init__(self, api_key):
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
self.history = []
def edit(self, image_url, prompt):
response = requests.post(
"https://api.x.ai/v1/images/edits",
headers=self.headers,
json={
"model": "grok-imagine-image",
"prompt": prompt,
"image": {"url": image_url}
}
)
response.raise_for_status()
result_url = response.json()["data"][0]["url"]
self.history.append({
"prompt": prompt,
"input": image_url,
"output": result_url
})
return result_url
Key Takeaways
- Multi-turn editing chains results: each output becomes the input of the next edit
- Edit when the subject and layout are good and only one to three details need changing
- Each turn: modification first, then what must remain identical
- The API has no
maskparameter: target via the prompt, and protect a zone with a local mask applied after editing - Output URLs are temporary: download intermediate results