Referencia de la API
Imagen
Genera una imagen a partir de un prompt, o edita imágenes existentes con hasta cuatro referencias.
/v1/images/generationsDos rutas sobre el mismo modelo: una parte solo de un prompt, la otra parte de imágenes que tú envías. Ambas devuelven la imagen en base64 en el cuerpo de la respuesta.
/v1/images/generations/v1/images/editsEstas rutas requieren una clave de un stack del plan de imagen. Una
clave de un plan de texto recibe 403 aquí, y una clave de imagen recibe
403 en las rutas de chat. La generación de imágenes corre en
infraestructura dedicada, no en la máquina que responde chat.
Generación
application/json. Entra un prompt, sale un PNG.
curl -X POST "https://api.trystac.com/v1/images/generations" \
-H "Authorization: Bearer $STAC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "a white dress shirt folded on a wooden table",
"size": "1024x1024",
"seed": 42
}'Esta ruta no acepta imagen de entrada. Enviar una devuelve 400
wrong_route_for_reference_image — usa /v1/images/edits.
Edición
multipart/form-data. De una a cuatro imágenes de referencia, más un prompt
que describa el cambio.
curl -X POST "https://api.trystac.com/v1/images/edits" \
-H "Authorization: Bearer $STAC_API_KEY" \
-F "prompt=make it black and white" \
-F "size=1024x1024" \
-F "image[]=@photo.png"El campo de archivo acepta tanto image como image[] — el segundo es el que
usan los propios ejemplos de OpenAI para múltiples archivos. Hasta 4
imágenes, de 5 MiB cada una, en PNG, JPEG o WEBP. El formato se lee del
contenido del archivo, no de su extensión ni del Content-Type de la parte. El
cuerpo multipart completo tiene un tope de 21 MiB.
Las imágenes de referencia se convierten a RGB al llegar, lo que descarta el canal alfa, los perfiles de color y los metadatos EXIF — incluido cualquier dato de ubicación que llevara el archivo original.
El campo model se comporta distinto en esta ruta. En todo el resto de la
API se ignora y se reemplaza por el modelo de tu stack. Aquí no —
reescribirlo exigiría recodificar el cuerpo multipart entero. Omite el campo,
o envía exactamente flux2-klein-4b. Cualquier otro valor devuelve 404.
mask no está soportado y devuelve 400. El pod carga un único pipeline, y
aplicar la edición a la imagen completa fingiendo respetar la máscara sería peor
que rechazarla.
Parámetros
Los mismos campos en ambas rutas — como JSON en /generations, como campos de
formulario en /edits.
promptstringObligatorioQué generar, o qué cambiar en las imágenes que enviaste. Puede omitirse si tu clave tiene un prompt configurado — ver Prompt en la clave. Lee Longitud del prompt antes de escribir uno largo.
sizestringOpcionalPredeterminado: 1024x1024Dimensiones de salida — cuadrada, horizontal o vertical. Es una lista cerrada; cualquier otro valor devuelve 400.
1024x10241536x10241024x1536stepsintegerOpcionalPredeterminado: 4Pasos de difusión, de 1 a 8. El checkpoint es destilado, así que está afinado para producir una imagen terminada en muy pocos pasos — por eso el tope es 8 y no 50.
guidance_scalenumberOpcionalPredeterminado: 1.0Con qué rigor seguir el prompt, de 0 a 20.
seedintegerOpcionalDe 0 a 2^64−1. Si la omites, el servidor sortea una y la devuelve en meta.seed — ese valor es el que reproduce la misma imagen después.
nintegerOpcionalPredeterminado: 1Imágenes por petición. Hoy 1 es el único valor aceptado.
response_formatstringOpcionalPredeterminado: b64_jsonSolo b64_json. url se rechaza — la imagen viene en el cuerpo de la respuesta.
Respuesta
Idéntica en ambas rutas.
{
"created": 1767225600,
"data": [{ "b64_json": "iVBORw0KGgo..." }],
"meta": {
"prompt": "a white dress shirt folded on a wooden table",
"width": 1024,
"height": 1024,
"steps": 4,
"guidance_scale": 1.0,
"seed": 8151234567890123456,
"n": 1,
"model": "flux2-klein-4b",
"timings": {
"queue_wait_s": 0.0100,
"decode_s": null,
"gpu_s": 4.1000,
"encode_s": 0.1800,
"worker_s": 4.2800
}
}
}meta trae los parámetros efectivos — lo que el servidor usó de verdad,
después de los valores por defecto y después de sortear una seed, si no enviaste
ninguna.
data[].b64_jsonstringOpcionalEl PNG, codificado en base64.
meta.seedintegerOpcionalLa seed que produjo este resultado. Es del lote, no de cada imagen: reproducir la imagen i exige la misma seed y el mismo n.
meta.timingsobjectOpcionalA dónde se fue el tiempo, en segundos, con cuatro decimales. queue_wait_s es la espera por un espacio libre; decode_s es la lectura de tus imágenes de referencia (null en /generations, que no tiene ninguna); gpu_s es la difusión en sí; encode_s es la producción del PNG. worker_s es la suma de los tres últimos y no incluye la espera en la cola.
Longitud del prompt
El prompt se trunca en 512 tokens, de forma silenciosa. No hay error ni aviso — lo que pase de ahí simplemente nunca llega al modelo.
Esta es la causa más común de "la imagen ignoró la mitad de lo que pedí". Un prompt largo y detallado no solo se desperdicia después del corte, sino que además diluye la parte que sí cabe. Empieza por el sujeto y por los detalles que más importan.
Prompt en la clave
El prompt puede vivir en tu clave de API, como el system prompt en las rutas
de texto — y vale la misma precedencia.
| En el cuerpo de la petición | En la clave | Lo que recibe el modelo |
|---|---|---|
prompt con texto | cualquier cosa | el de la petición |
| ausente o en blanco | configurado | el de la clave |
| ausente o en blanco | nada | 400 missing_prompt |
Es lo que permite enviar solo la URL, la clave y la imagen:
curl -X POST "https://api.trystac.com/v1/images/edits" \
-H "Authorization: Bearer $STAC_API_KEY" \
-F "image[]=@photo.png"Sustituye, no suma. No hay concatenación entre el prompt de la clave y el
de la petición: enviar prompt descarta por completo el configurado. Y el
texto de la clave gasta el mismo presupuesto de 512 tokens — un prompt largo
en la clave no deja espacio para nada más.
Rendimiento
La generación de imágenes no tiene cuota diaria — la difusión no produce tokens, así que el presupuesto de tokens que aplica a las rutas de chat no aplica aquí. Lo que limita es la GPU, que renderiza una imagen a la vez.
| Límite | Qué significa | |
|---|---|---|
| Envíos | 10 por minuto | Compartido entre generations y edits |
| En vuelo | 3 a la vez | 1 renderizando y hasta 2 esperando |
| Espera en cola | 60 segundos | Pasado eso la petición devuelve 504 |
Ambos límites son del stack, no de la clave. Emitir más claves no los sube, porque es la misma GPU la que hace el trabajo de todos modos.
Disparar 10 peticiones a la vez no hace que terminen antes — 3 se aceptan y 7
vuelven 429. El patrón que funciona es mantener 3 en vuelo y empalmar la
siguiente conforme cada una termina.
Observado de extremo a extremo: alrededor de 6–9s para texto → imagen y 7–21s para una edición, variando con la cantidad, las dimensiones y el peso de las imágenes de referencia. "10 por minuto" es un tope de envío, no una promesa de diez imágenes terminadas por minuto.
Almacenamiento y retención
Cada imagen generada se almacena, vinculada a la cuenta, al stack y a la clave
que la creó. Esto ocurre en el servidor y no cambia nada en tu código — la
respuesta sigue siendo b64_json.
Dos consecuencias que vale la pena conocer:
- Un
200significa que la imagen fue almacenada. La escritura ocurre antes de que salga la respuesta y añade unos cientos de milisegundos a una llamada que ya tarda segundos. - Un
502puede ocurrir con la imagen ya generada. Si el almacenamiento falla, devolvemos el error en lugar de entregarte la imagen afirmando que quedó guardada. Reintentar es seguro — pero ten en cuenta que genera de nuevo, con una seed nueva si no fijaste ninguna.
Los archivos se conservan 30 días. Si necesitas una imagen por más tiempo,
guarda el b64_json de tu lado: este almacenamiento existe para trazabilidad y
para verla en la plataforma, no como alojamiento permanente.
Errores
Dos formatos de error te llegan en estas rutas. Los rechazos del propio gateway
usan el formato { "detail": "..." } común a toda la API; lo que rechaza el
servidor de imágenes vuelve en el formato de OpenAI, con un code estable sobre
el que sí puedes ramificar:
{
"error": {
"message": "size must be one of: 1024x1024, 1536x1024, 1024x1536",
"type": "invalid_request_error",
"code": "invalid_size"
}
}| Status | code | Significado |
|---|---|---|
400 | invalid_size, invalid_steps, invalid_n, invalid_guidance_scale, invalid_seed | Campo fuera del rango aceptado, o con el tipo equivocado |
400 | missing_prompt | prompt ausente o vacío, y sin prompt configurado en la clave |
400 | mask_not_supported | mask no está soportado en esta versión |
400 | wrong_route_for_reference_image | Enviaste una imagen a /generations — usa /edits |
400 | missing_image | /edits llamado sin archivo |
400 | too_many_reference_images | Más de 4 referencias |
400 | unsupported_image_format | Una referencia no es PNG, JPEG ni WEBP |
403 | — | La clave no es de un stack del plan image |
404 | model_not_found | model distinto del modelo servido (solo en /edits) |
413 | image_too_large | Referencia por encima de 5 MiB, o cuerpo por encima del tope de la ruta |
429 | queue_full | Ya hay 3 en vuelo — respeta el Retry-After |
429 | — | Por encima de 10 envíos por minuto — respeta el Retry-After |
502 | — | La imagen se generó, pero no se pudo almacenar |
503 | model_not_ready | Infraestructura aún arrancando, o degradada |
504 | queue_timeout | Esperó más de 60s por un espacio libre |
Reintenta 429, 503 y 504 tras el tiempo indicado en Retry-After. Un
502 también merece un intento, teniendo en cuenta que renderiza de nuevo desde
cero.

