# Editar imágenes con la API de OpenAI: modelo, máscara y migración

> Edita con /v1/images/edits y GPT Image 2.5 (Sunburst o Flare), decodifica b64_json antes de guardar y migra gpt-image-1 antes del 23 de octubre de 2026.

- Source: https://www.aifreeapi.com/es/posts/openai-image-editing-api
- Language: es
- Published: 2026-03-23
- Updated: 2026-09-25
- Publisher: AI Free API (https://www.aifreeapi.com)

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, como `image[]`. 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-2` y el endpoint `variations` ya no funcionan desde el 12 de mayo de 2026; `gpt-image-1` se apaga el 23 de octubre de 2026, y `gpt-image-1.5`, `gpt-image-1-mini` y `chatgpt-image-latest`, el 1 de diciembre de 2026, según la [página de retiradas de OpenAI](https://developers.openai.com/api/docs/deprecations).

`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](https://developers.openai.com/api/docs/guides/image-generation) y en la [referencia del endpoint de edición](https://developers.openai.com/api/reference/resources/images/methods/edit); 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](#migrar-desde-variations-dall-e-2-y-gpt-image-1)) |

La diferencia entre Sunburst y Flare es una recomendación de uso, no un límite: las [páginas de modelo de Sunburst](https://developers.openai.com/api/docs/models/gpt-image-2.5-sunburst) y [de Flare](https://developers.openai.com/api/docs/models/gpt-image-2.5-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](/es/posts/gpt-image-2-5).

La [página de retiradas](https://developers.openai.com/api/docs/deprecations) 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](/es/posts/openai-image-generation-api-verification).

En Python (`python -m pip install --upgrade openai`):

```python
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`:

```javascript
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`:

```bash
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.txt
```

La 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:

```python
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](https://developers.openai.com/api/reference/resources/images/methods/edit) 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):

```bash
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.json
```

Una 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)

![Tres paneles de un salón: la foto original, la zona del cuadro marcada como transparente en la máscara y un resultado ilustrativo con una lámina botánica](https://www.aifreeapi.com/posts/es/openai-image-editing-api/img/mascara-salon.webp)

Una máscara indica qué parte de la imagen puede cambiar. La [guía de OpenAI](https://developers.openai.com/api/docs/guides/image-generation#edit-an-image-using-a-mask) 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.

```python
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:

```python
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](/es/posts/gpt-image-2-transparent-background).

## 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](https://developers.openai.com/api/docs/guides/image-generation) 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 `model` de 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_mask` con un `file_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](https://developers.openai.com/api/docs/deprecations) y [referencia de variations](https://developers.openai.com/api/reference/resources/images/methods/create_variation). La página del modelo [DALL·E 2](https://developers.openai.com/api/docs/models/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

![Infografía de cuatro etapas para localizar un fallo de edición: modelo y destino, imagen y máscara, respuesta y bytes, y resultado visual](https://www.aifreeapi.com/posts/es/openai-image-editing-api/img/diagnostico-edicion.webp)

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](https://developers.openai.com/api/docs/guides/image-generation#handling-blocked-requests-and-other-errors) 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](https://github.com/openai/openai-node/issues/1844), 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](https://docs.laozhang.ai/api-capabilities/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](https://developers.openai.com/api/docs/supported-countries). 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](https://developers.openai.com/api/docs/pricing). 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](/es/posts/openai-image-generation-api-pricing).

### ¿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](/es/posts/gpt-image-2-codex).
