GPT-6 Sol y Claude Opus 5.5 ya disponiblesGPT-6 Sol por la mitad del precio de 5.6 Sol

API de GPT Image 2.5: generar y editar imágenes con Python

Una petición POST crea la tarea y una GET lee el resultado. Aquí están el código de la petición, los tamaños que probamos el 29 de octubre de 2026 y una edición con su antes y después.

Kiki, OmniaKey COO7 min de lectura
En esta página

Envía un POST a https://api.omniakey.com/v1/media/tasks con el modelo gpt-image-2.5-flare, consulta el id de tarea que devuelve y descarga assets[0].url cuando el estado sea succeeded. El 29 de octubre de 2026 generamos en 1K, 2K y 1536x1024, editamos una foto de una cafetería y abrimos todos los archivos para leer el tamaño real en píxeles: 1024×1024, 2048×2048, 1536×1024 y 1024×682. La generación en 1K tardó 29.5 s y la de 2K, 45.2 s.

Qué id de modelo 2.5 usar

Usa gpt-image-2.5-flare. Es el id con el que llamamos en todas las ejecuciones de abajo. La página del modelo GPT-Image 2.5 Flare (revisada el 29 de octubre de 2026) indica que el proveedor es OpenAI, incluye texto a imagen y edición de imágenes, y lleva la nota «Guide updated 2026-10-27». Esa misma página da un segundo id 2.5, gpt-image-2.5-sunburst.

Flare hace los dos trabajos. Generar envía un prompt; editar envía un prompt y una imagen de origen. La calidad admite low, medium o high, y la misma página dice que el nivel no cambia el precio. Todas las ejecuciones de aquí usaron medium. No probamos sunburst, ni la calidad low o high, ni 4K o 3840x2160, ni máscaras, ni varias imágenes de referencia, así que planifica con Flare en medium y una sola imagen de origen hasta que pruebes el resto.

El código de la petición

El script de abajo es el que ejecutamos, sin cambios: dos funciones auxiliares y luego una llamada de generación y otra de edición. Usa solo la biblioteca estándar de Python, lee tu clave de OMNIAKEY_API_KEY y escribe cada PNG en la carpeta desde la que lo ejecutes.

python
import base64
import json
import os
import time
import urllib.request
import uuid

API = "https://api.omniakey.com/v1/media/tasks"
KEY = os.environ["OMNIAKEY_API_KEY"]
MODEL = "gpt-image-2.5-flare"

def request(method, url, body=None, extra_headers=None):
    headers = {"Authorization": f"Bearer {KEY}", "User-Agent": "omniakey-example/1"}
    data = None
    if body is not None:
        headers["Content-Type"] = "application/json"
        data = json.dumps(body).encode()
    headers.update(extra_headers or {})
    req = urllib.request.Request(url, data=data, headers=headers, method=method)
    with urllib.request.urlopen(req, timeout=120) as resp:
        return json.load(resp)

def run_task(body, out_path):
    task = request("POST", API, body, {"Idempotency-Key": str(uuid.uuid4())})["id"]
    for _ in range(150):
        time.sleep(4)
        state = request("GET", f"{API}/{task}")
        if state["status"] not in ("queued", "processing"):
            break
    if state["status"] != "succeeded":
        raise RuntimeError(state.get("error") or state["status"])
    asset_url = state["assets"][0]["url"]  # enlace firmado: dura una hora, descárgalo ya
    req = urllib.request.Request(asset_url, headers={"User-Agent": "omniakey-example/1"})
    with urllib.request.urlopen(req, timeout=120) as resp, open(out_path, "wb") as f:
        f.write(resp.read())
    return task

def generate_image(prompt, out_path, size="1K", quality="medium"):
    body = {
        "model": MODEL,
        "type": "image",
        "operation": "generate",
        "input": {"prompt": prompt},
        "parameters": {"size": size, "quality": quality},
    }
    return run_task(body, out_path)

def edit_image(source_path, prompt, out_path, size="1K", quality="medium"):
    with open(source_path, "rb") as f:
        image = base64.b64encode(f.read()).decode()
    body = {
        "model": MODEL,
        "type": "image",
        "operation": "edit",
        "input": {"prompt": prompt, "image": {"data": image, "mime_type": "image/jpeg"}},
        "parameters": {"size": size, "quality": quality},
    }
    return run_task(body, out_path)

if __name__ == "__main__":
    task = generate_image(
        "A small glass greenhouse on a hillside at sunrise, morning fog in the valley, "
        "soft watercolor style, a wooden bench outside the door, no people, no text.",
        "greenhouse.png",
    )
    print("generate task", task)
    task = edit_image(
        "cafe-base.jpg",
        "Change the red bicycle to matte black. Keep everything else exactly the same: "
        "the table, the cup, the window frame and the daylight. Photorealistic, no text, no logos.",
        "cafe-edited.png",
    )
    print("edit task", task)

Authorization: Bearer <key> va en cada llamada, y la llamada de creación necesita además un Idempotency-Key, que el script rellena con un UUID nuevo. El cuerpo fija type en "image", operation en "generate" o "edit", las palabras en input.prompt y el tamaño y la calidad en parameters. La API también acepta n, y solo 1 es válido, así que el script lo omite. Una creación responde con HTTP 202 y un id de tarea, el estado empieza en queued y el bucle espera 4 s entre comprobaciones hasta que sale de los dos estados de trabajo.

Una edición añade el JPEG en input.image como objeto Base64 en línea junto con su tipo MIME. Los cuerpos de petición, Base64 incluido, tienen un límite de 1 MiB, así que el script envía un JPEG de 1024 píxeles de unos 230 KB.

Los tamaños que probamos y lo que volvió

Cuatro ejecuciones, todas con calidad medium, el 29 de octubre de 2026. Tres volvieron con el tamaño pedido. La edición en 1K no lo hizo en una de sus dos ejecuciones.

  • 1K, generar — Píxeles leídos del archivo: 1024×1024; Fecha: 29 de octubre de 2026
  • 2K, generar — Píxeles leídos del archivo: 2048×2048; Fecha: 29 de octubre de 2026
  • 1536x1024, generar — Píxeles leídos del archivo: 1536×1024; Fecha: 29 de octubre de 2026
  • 1K, editar — Píxeles leídos del archivo: 1024×682; Fecha: 29 de octubre de 2026

El invernadero de abajo es una generación en 1K con el mismo cuerpo de petición que el código de arriba.

Invernadero de cristal estilo acuarela en una ladera al amanecer, con niebla en el valle y un banco de madera junto a la puerta.
Generado con GPT-Image 2.5 Flare a través de la API de OmniaKey el 29 de octubre de 2026, tamaño 1K, calidad medium.

Hay dos conclusiones que sacar de la lista. La primera: lee el tamaño en el archivo que descargaste. La edición en 1K pidió un cuadrado y volvió en 1024×682, la forma del JPEG de 1024×683 que enviamos, y otra ejecución de esa misma edición en 1K volvió en 1024×1024. La segunda: la lista de tamaños de la documentación de la API de imágenes (revisada el 29 de octubre de 2026) ofrece auto, 1K, 2K, 4K y 3840x2160 para este modelo, y dice que rechaza los tamaños fuera de la lista antes de cobrar; nuestra llamada de 1536x1024 del 29 de octubre de 2026 no fue rechazada y devolvió 1536×1024. Comprueba el archivo real antes de montar un diseño sobre un solo tamaño.

Una edición conserva la escena y cambia una cosa

Una edición responde a dos preguntas: qué cambia y qué se queda. Pedimos un solo cambio y nombramos lo que tenía que sobrevivir.

Prompt: "Change the red bicycle to matte black. Keep everything else exactly the same: the table, the cup, the window frame and the daylight. Photorealistic, no text, no logos."

Izquierda: una ventana de cafetería con una bicicleta roja fuera. Derecha: la misma ventana tras la edición, con la bicicleta ya oscura.
Izquierda: la foto de origen que enviamos. Derecha: la salida de una edición del 29 de octubre de 2026, tamaño 1K, calidad medium. Solo se pidió cambiar la bicicleta; la mesa, la taza y la planta siguen en su sitio.

La bicicleta volvió oscura, y la mesa, la taza, la planta y el marco de la ventana seguían en el encuadre. El origen era un JPEG de 1024×683, la salida midió 1024×682 y la ejecución tardó 38.0 s. Escribe la lista de lo que se queda cada vez. Para la estructura de prompts en general, consulta la guía de prompts de GPT Image 2.

Errores y límites

Dos cabeceras hacen su trabajo antes de que exista un solo píxel: el token bearer y un Idempotency-Key único. Si los aciertas, el resto de la llamada se reintenta sin complicaciones.

Lo que envíasLo que vuelve
Llamada de creación sin clave400 missing_idempotency_key
Misma clave, mismo cuerpo, dos veces200 con la tarea existente, sin cargo nuevo
Misma clave, cuerpo cambiado409 idempotency_key_reused

La clave puede tener hasta 255 caracteres, según la documentación revisada el 29 de octubre de 2026. Reutilizarla con el mismo cuerpo es el reintento seguro: recibes la tarea existente y no se cobra nada nuevo. Mantén el cuerpo por debajo de 1 MiB, Base64 incluido, así que reduce o comprime el origen antes de enviarlo.

Cuando una tarea tiene éxito, assets[0].url es un enlace firmado que dura alrededor de una hora, según la documentación, así que descarga enseguida o consulta la misma tarea otra vez para obtener un enlace nuevo. Los registros de tarea se conservan 24 horas.

Una cabecera nos sorprendió el 29 de octubre de 2026: un POST enviado con el User-Agent por defecto de urllib de Python devolvió HTTP 403 con el cuerpo "error code: 1010" de Cloudflare. El mismo POST con nuestra propia cabecera User-Agent: omniakey-example/1 llegó a la API, que respondió 400 invalid_request por el cuerpo vacío que enviamos, y no se cobró nada. La documentación solo nombra Authorization e Idempotency-Key, así que define un User-Agent en tu cliente.

¿GPT Image 2.5 o GPT Image 2 para trabajar con la API?

Flare es el id 2.5 que probamos. GPT Image 2 usa el id gpt-image-2, como indica su página del modelo GPT Image 2. Si un script ya produce lo que necesitas con ese id, no hay motivo para cambiarlo.

Para una foto que debe conservar su escena mientras cambia un objeto, Flare en medium es lo que cubren nuestras ejecuciones del 29 de octubre de 2026: tres tamaños generados y la edición de 1024×682. La comparativa de GPT Image 2.5 y GPT Image 2 tiene los tamaños y los resultados del mismo prompt para los dos modelos, así que puedes elegir con los números delante. Las tarifas actuales están en la página de precios.

Preguntas frecuentes

¿Qué id de modelo uso, gpt-image-2.5-flare o gpt-image-2.5-sunburst?

En todas las ejecuciones de arriba usamos Flare, y su edición conservó la escena que pedimos conservar. La página del modelo lista Sunburst como el segundo id 2.5: empieza con Flare y somete Sunburst a tu edición más difícil antes de cambiar.

¿Puedo pedir un tamaño horizontal como 1536x1024?

El 29 de octubre de 2026 una generación en 1536x1024 volvió en 1536×1024. La lista de tamaños de la documentación de la API de imágenes no incluye ese valor para este modelo, así que lee el archivo y revisa la documentación antes de depender de él en producción.

¿Por qué mi edición vuelve en un tamaño distinto del que pedí?

La misma edición en 1K volvió en 1024×682 en una ejecución y en 1024×1024 en otra, así que trata el tamaño que pides como una petición, no como una promesa. Abre el PNG y lee su ancho y su alto antes de colocarlo.

¿Hace falta una cabecera User-Agent?

El 29 de octubre de 2026 una petición con el User-Agent por defecto de Python recibió HTTP 403 con el error 1010 de Cloudflare. La misma petición con nuestra propia cabecera User-Agent llegó a la API, así que envía una.

¿Cuánto duran los enlaces de las imágenes?

La documentación dice que el enlace firmado dura alrededor de una hora. Consulta la tarea de nuevo para obtener un enlace fresco y descarga el archivo en cuanto la tarea termine bien.

Modelos de este artículo

GPT Image 2.5API de imágenesPythonedición de imágenesAPI

Artículos relacionados

Artículos recientes