HiAPI
Blog

Tutorial

Cómo usar seedream-5.0-lite imagen a imagen a través de la API de hiapi

Jul 7, 2026
Cómo usar seedream-5.0-lite imagen a imagen a través de la API de hiapi

Este tutorial te mostrará cómo llamar al modo imagen a imagen de seedream-5.0-lite a través de la API unificada de tareas de hiapi: la estructura exacta de la solicitud, un comando curl que puedes ejecutar directamente, un script de Python que puedes integrar en tu backend, y las trampas de validación que este modelo impone y que otros modelos no.

Al terminar de leer este artículo, tendrás un script que recibe una o varias URL de imágenes de referencia y un prompt de edición, y devuelve una URL de imagen generada lista para descargar.

Qué necesitas preparar

  • Una cuenta de hiapi y una API key. Puedes obtenerla en la consola de hiapi.
  • Una o varias imágenes de referencia alojadas en URL HTTPS públicas. Este modelo acepta hasta 14 imágenes de referencia por solicitud, y esa es precisamente la razón por la que resulta útil para flujos de trabajo con múltiples referencias: fusionar el sujeto de una imagen con el estilo o la escena de otra.
  • Un prompt de texto que describa la edición o transformación (mínimo 3 caracteres; sí, la API lo valida).

Todas las solicitudes se envían al endpoint unificado de tareas, con la clave en el encabezado Authorization:

POST https://api.hiapi.ai/v1/tasks
Authorization: Bearer sk-<your-key>
Content-Type: application/json

Estructura de la solicitud (y los requisitos de este modelo)

El id del modelo es seedream-5.0-lite/image-to-image; pásalo tal cual, exactamente como aparece en /v1/models. Su schema de input es estricto: los cuatro campos son obligatorios:

Campo Tipo Descripción
prompt string Instrucción de edición. Longitud mínima 3.
image_urls string[] De 1 a 14 URL de imágenes de referencia.
aspect_ratio string Uno de los valores 1:1, 4:3, 3:4, 16:9, 9:16, 2:3, 3:2, 21:9.
resolution string Solo puede ser 2K o 4K. Este modelo no tiene nivel 1K.

Quienes migran desde otros modelos de la plataforma suelen tropezar con dos trampas:

  1. resolution solo acepta 2K o 4K. Si tu código de envío de tareas compartido pone "1K" por defecto (lo que funciona en muchos otros modelos de imagen), este modelo lo rechazará con un 400.
  2. Los campos sobrantes se rechazan en lugar de ignorarse. Enviar size, n o cualquier cosa fuera del schema devuelve 400 INVALID_REQUEST con additional properties '<field>' not allowed. La API de tareas valida el input según el modelo; no reutilices a ciegas el payload de otro modelo.

Ejemplo mínimo funcional: curl

Crear la tarea:

curl -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<your-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedream-5.0-lite/image-to-image",
    "input": {
      "prompt": "Replace the background with a sunlit Tokyo street at golden hour, keep the subject unchanged",
      "image_urls": ["https://your-cdn.example.com/subject.png"],
      "aspect_ratio": "3:2",
      "resolution": "2K"
    }
  }'

Si el envío es exitoso, devuelve un id de tarea en data:

{"code": 200, "data": {"taskId": "task_abc123..."}}

Consultar el resultado:

curl https://api.hiapi.ai/v1/tasks/task_abc123 \
  -H "Authorization: Bearer sk-<your-key>"

Mientras se ejecuta, data.status es pending/processing. Al terminar pasa a "success" y la imagen aparece en data.output:

{
  "code": 200,
  "data": {
    "status": "success",
    "output": [{"url": "https://.../result.png", "expireAt": "..."}]
  }
}

La URL de salida tiene validez temporal (fíjate en expireAt). Descarga los bytes de inmediato y almacénalos por tu cuenta; no hagas hotlinking ni persistas la URL original.

Múltiples imágenes de referencia: pasar varias imágenes

Para fusionar varias imágenes de referencia —por ejemplo, una imagen de producto más una imagen de referencia de estilo—, basta con añadir más URL a image_urls e indicar en el prompt qué aporta cada imagen:

{
  "model": "seedream-5.0-lite/image-to-image",
  "input": {
    "prompt": "Place the product from the first image into the scene from the second image, matching its lighting and color grade",
    "image_urls": [
      "https://your-cdn.example.com/product.png",
      "https://your-cdn.example.com/scene-reference.jpg"
    ],
    "aspect_ratio": "1:1",
    "resolution": "2K"
  }
}

El límite máximo es de 14 URL; la 15.ª devuelve 400 INVALID_REQUEST: image_urls: maxItems: got 15, want 14. En la práctica, 2–4 imágenes de referencia bien elegidas, con un prompt que asigne explícitamente un rol a cada una («conserva el sujeto de la imagen 1, adopta la paleta de la imagen 2»), producen ediciones mucho más controladas que un montón de imágenes poco relacionadas.

Para ediciones precisas y localizadas sobre una sola imagen —cambiar el fondo, modificar la ropa, eliminar un objeto—, usa una sola URL de referencia e indica tanto qué cambiar como qué conservar («mantén el rostro y la postura sin cambios»). Los modelos Seedream siguen bien las instrucciones de conservación, y ser explícito es justo la clave que distingue una edición precisa de una reinterpretación completa.

Python listo para producción: enviar, consultar, descargar

import time
import requests

API_BASE = "https://api.hiapi.ai/v1/tasks"
API_KEY = "sk-<your-key>"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}


def edit_image(prompt: str, image_urls: list[str],
               aspect_ratio: str = "1:1", resolution: str = "2K") -> bytes:
    # 1. Create the task
    resp = requests.post(API_BASE, headers=HEADERS, json={
        "model": "seedream-5.0-lite/image-to-image",
        "input": {
            "prompt": prompt,
            "image_urls": image_urls,
            "aspect_ratio": aspect_ratio,
            "resolution": resolution,  # this model: "2K" or "4K" only
        },
    }, timeout=60)
    body = resp.json()
    if resp.status_code != 200 or not (body.get("data") or {}).get("taskId"):
        raise RuntimeError(f"create failed [{resp.status_code}]: {body}")
    task_id = body["data"]["taskId"]

    # 2. Poll until terminal state
    deadline = time.time() + 600
    while time.time() < deadline:
        task = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS,
                            timeout=30).json().get("data") or {}
        if task.get("status") == "success":
            outputs = task.get("output") or []
            if not outputs or not outputs[0].get("url"):
                raise RuntimeError(f"task {task_id} succeeded but returned no output URL")
            # 3. Download immediately — the URL expires
            img = requests.get(outputs[0]["url"], timeout=120)
            img.raise_for_status()
            return img.content
        if task.get("status") == "fail":
            err = task.get("error") or {}
            raise RuntimeError(f"task failed: {err.get('code')} {err.get('message')}")
        time.sleep(5)
    raise TimeoutError(f"task {task_id} still running after 600s")


if __name__ == "__main__":
    png = edit_image(
        "Replace the background with a minimalist studio backdrop, keep the subject unchanged",
        ["https://your-cdn.example.com/subject.png"],
        aspect_ratio="3:2",
    )
    with open("edited.png", "wb") as f:
        f.write(png)
    print(f"saved edited.png ({len(png)} bytes)")

Usar callbacks en lugar de polling

El polling va bien para scripts y colas de workers. Para un backend web, registra un callback al crear la tarea y deja que hiapi te envíe el estado final: el objeto callback va en el nivel superior de la solicitud, junto a model:

{
  "model": "seedream-5.0-lite/image-to-image",
  "input": { "...": "..." },
  "callback": {
    "url": "https://your-app.example.com/hooks/hiapi",
    "when": "final"
  }
}

Con "when": "final", solo recibirás un POST cuando la tarea entre en success o fail. Dos reglas para el handler:

  • Hazlo idempotente. Usa el id de tarea como clave de procesamiento para que las entregas duplicadas del webhook no provoquen un procesamiento doble. Guarda el id de tarea en el momento del envío y trata el callback como una notificación de «ve a buscarlo y termina», no como la única fuente de verdad.
  • Mantén una vía de reconciliación. Si tu endpoint está caído cuando se dispara el callback, un escaneo periódico de los ids pendientes con GET /v1/tasks/<id> capturará lo que se haya perdido.

Si tu callback parece no llegar nunca, revisa uno por uno los modos de fallo habituales, en orden de probabilidad, en por qué no se dispara tu callback de tareas de hiapi.

Gestión de errores: los tres fallos que de verdad importan

401 permission_denied al crear: tu clave no puede usar ese modelo. El cuerpo de la respuesta tiene esta forma:

{"error": {"code": "permission_denied", "message": "This API key cannot use the selected model...", "type": "hiapi_error"}}

Revisa los permisos de modelos de la clave en la consola, o usa una clave con modelos de imagen habilitados.

400 INVALID_REQUEST al crear: tu input no coincide con el schema de este modelo. El mensaje enumera todos los campos infractores de una vez (por ejemplo, resolution: value must be one of '2K', '4K'; <root>: additional properties 'size' not allowed), así que léelo completo y corrige todos los campos de una vez. Son errores permanentes: reintentar con el mismo payload fallará siempre.

status: "fail" en la tarea: la creación tuvo éxito pero la generación falló (URL de referencia inaccesible para el backend, política de contenido, capacidad del proveedor). error.code y error.message de la tarea indican el motivo. A diferencia del 400, algunos de estos son transitorios y merece la pena reintentar una vez con backoff.

También conviene saber que un GET sobre un id de tarea inexistente o caducado devuelve 404 task not found; en el escaneo de reconciliación trátalo como estado final, no como «aún en espera».

Adónde ir después

FAQ

¿Cuántas imágenes de referencia puedo pasar a seedream-5.0-lite imagen a imagen? El array image_urls admite hasta 14 imágenes. El mínimo es una, ya que el campo es obligatorio; por tanto, para llamadas de texto a imagen puras deberías usar seedream-5.0-lite/text-to-image.

¿Por qué otros modelos aceptan 1K y a mí me devuelve «value must be one of '2K', '4K'»? El schema de entrada de la API de tareas se define por modelo. El modo imagen a imagen de seedream-5.0-lite solo ofrece salidas 2K y 4K; otros modelos ofrecen el nivel 1K. No reutilices el payload de otro modelo sin comprobarlo.

¿Puedo enviar las imágenes de referencia en base64 en lugar de una URL? El schema de este modelo acepta image_urls, un array de URL. Aloja las imágenes en una URL HTTPS accesible (cualquier CDN, bucket de almacenamiento de objetos o URL prefirmada sirve) y pasa esa URL.

¿Cuánto tarda una generación y cuánto dura la URL de salida? Normalmente bastante menos que el presupuesto de polling de 600 segundos del ejemplo de Python anterior. La URL de salida lleva una marca de tiempo expireAt; descarga los bytes en cuanto la tarea tenga éxito y guárdalos en tu propio almacenamiento.

¿Sirve el mismo código para seedream-5.0-lite texto a imagen? El endpoint y el flujo son los mismos, pero texto a imagen tiene su propio schema de input (sin image_urls). Cambia el id del modelo a seedream-5.0-lite/text-to-image y elimina las imágenes de referencia; luego valídalo con una llamada de prueba, porque los campos obligatorios difieren entre modos.

¿Cuánto cuesta cada imagen? El precio se factura por uso de cada generación y varía según la resolución. Consulta las tarifas en tiempo real en la página de precios.

Artículos relacionados

Ver todos los artículos →

Empieza a crear con artefactos de IA persistentes

Consigue tu API key y llama a modelos de imagen, vídeo y audio a través de una única API basada en tasks.

Leer la documentación de la API