Para editar una imagen con la API de OpenAI, envía la imagen original y un prompt a POST /v1/images/edits (en los SDK, client.images.edit()) con uno de los dos modelos de GPT Image 2.5: gpt-image-2.5-sunburst cuando la precisión de la edición es lo más importante o gpt-image-2.5-flare cuando prima la rapidez. La respuesta trae la imagen en base64 dentro de data[0].b64_json; tienes que decodificarla antes de escribir el archivo.
Tres detalles deciden si la llamada funciona:
- Archivos locales por multipart. Una imagen va en el campo
image; varias, comoimage[]. Admite hasta 16, en PNG, WebP o JPG y de menos de 50 MB cada una. - La máscara es opcional y orientativa. Un PNG con canal alfa, del mismo tamaño que la primera imagen, en el que la zona transparente marca lo que se puede cambiar. El modelo la usa como guía, no como recorte exacto.
- El código antiguo tiene fecha de caducidad.
dall-e-2y el endpointvariationsya no funcionan desde el 12 de mayo de 2026;gpt-image-1se apaga el 23 de octubre de 2026, ygpt-image-1.5,gpt-image-1-miniychatgpt-image-latest, el 1 de diciembre de 2026, según la página de retiradas de OpenAI.
gpt-image-2 sigue activo y sin fecha de retirada, así que puedes quedarte en él si tu integración ya funciona o si editas en lote con Batch, que los modelos 2.5 no admiten. Los ejemplos de código siguen el uso que documenta OpenAI en su guía de generación de imágenes y en la referencia del endpoint de edición; no son la salida de una llamada ejecutada, así que prueba primero con una imagen de muestra.
Qué modelo usar para editar
| Tu situación | Modelo | Motivo |
|---|---|---|
| Integración nueva; cambios delicados en productos, rostros o texto | gpt-image-2.5-sunburst | OpenAI lo recomienda cuando la precisión de la edición es lo más importante |
| Integración nueva; borradores o ediciones diarias donde importa la velocidad | gpt-image-2.5-flare | Es el modelo rápido de la familia 2.5 y también admite edición |
Ya tienes código estable con gpt-image-2 | gpt-image-2 | No está retirado; migrar es opcional |
| Ediciones masivas por Batch | gpt-image-2 | Los modelos 2.5 no admiten v1/batch |
Código con gpt-image-1, gpt-image-1.5, gpt-image-1-mini o chatgpt-image-latest | Cualquiera de los anteriores | Dejan de funcionar en octubre o diciembre de 2026 (ver la tabla de migración) |
La diferencia entre Sunburst y Flare es una recomendación de uso, no un límite: las páginas de modelo de Sunburst y de Flare indican que los dos admiten v1/images/edits. No existe un modelo llamado gpt-image-2.5 a secas; escribe el ID completo. Si quieres comparar calidad, tiempos y precio de ambas variantes, tienes el detalle en GPT Image 2.5: qué cambia, cuánto cuesta y cómo usar la API.
La página de retiradas propone gpt-image-2 como sustituto de los modelos 1.x, porque se redactó antes de que existiera 2.5, mientras que la guía actual pide GPT Image 2.5 para integraciones nuevas. Las dos opciones son válidas; OpenAI no obliga a pasar a 2.5.
Una edición mínima que termina en un archivo
Antes de añadir máscara o varias referencias, consigue que una edición sencilla produzca un PNG que se abra. Necesitas una clave en OPENAI_API_KEY, una imagen salon.png junto al programa y la organización verificada si la API te lo pide: el error «Your organization must be verified» se resuelve como explica GPT Image 2: cómo resolver el error de organización sin verificar.
En Python (python -m pip install --upgrade openai):
import base64
from pathlib import Path
from openai import OpenAI
client = OpenAI() # lee OPENAI_API_KEY del entorno
with open("salon.png", "rb") as original:
result = client.images.edit(
model="gpt-image-2.5-sunburst",
image=original,
prompt=(
"Fotografía de este mismo salón. Sustituye el cuadro de la pared "
"por una lámina botánica enmarcada. Conserva los muebles, la "
"distribución, la luz y el encuadre de la imagen original."
),
output_format="png",
)
if not result.data or not result.data[0].b64_json:
raise RuntimeError("La respuesta no contiene b64_json")
Path("salon-editado.png").write_bytes(base64.b64decode(result.data[0].b64_json))En Node.js (npm install openai), guarda el código como editar.mjs para poder usar await en el nivel superior y ejecútalo con node editar.mjs:
import fs from "node:fs";
import OpenAI from "openai";
const client = new OpenAI();
const result = await client.images.edit({
model: "gpt-image-2.5-sunburst",
image: fs.createReadStream("salon.png"),
prompt:
"Fotografía de este mismo salón. Sustituye el cuadro de la pared " +
"por una lámina botánica enmarcada. Conserva los muebles, la " +
"distribución, la luz y el encuadre de la imagen original.",
output_format: "png",
});
const encoded = result.data?.[0]?.b64_json;
if (!encoded) throw new Error("La respuesta no contiene b64_json");
fs.writeFileSync("salon-editado.png", Buffer.from(encoded, "base64"));Con cURL la petición es multipart; cURL genera el Content-Type con su delimitador, así que no añadas application/json a mano. La respuesta se guarda como JSON y la imagen se extrae después con jq:
curl --fail-with-body -sS https://api.openai.com/v1/images/edits \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-D cabeceras.txt \
-F "model=gpt-image-2.5-sunburst" \
-F "image[]=@salon.png" \
-F "prompt=Sustituye el cuadro por una lámina botánica enmarcada. Conserva el resto del salón." \
-F "output_format=png" \
-o respuesta.json
jq -r '.data[0].b64_json' respuesta.json | base64 --decode > salon-editado.png
grep -i x-request-id cabeceras.txtLa edición está completa cuando salon-editado.png se abre como imagen y conserva lo que pediste. Una respuesta HTTP 200 no basta, y guardar el texto base64 con extensión .png tampoco produce un PNG. Si pides varias imágenes con n, recorre todos los elementos de data; los ejemplos solo guardan el primero. Una edición compleja puede tardar hasta dos minutos según la guía de OpenAI, así que no configures un tiempo de espera del cliente más corto que eso.
En estos ejemplos faltan, a propósito, dos parámetros habituales en código antiguo. response_format no se admite con los modelos GPT Image: siempre devuelven b64_json y nunca una url. input_fidelity se omite porque gpt-image-2 procesa las imágenes de entrada con alta fidelidad y la referencia indica que ignora ese parámetro; para Sunburst y Flare, la documentación no dice si lo aceptan, así que es mejor no enviarlo.
Combinar varias imágenes de referencia
Con varias imágenes, pon primero la escena base y después las que aportan objetos, texturas o estilo. En multipart se repite el campo image[] una vez por archivo; en Python se pasa una lista:
with open("salon.png", "rb") as escena, open("lamina.png", "rb") as lamina:
result = client.images.edit(
model="gpt-image-2.5-sunburst",
image=[escena, lamina],
prompt=(
"Usa la primera imagen como escena base. Coloca la lámina de la "
"segunda imagen dentro del marco de la pared, con la misma "
"perspectiva. No cambies los muebles ni la luz."
),
)El orden importa: si después añades una máscara, se aplica a la primera imagen. Di en el prompt qué aporta cada archivo; el modelo no sabe por sí solo cuál es la escena y cuál el detalle que debe copiar. Los límites de la referencia de edición son los mismos que para una sola imagen: hasta 16 archivos PNG, WebP o JPG de menos de 50 MB cada uno.
Cuerpo JSON en lugar de multipart
La referencia también acepta un cuerpo JSON. En ese caso el campo se llama images y es una lista de objetos, cada uno con image_url (una URL completa o una data URL en base64) o con file_id (un archivo subido antes con la API de archivos, Files API):
curl --fail-with-body -sS https://api.openai.com/v1/images/edits \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2.5-flare",
"images": [
{ "image_url": "https://ejemplo.com/salon.png" },
{ "file_id": "file-ID_DE_TU_ARCHIVO" }
],
"prompt": "Coloca la lámina de la segunda imagen en el marco de la primera."
}' \
-o respuesta.jsonUna ruta local como "salon.png" dentro del JSON no sube el archivo: la API solo acepta URL, data URL o file_id. Para archivos que están en tu disco, multipart sigue siendo la forma directa. La documentación tampoco garantiza que todas las versiones de los SDK expongan esta forma JSON; si la necesitas desde un SDK, comprueba la firma del método en la versión que tienes instalada.
Editar solo una zona con máscara (mask)

Una máscara indica qué parte de la imagen puede cambiar. La guía de OpenAI y la referencia no dan exactamente los mismos requisitos (la guía habla de 50 MB y la referencia exige menos de 4 MB para la máscara), así que lo más seguro es cumplir ambos:
| Requisito | Valor seguro |
|---|---|
| Formato | PNG con canal alfa |
| Zona editable | Píxeles totalmente transparentes (alfa cero) |
| Dimensiones | Idénticas a las de la primera imagen, en píxeles |
| Peso | Menos de 4 MB |
| Con varias imágenes | Se aplica solo a la primera |
Si tu máscara es en blanco y negro, sin transparencia, la guía de OpenAI la convierte así con Pillow. El propio gris se usa como alfa: lo negro queda transparente y editable, y lo blanco, opaco y protegido.
from PIL import Image
mascara = Image.open("mascara-bn.png").convert("L")
mascara_rgba = mascara.convert("RGBA")
mascara_rgba.putalpha(mascara)
mascara_rgba.save("mascara.png")
original = Image.open("salon.png")
assert original.size == mascara_rgba.size, "La máscara debe medir lo mismo que la imagen"Después basta con añadir mask a la llamada. Describe en el prompt la imagen final completa, no solo lo que va dentro de la zona transparente:
with open("salon.png", "rb") as original, open("mascara.png", "rb") as mask:
result = client.images.edit(
model="gpt-image-2.5-sunburst",
image=original,
mask=mask,
prompt=(
"Salón luminoso con un sofá beige, una mesa baja de madera y una "
"lámina botánica enmarcada en la pared. Mantén el sofá, la mesa, "
"las plantas, la luz y el encuadre de la foto original."
),
)En cURL, la máscara es un campo más: -F "mask=@mascara.png", junto a -F "image[]=@salon.png".
La máscara no garantiza que todo lo de fuera quede idéntico. Según la guía, la edición con máscara en GPT Image «se basa por completo en el prompt» y el modelo puede no seguir la forma exacta. Compara el resultado con el original, sobre todo en rostros, logotipos, texto y geometría de producto. Si tu aplicación necesita que el exterior de la selección no cambie ni un píxel, tendrás que componer tú el resultado sobre el original y comprobarlo; añadir mask no basta.
Parámetros de edición que conviene revisar
| Parámetro | Valores | Lo que debes saber |
|---|---|---|
prompt | 1–32.000 caracteres | Describe el resultado final y lo que debe conservarse |
quality | low, medium, high; xhigh y max solo en 2.5; auto por defecto | low sirve para borradores rápidos |
size | 1024x1024, 1536x1024, 1024x1536 o personalizado | En gpt-image-2 y 2.5: lados múltiplos de 16, proporción entre 1:3 y 3:1, hasta 3840x2160; por encima de 2560x1440 es experimental |
output_format | png (por defecto), jpeg, webp | Usa la misma extensión al guardar; jpeg es más rápido |
output_compression | 0–100 | Solo con jpeg o webp |
background | transparent, opaque, auto | Transparente admitido en 2.5 y en versión preliminar en gpt-image-2; requiere png o webp |
n | 1–10 | Número de imágenes devueltas; no controla cuánto cambia la original |
input_fidelity | — | No lo envíes |
response_format | — | No se admite con GPT Image |
Si editas una imagen con fondo transparente, repite en cada prompt que la transparencia debe mantenerse; de lo contrario, una edición posterior puede añadir un fondo nuevo. Cómo pedir y comprobar un PNG o WebP con alfa real está en Fondo transparente con GPT Image 2 y 2.5: modelo, código y fallos.
Revisiones sucesivas y cuándo pasar a Responses
El endpoint de edición no recuerda llamadas anteriores. Para retocar un resultado, vuelve a enviar como imagen la última versión que hayas aceptado, no cualquier resultado recién generado, y pide un solo cambio: «Conserva esta versión y reduce el reflejo del cristal del cuadro». Guarda el original y cada versión aceptada con nombres distintos; si una edición deforma el sofá o la perspectiva, vuelves a la anterior sin arrastrar el error.
La guía de OpenAI reserva la Images API para generar o editar una imagen a partir de un prompt, y la Responses API para experiencias conversacionales en las que el usuario pide cambios sobre lo anterior. Si tu producto es un chat de edición, en Responses:
- el
modelde nivel superior es un modelo de texto compatible, nunca un modelo de imagen; - la edición la hace la herramienta
image_generation, a la que indicas el modelo de imagen, por ejemplo{"type": "image_generation", "model": "gpt-image-2.5-sunburst"}; - la máscara se pasa como
input_image_maskcon unfile_id; - los turnos siguientes se enlazan con
previous_response_id.
Para una aplicación que recibe una imagen, hace un cambio y devuelve un archivo, la Images API es suficiente.
Migrar desde variations, dall-e-2 y gpt-image-1
| Si tu código usa… | Estado según OpenAI | Qué cambiar |
|---|---|---|
dall-e-2 o dall-e-3 | Retirados el 12 de mayo de 2026 | Pasa a gpt-image-2.5-sunburst, -flare o gpt-image-2; quita response_format y la lectura de url |
/v1/images/variations (create_variation en Python, createVariation en Node) | Solo admite dall-e-2, que ya no existe | Usa /v1/images/edits con la imagen de origen y un prompt explícito |
gpt-image-1 | Se apaga el 23 de octubre de 2026 | Cambia el modelo; quita input_fidelity si lo envías |
gpt-image-1.5, gpt-image-1-mini, chatgpt-image-latest | Se apagan el 1 de diciembre de 2026 | Cambia el modelo; quita input_fidelity si lo envías; xhigh y max solo existen en 2.5 |
gpt-image-2 | Sin fecha de retirada | Nada obligatorio; 2.5 para funciones nuevas si no dependes de Batch |
Fuentes: página de retiradas y referencia de variations. La página del modelo DALL·E 2 recomienda hoy GPT-Image-2.5 Sunburst para generar y editar.
Con variations, actualizar el SDK o cambiar solo model no sirve: la llamada sigue llegando a un endpoint que solo aceptaba DALL·E 2. Hay que cambiar de método y de ruta. Además, variations funcionaba sin prompt, y ese comportamiento no tiene un equivalente exacto; en edits debes decir qué puede cambiar y qué se conserva. «Crea otra versión» deja demasiado abierto; «mantén los muebles y el encuadre, cambia la luz a la de una tarde cálida y no añadas objetos» define la alternativa.
Si llegas con código de gpt-image-1.5 y máscara, la máscara, los campos image e image[] y la lectura de b64_json no cambian; basta con cambiar el ID del modelo y quitar input_fidelity. Aun así, revisa con unas cuantas imágenes que el resultado sigue siendo aceptable, porque el modelo que interpreta la máscara es otro.
Cuando la edición falla: dónde mirar

Antes de retocar el prompt, averigua en qué capa está el fallo. Cambia una sola cosa cada vez:
| Lo que observas | Dónde está el problema | Qué comprobar primero |
|---|---|---|
Error sobre model, modelo no encontrado o un modelo retirado | Ruta y modelo | ID completo (no gpt-image-2.5), URL real incluida la base_url de tu cliente, y que no sigues llamando a variations |
Error sobre image o mask | Archivos | Formato, peso, número de imágenes; máscara PNG con alfa, del tamaño exacto de la primera imagen y de menos de 4 MB |
| HTTP 200 pero no hay archivo válido | Respuesta | Que existe data[0].b64_json y que lo decodificas antes de guardar |
| El archivo se abre, pero cambia demasiado | Resultado visual | Prompt que describa la escena completa, orden de las referencias, máscara y comparación con el original |
Para los errores de la API, la guía de OpenAI pide mirar el estado HTTP o la excepción del SDK y guardar el identificador de la petición (la cabecera x-request-id). Reintenta con espera creciente solo los errores transitorios: límite de peticiones (429) y fallos del servidor (5xx). Según sus páginas de modelo, en el nivel 1 de uso Sunburst y Flare admiten 5 imágenes por minuto, así que un 429 temprano puede ser simplemente ese límite. No reintentes automáticamente los errores de cuota ni los que traen error.type = "image_generation_user_error": ahí hay que cambiar el prompt o las imágenes, y error.code indica el motivo. Si el código es moderation_blocked, el campo opcional moderation_details dice si el bloqueo vino de la entrada o de la imagen generada.
Si ves Value must be 'dall-e-2', el mensaje corresponde a un fallo ya corregido. En el issue #1844 de openai-node, abierto en abril de 2026, el endpoint de edición rechazaba gpt-image-2 con ese mensaje tanto desde el SDK como con cURL. OpenAI lo corrigió en el servicio y el issue se cerró el 13 de agosto de 2026. Si hoy te aparece contra api.openai.com, revisa primero si tu código sigue llamando a variations; si pasas por un intermediario, puede que su validación no se haya actualizado. Cambiar de SDK o de modelo a ciegas no lo aclara.
Si usas un servicio compatible con la API de OpenAI en lugar de la conexión directa, la ruta y la clave son las de ese servicio. Por ejemplo, según su documentación de GPT Image 2.5, laozhang.ai usa la misma ruta /v1/images/edits con la base URL https://api.laozhang.ai/v1; sus modelos de pago por petición (los que acaban en -vip) no admiten mask, mientras que gpt-image-2.5-flare y gpt-image-2.5-sunburst se facturan por tokens a la tarifa de OpenAI o con un 20 % más, según el grupo de la clave. Ningún intermediario es necesario para editar desde España: la API de OpenAI está disponible allí directamente, según su lista de países admitidos. Compara siempre las peticiones contra el mismo proveedor y no reutilices una clave en otro servicio.
Preguntas frecuentes
¿Puedo editar con Flare o solo con Sunburst?
Con los dos. Ambos admiten /v1/images/edits. OpenAI recomienda Sunburst cuando la precisión de la edición es lo más importante, pero es una orientación de uso, no una restricción. Si dudas, prueba la misma edición con los dos sobre tus propias imágenes.
¿Puedo recibir una URL en lugar de base64?
No con los modelos GPT Image: url no se admite y response_format tampoco. Si tu aplicación necesita un enlace, decodifica b64_json, sube el archivo a tu propio almacenamiento y sirve esa URL.
¿Cuánto cuesta una edición?
Sunburst, Flare y gpt-image-2 tienen la misma tarifa estándar por tokens (8 $ por millón de tokens de imagen de entrada y 30 $ por millón de tokens de imagen de salida), según los precios de OpenAI. Una edición paga además los tokens de las imágenes que envías, así que el total depende también de cuántas referencias incluyes. Revisa el campo usage de la respuesta para ver el consumo real; el cálculo por calidad y tamaño está en Precio por imagen de la API de OpenAI: GPT Image 2.5 y GPT Image 2.
¿Hay forma de editar fotos con ChatGPT sin programar?
Sí, pero no a través de la API. La aplicación de ChatGPT edita fotos desde el chat, y si trabajas en Codex puedes seguir Cómo generar y editar imágenes con GPT Image 2 en Codex.



