Tutorial
Cómo usar gpt-image-2/text-to-image a través de la API de hiapi: parámetros, código y ejemplo ejecutable
Este tutorial muestra el código mínimo necesario para generar una imagen con gpt-image-2/text-to-image mediante la API de tareas unificada de hiapi, y después explica uno a uno cada parámetro, así como los patrones de nivel de producción que conviene adoptar una vez que el código funciona (callbacks, idempotencia, manejo de errores).
Requisitos previos
Necesitas una clave de API. Créala desde la página de claves de API de la consola de hiapi: la clave empieza por sk-. La página del modelo gpt-image-2/text-to-image indica el precio actual por imagen; el desglose completo está en la página de precios.
Todas las llamadas de esta guía van al endpoint unificado de tareas asíncronas:
POST https://api.hiapi.ai/v1/tasks: crea una tarea de generaciónGET https://api.hiapi.ai/v1/tasks/{taskId}: consulta el estado de la tarea
La documentación de referencia general de la plataforma está en la documentación de la API de hiapi.
Ejemplo mínimo ejecutable (curl)
Una generación individual es una interacción de dos pasos: primero se crea la tarea y luego se espera a que termine.
# 1. Create the task
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2/text-to-image",
"input": {
"prompt": "a calico cat curled up on a sunlit windowsill, soft focus background",
"aspect_ratio": "1:1",
"resolution": "1K"
}
}'
# => {"code":200,"data":{"taskId":"tk-hiapi-01KVY...."},"message":"success"}
# 2. Poll until status == "success"
TASK_ID="tk-hiapi-01KVY...."
curl -s "https://api.hiapi.ai/v1/tasks/$TASK_ID" \
-H "Authorization: Bearer sk-YOUR_KEY"
# => {"code":200,"data":{"status":"success","output":[{"url":"https://..."}], ...}}
La URL de la imagen está en data.output[0].url. Descárgala de inmediato: output[0].expireAt es muy corto, así que esa URL solo sirve para obtener la imagen, no para incrustarla de forma permanente.
Python: crear + consultar + guardar en disco
import os
import time
import urllib.request
import requests # pip install requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"] # sk-...
def create_task(prompt: str, aspect_ratio: str = "1:1", resolution: str = "1K") -> str:
payload = {
"model": "gpt-image-2/text-to-image",
"input": {
"prompt": prompt,
"aspect_ratio": aspect_ratio,
"resolution": resolution,
},
}
r = requests.post(API_BASE, json=payload,
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=60)
r.raise_for_status()
body = r.json()
if body.get("error"):
raise RuntimeError(f"create failed: {body['error']}")
return body["data"]["taskId"]
def wait_task(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{API_BASE}/{task_id}",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30)
r.raise_for_status()
task = r.json().get("data") or {}
status = task.get("status")
if status == "success":
return task
if status == "fail":
raise RuntimeError(f"task failed: {task.get('error')}")
time.sleep(poll_s)
raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")
if __name__ == "__main__":
task_id = create_task(
"a calico cat curled up on a sunlit windowsill, soft focus background",
aspect_ratio="3:2",
resolution="1K",
)
task = wait_task(task_id)
url = task["output"][0]["url"]
urllib.request.urlretrieve(url, "cat.png")
print(f"saved cat.png from task {task_id}")
Node.js: el mismo flujo con fetch
// Node 18+ has global fetch
const API_BASE = "https://api.hiapi.ai/v1/tasks";
const TOKEN = process.env.HIAPI_API_KEY;
async function createTask(prompt, aspectRatio = "1:1", resolution = "1K") {
const res = await fetch(API_BASE, {
method: "POST",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-image-2/text-to-image",
input: { prompt, aspect_ratio: aspectRatio, resolution },
}),
});
const body = await res.json();
if (body.error) throw new Error(`create failed: ${body.error.code} ${body.error.message}`);
return body.data.taskId;
}
async function waitTask(taskId, { timeoutMs = 600_000, pollMs = 5_000 } = {}) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const res = await fetch(`${API_BASE}/${taskId}`, {
headers: { "Authorization": `Bearer ${TOKEN}` },
});
const task = (await res.json()).data || {};
if (task.status === "success") return task;
if (task.status === "fail") throw new Error(`task failed: ${JSON.stringify(task.error)}`);
await new Promise(r => setTimeout(r, pollMs));
}
throw new Error(`task ${taskId} timed out`);
}
(async () => {
const id = await createTask(
"a calico cat curled up on a sunlit windowsill, soft focus background",
"16:9",
"1K",
);
const task = await waitTask(id);
const url = task.output[0].url;
const img = await fetch(url).then(r => r.arrayBuffer());
const { writeFileSync } = await import("node:fs");
writeFileSync("cat.png", Buffer.from(img));
console.log(`saved cat.png from task ${id}`);
})();
Referencia de parámetros
El cuerpo de la solicitud siempre contiene dos campos de nivel superior: model (cadena, el ID de modelo sin prefijos gpt-image-2/text-to-image) e input (el objeto de parámetros específico de cada modelo).
Campo de input |
¿Obligatorio? | Tipo | Descripción |
|---|---|---|---|
prompt |
Sí | string | Descripción textual de la imagen que deseas. |
aspect_ratio |
Sí | string | Uno de estos valores: 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9 o auto. |
resolution |
No | string | 1K (predeterminado), 2K o 4K. Las dimensiones en píxeles se escalan según la relación de aspecto elegida. |
callback |
No | object | { "url": "https://yours.example/hook", "when": "final" }: consulta la sección siguiente. |
Una creación correcta devuelve {"code":200, "data":{"taskId":"tk-hiapi-..."}, "message":"success"}. La llamada GET /v1/tasks/{taskId} devuelve data.status con uno de estos valores: handling, success o fail; cuando tiene éxito, data.output es un array cuyo primer elemento contiene la url de la imagen y la marca de tiempo expireAt.
Otros modelos de imagen de hiapi (por ejemplo,
z-image,qwen-image) usan campos deinputalgo distintos:aspect_ratioes la convención que adoptagpt-image-2/text-to-image. Al cambiar de modelo, consulta la página del modelo para confirmar la estructura exacta deinput.
Patrones de nivel de producción
Usar callbacks en lugar de polling
Consultar cada 5 segundos está bien para un prototipo, pero para tráfico de producción querrás que hiapi te envíe las tareas completadas y así liberar al worker. Añade un bloque callback dentro de input:
{
"model": "gpt-image-2/text-to-image",
"input": {
"prompt": "an astronaut sketching the moon",
"aspect_ratio": "3:2",
"resolution": "1K",
"callback": {
"url": "https://your-app.example.com/webhooks/hiapi",
"when": "final"
}
}
}
when: "final" se dispara una vez cuando la tarea alcanza un estado terminal (success o fail). La carga útil que recibe tu endpoint tiene la misma estructura que GET /v1/tasks/{id}, así que el manejador puede reutilizar la lógica de análisis del polling. Compara taskId con el taskId que guardaste al crear la tarea para saber a qué solicitud corresponde el callback.
Hacer idempotente la operación de creación
Si el worker se cae justo después de POST /v1/tasks y antes de guardar el taskId, podrías generar la misma imagen dos veces. La solución de bajo coste es: en el momento de recibir la respuesta de creación, guardar (your_request_id → taskId) en la base de datos dentro de la misma transacción en la que se envía la solicitud. Si el worker reintenta, encontrará el taskId existente y reanudará el polling en lugar de crear una nueva tarea.
Manejar correctamente los errores de autenticación
Un fallo de autenticación de hiapi devuelve HTTP 200 con la carga útil de error embebida en el cuerpo de la respuesta:
{"error":{"code":"permission_denied","message":"This API key cannot use the selected model. ...","type":"hiapi_error"}}
Por lo tanto, un código de estado 200 por sí solo no significa éxito. Comprueba siempre primero body.error; si existe, revisa error.code (permission_denied, invalid_request, etc.) y error.message. El request_id del mensaje es lo que debes pegar en el ticket de soporte cuando necesites ayuda.
Descargar de inmediato y volver a alojar por tu cuenta
data.output[0].url es una URL de corta duración: la respuesta incluye expireAt. No pongas la URL de hiapi directamente en el <img src> de tu producto; en cuanto la tarea tenga éxito, descarga los bytes de inmediato, súbelos a tu propio almacenamiento (S3, R2, Supabase Storage, etc.) y sirve la imagen desde ahí.
Configurar tiempos de espera razonables
Un valor predeterminado razonable es: 60 segundos de timeout para la solicitud POST (crear la tarea es rápido: en realidad solo esperas a que la API confirme la recepción), un presupuesto total de 10 minutos para el bucle de polling con un intervalo de 5 segundos. Una tarea que tarda más de 10 minutos casi siempre significa que ha pasado silenciosamente al estado fail, así que agotar el tiempo de espera y registrar en los logs el último cuerpo de respuesta de la tarea es más útil que esperar indefinidamente.
Preguntas frecuentes
¿Cuál es la diferencia entre gpt-image-2 y gpt-image-2/text-to-image?
gpt-image-2 es la familia de modelos; gpt-image-2/text-to-image es el endpoint específico al que llamas para convertir un prompt de texto en una imagen nueva. Otras variantes de la familia exponen estructuras de input distintas (por ejemplo, la edición de imágenes acepta imágenes de referencia). Si tienes dudas, usa el ID de modelo sin prefijos que veas en la página del modelo.
¿Qué hace aspect_ratio: auto?
auto deja que el modelo decida la relación de aspecto según el prompt. Úsalo cuando no tengas requisitos estrictos de composición; en caso contrario, fija tú mismo la relación para que el recorte posterior sea predecible.
¿Por qué mi solicitud devuelve HTTP 200 con permission_denied?
O la clave de API es incorrecta (error tipográfico, revocada, sin el prefijo sk-), o el plan de esa clave no incluye gpt-image-2/text-to-image. Abre la consola de claves de API, confirma la cadena de la clave y revisa tu plan en la página de precios. Comprueba siempre body.error.code: nunca confíes únicamente en el código de estado HTTP.
¿Puedo generar varias imágenes en una sola solicitud?
gpt-image-2/text-to-image genera solo una imagen por tarea: data.output es un array, pero para este modelo su longitud siempre es 1. Para generar N variantes, lanza N tareas en paralelo y usa el patrón callback anterior, así no dejas N hilos de trabajo colgados.
¿Cómo cancelo una tarea en ejecución?
La API de tareas unificada no ofrece actualmente un endpoint de cancelación. La mitigación más sencilla es que el worker del cliente descarte el resultado cuando el usuario ya no lo necesite; la generación que ya se ejecutó se cobra igualmente, así que el lugar correcto para forzar una cancelación es antes de llamar a POST /v1/tasks.
¿Cómo cambio a otro modelo de imagen?
Cambia model por el nuevo ID sin prefijos (por ejemplo, z-image/text-to-image) y ajusta input para que coincida con la estructura de ese modelo. Las estructuras de cada modelo no son idénticas: algunos aceptan size, otros aceptan aspect_ratio y unos pocos no aceptan resolution. El catálogo de modelos lista todos los modelos disponibles, y la página de cada modelo documenta sus campos de input.
Artículos relacionados
Ver todos los artículos →-
Tutorial
Cómo llamar a hailuo-2.3-fast/image-to-video a través de la API de HiAPI: práctica con curl y Python
La primera solicitud ejecutable del nivel rápido y de bajo coste de imagen a vídeo: del ID del modelo a la descarga del MP4
-
Tutorial
Cómo llamar a hailuo-2.3/text-to-video mediante la API de HiAPI: curl, Python y ejemplos de solicitud ejecutables
-
Tutorial
Uso de Kandinsky 6.0 Pro texto a video en HiAPI: tutorial con curl y Python
Demostración práctica centrada en la solicitud: construir la llamada de prompt a clip de video, enviar la solicitud, sondear el estado de finalización y descargar el resultado