Guía: generar y editar imágenes
Cómo se comportan los endpoints de imagen como familia — las dos formas de petición, las tres maneras de escribir el tamaño de salida, lo que una imagen de referencia añade a la factura, los pesos de adaptación y cómo leer un rechazo.
Esta guía trata de la familia de endpoints de imagen, no de un modelo concreto. Explica lo que no cambia entre ellos y, más útil todavía, los puntos en los que difieren tanto que un cuerpo de petición escrito para uno no sobrevive al siguiente.
No encontrará aquí una tabla de parámetros, y es deliberado. Los parámetros tienen una única fuente: el inputSchema que el catálogo en vivo devuelve para el modelo exacto que va a llamar. Esta página explica cómo leer ese esquema y lo que no dice en voz alta.
| Si busca | Lea en su lugar |
|---|---|
| Su primera imagen, de la clave al archivo, de principio a fin | Inicio rápido |
| El mismo recorrido para vídeo, paso a paso | Tutorial: convertir una foto en vídeo |
| Todos los campos de un modelo concreto | Su inputSchema — véase Catálogo de modelos y esquemas |
| Llevar una cara o una cabeza de una foto a otra | Intercambio de sujeto |
MODEL_ID_FROM_CATALOG es un marcador de posición
Todos los ejemplos escriben MODEL_ID_FROM_CATALOG donde va un identificador de modelo real. Tome ese identificador del catálogo en vivo autenticado — GET /api/v1/models?modality=image — y exija enabled: true y available: true antes de gastar nada. Leer el catálogo es gratis. Enviar el marcador tal cual solo devuelve un error «not found».
Dos formas de petición
El trabajo con imágenes llega como dos tareas, y el catálogo las separa:
- Los endpoints de generación terminan en
/text-to-image. Usted envía palabras y recibe una imagen. - Los endpoints de edición terminan en
/edit. Además envía al menos una imagen.
La edición tiene dos grafías admitidas, y conviene conocer ambas antes de filtrar el catálogo: los endpoints se publican con el sufijo edit, mientras que el array tasks los clasifica como image-to-image. El parámetro de consulta task acepta cualquiera de las dos. Véase Catálogo de modelos y esquemas.
Ambas formas usan el mismo sobre de creación, el mismo ciclo de vida de tarea y el mismo formato de resultado que cualquier otro modelo de medios. Lo que cambia es input.
prompt es obligatorio en las dos
Es tentador suponer que un endpoint de edición puede trabajar solo con la imagen y que prompt allí es opcional. En los endpoints que aceptan un prompt, no lo es: prompt está en la lista required raíz de ambas formas, y omitirlo se rechaza antes de cobrar nada.
{
"model": "MODEL_ID_FROM_CATALOG",
"input": {
"image_urls": ["spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"]
}
}prompt: is requiredLa imagen dice de dónde parte; el prompt dice qué hacer con ella. Un endpoint de edición que no recibió instrucción no tiene sobre qué actuar.
Hay una excepción, y es una familia entera más que un caso suelto: algunos endpoints de edición no aceptan ningún prompt y solo toman imágenes, porque la operación la fija el propio endpoint. Pertenecen al conjunto de herramientas de intercambio de sujeto y llevan un campo toolkit en el catálogo que permite distinguirlos; véase Intercambio de sujeto. En ellos, prompt: is not a supported field es la respuesta correcta, no un fallo.
El campo de la imagen de entrada tiene tres nombres
Cuál usa cada endpoint forma parte de su esquema y no se deduce del tipo de tarea:
| Campo | Forma | Lo que suele significar |
|---|---|---|
image_url | una referencia de imagen | Hay exactamente una imagen de sujeto y el endpoint no contempla una segunda |
image_urls | array de referencias de imagen | Las imágenes son el material que se edita o combina, en el orden al que alude la instrucción |
reference_image_urls | array de referencias de imagen | Las imágenes orientan una generación que de otro modo sería solo de texto: son guía, no el sujeto |
El que sorprende es reference_image_urls: aparece en endpoints de generación, así que un endpoint /text-to-image sí puede aceptar imágenes. No dé por hecho que «text-to-image» signifique «sin imágenes en la petición».
Una referencia de imagen es una URL HTTPS pública, una URI spicy:// confirmada tras una subida, o una URI data:image/…;base64,… pequeña. Para subidas véase Medios; para los nombres canónicos, el contrato Spicy Schema.
Los límites de los arrays varían mucho más de lo que se supone
Los arrays anteriores llevan minItems y maxItems, el servidor aplica ambos y los números difieren según el endpoint: hoy van desde un array que acepta exactamente una entrada hasta arrays que aceptan diez. Un endpoint de la misma familia, con el mismo nombre de campo, puede tener otro techo.
image_urls: must contain at least 1 items
image_urls: must contain at most 3 itemsLea minItems y maxItems del esquema del modelo que va a llamar. Una tabla de parámetros que muestre un array como un mero array, sin la forma de sus entradas ni el límite de longitud, es justo la fila con la que un lector no puede hacer nada, y por eso este sitio no publica ninguna.
El tamaño de salida se escribe de tres formas
Es lo primero con lo que se tropieza al apuntar un cuerpo de petición existente a un segundo endpoint.
En el catálogo de imagen conviven tres grafías, y cada endpoint acepta exactamente una:
| Grafía | Campos | Notas |
|---|---|---|
| Separada | aspect_ratio y resolution | La forma del encuadre y el escalón de píxeles se eligen por separado |
| Preajuste | size | Un valor de enumeración fija ambos de una vez |
| Explícita | width y height | Píxeles enteros, cada uno con su minimum y su maximum |
La grafía separada es la más común en los endpoints recientes y la más útil de las tres: aspect_ratio compone el encuadre antes de generar en lugar de recortar después, de modo que puede cambiar la forma sin tocar el presupuesto de píxeles.
Un campo de la grafía equivocada se rechaza, no se ignora
Todo inputSchema de imagen fija additionalProperties: false. Un campo que el endpoint no lista se rechaza, de modo que un cuerpo de petición traído de otro endpoint falla de plano en lugar de caer calladamente en un valor por defecto.
Falla en las dos direcciones, y el mensaje nombra el campo:
size: is not a supported field
aspect_ratio: is not a supported fieldNinguno de los dos se cobra. El coste no es dinero, es el supuesto: no puede escribir un único objeto input y apuntarlo a varios endpoints de imagen, y no existe una grafía «de compatibilidad» que todos acepten.
Cuál selecciona un escalón de precio
En un endpoint de grafía separada, los dos campos suelen jugar papeles distintos en la factura:
resolutionnormalmente selecciona un escalón de precio. Aparece en el presupuesto comovariant, y moverlo mueve el importe.aspect_rationormalmente no. Reencuadrar no es reescalar.
Ese «normalmente» está trabajando de verdad en las dos frases. La respuesta legible por máquina está en el propio campo: x-ui.affects_price: true y, cuando el endpoint lo declara, la pertenencia a x-pricing.variantFields. Consulte el esquema, no la costumbre. Véase Leer los precios y la referencia de anotaciones en el contrato Spicy Schema.
Los valores permitidos también son por endpoint. Un rechazo los enumera, lo que es una forma gratuita de verlos:
aspect_ratio: must be one of: "1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "21:9"Útil mientras explora, pero no sustituye leer enum, porque el esquema también lleva el default que se aplica cuando omite el campo.
Lo que una imagen de referencia añade a la factura
Este es el concepto silencioso, y merece sección propia porque nada en la respuesta apunta a él.
La aritmética habitual de un modelo de medios es precio × cantidad, donde la cantidad es el valor de quantityField en su entrada, o una unidad si quantityField está vacío. En los endpoints de imagen quantityField suele ser num_outputs, y se comporta como cabe esperar: pida cuatro imágenes y el presupuesto marcará quantity en 4. Esa dimensión es honesta: se la ve moverse.
Algunos endpoints añaden encima un importe aparte por cada imagen de entrada, y ese no se ve moverse. Pida dos presupuestos del mismo endpoint, uno con una sola referencia y otro con el array lleno, y obtendrá:
- la misma
unit; - la misma
quantity; - la misma
variant; - un importe distinto.
Tres de los cuatro campos con los que se suele construir una estimación se quedan exactamente donde estaban. Una estimación calculada como precio × cantidad se queda corta, y nada en la respuesta lo señala.
La firma legible por máquina
Un campo marcado con x-ui.affects_price: true que ni es el quantityField ni figura en x-pricing.variantFields mueve el importe sin seleccionar escalón. En un endpoint así, lea el pricing del catálogo como un suelo y tome el importe de un presupuesto.
Es la misma regla que enuncia Catálogo de modelos y esquemas, y la edición de imagen es donde más veces se la encontrará: el array de imágenes de entrada lleva esa marca con frecuencia.
Cuánto añade depende del endpoint y no sigue ninguna proporción fija. Hoy el catálogo contiene endpoints en los que llenar el array cuesta varias veces lo que una referencia única, y endpoints en los que las referencias adicionales no cuestan nada — sin forma de distinguirlos salvo preguntando. Así que no calcule el precio del array por analogía con un endpoint hermano, ni deduzca el de un array lleno a partir de un presupuesto de una sola referencia.
Presupueste el cuerpo que va a enviar de verdad
curl -sS https://api.spicyapi.ai/api/v1/jobs/quote \
-H "Authorization: Bearer $SPICY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"MODEL_ID_FROM_CATALOG","input":{"prompt":"your instruction","image_urls":["spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"]}}'Un presupuesto ejecuta la misma validación que crear la tarea, no cuesta nada, no inicia nada y no reserva nada. Devuelve estimatedCost, maxCharge, quantity y unit para ese cuerpo exacto. Cambie el array y vuelva a presupuestar. Los detalles, y cómo recuperarse cuando se pierde la respuesta, están en Presupuestos y compatibilidad; dónde encaja un presupuesto en una integración real, en Integración en producción.
Pesos de adaptación
Algunos endpoints permiten aplicar pesos propios ajustados sobre el modelo base. El campo canónico es loras, o high_noise_loras y low_noise_loras cuando un endpoint expone sus etapas por separado.
Un array de objetos, con sus propias reglas dentro
Estos campos llevan x-ui.widget: "object-list": un array cuyo items es un esquema de objeto completo por derecho propio. Tiene su propio required, su propio additionalProperties: false y su propio tipo, rango y default para cada subcampo. Una entrada típica nombra un juego de pesos y con qué fuerza aplicarlo.
{
"model": "MODEL_ID_FROM_CATALOG",
"input": {
"prompt": "your scene",
"loras": [
{ "path": "https://weights.example.com/style.safetensors", "scale": 1 },
{ "path": "https://weights.example.com/character.safetensors", "scale": 0.6 }
]
}
}La forma de una entrada no es fija entre endpoints. Qué cuenta como archivo de pesos —una dirección directa o una clave de una biblioteca incorporada— lo acota el subesquema items de cada endpoint, igual que los nombres de los subcampos, cuántas entradas caben y cuáles son obligatorias. Lea items, no este ejemplo. El contrato Spicy Schema describe el widget; Catálogo de modelos y esquemas muestra cómo convertirlo en una tabla anidada.
Una regla interna de estas entradas se malinterpreta con facilidad: los valores por defecto llegan hasta dentro de las entradas del array. Un subcampo que está en items.required y además tiene default es en la práctica opcional: si lo omite, el valor por defecto se rellena antes de validar. Un subcampo sin valor por defecto se rechaza si falta. Por tanto items.required no significa «debe aparecer en el JSON que envío».
De dónde salen los pesos
path admite una de tres cosas:
- Un enlace público al archivo
.safetensorso, donde el endpoint lo admita, un id de repositorio de Hugging Face comoowner/repo. El modelo lo descarga en el momento de la generación, así que la primera llamada con pesos nuevos es apreciablemente más lenta que las siguientes. - Una subida. Suba el archivo como
application/octet-streamcon el flujo de subida directa, hasta 2 GiB, y use el URIspicy://f/…que se devuelve. El commit comprueba que sea un archivo safetensors completo. - Una importación. Para un archivo que exige iniciar sesión, como uno de un repositorio privado o restringido de Hugging Face o un archivo de Civitai tras una clave de API, envíe el enlace y un token de acceso a
POST /api/v1/files/import. SpicyAPI descarga el archivo una sola vez y devuelve un URIspicy://f/…. El token se usa solo para esa descarga y nunca se guarda.
curl -sS https://api.spicyapi.ai/api/v1/files/import \
-H "Authorization: Bearer $SPICY_API_KEY" \
-H "Content-Type: application/json" \
--data "$(jq -n --arg url "https://huggingface.co/OWNER/REPO/blob/main/your_lora.safetensors" --arg token "$HF_TOKEN" '{url: $url, token: $token}')"url también puede ser el id del repositorio (OWNER/REPO) o la página del repositorio, cuando este contiene exactamente un archivo .safetensors. La respuesta tiene la misma forma que la de un commit; ponga data.uri en loras[].path. Los pesos subidos e importados se conservan un día, como cualquier otra subida, y nunca se comparten con otras cuentas. Pasado ese plazo, vuelva a subirlos o importarlos.
El envío comprueba el enlace, no los pesos que contiene
Antes de crear una tarea se sondea cada enlace de pesos. Un enlace que exige iniciar sesión, devuelve 404 o abre una página web se rechaza con un 400 y no se cobra nada; el mensaje señala la entrada. Todo lo demás pasa, así que un host que se caiga más tarde, o unos pesos que no se puedan cargar, siguen llegándole como fallo de tarea.
Los problemas que el sondeo no puede ver vuelven más tarde, como fallo de tarea con un errorCode de las nueve clases públicas de la plataforma y un mensaje que explica qué falló; el importe retenido para la tarea se devuelve. Véase Errores.
El peor caso es todavía más silencioso: unos pesos construidos para otro modelo base pueden cargarse sin fallar y cambiar el resultado casi nada. No hay error que leer, solo una imagen que parece la del modelo base.
Compruébelo, pues, en el despliegue
Saque la comprobación de la ruta de petición y llévela a lo que se ejecuta al publicar:
- Alcanzabilidad. Una petición
HEADcontra cada dirección de pesos que vaya a poner en producción. La plataforma sondea cada enlace al crear una tarea, pero un enlace que hoy funciona puede dejar de hacerlo la semana que viene, y una comprobación en el despliegue lo detecta antes que su tráfico. - Efecto. Una generación por cada archivo de pesos nuevo, comparada con el mismo prompt y la misma semilla sin él. Si no se distinguen, el archivo no está haciendo lo que cree; compruébelo antes de que un lote dependa de él.
- Estabilidad. Sus direcciones tienen que seguir funcionando mientras estén en producción. Un archivo de pesos que desaparece se convierte en fallos de tarea sin causa aparente, días después del despliegue al que se los achacará.
Los consejos específicos de cada endpoint sobre estos campos —contra qué se mide realmente un valor, qué ajuste hace una llamada notablemente más lenta, qué entradas acepta el esquema y acabará lamentando— viven en paramNotes, en el catálogo público, indexados por nombre de parámetro y disponibles en los diez idiomas de la documentación. Es prosa, nunca una regla; lo que se acepta lo sigue decidiendo inputSchema. Véase Catálogo de modelos y esquemas.
Asíncrono, como cualquier otro modelo de medios
Los endpoints de imagen son tareas, no llamadas de petición y respuesta. Se crea una tarea y luego se recoge el resultado sondeando o por webhook; queued y running no son terminales, y succeeded, failed y expired sí. La autoridad sobre los estados es Tareas asíncronas.
Las imágenes terminan antes que los vídeos, lo que tienta a escribir la llamada como si fuera síncrona. Resístase: aquí un sondeo acotado es lo bastante corto como para parecerlo, pero el código sigue teniendo que atender una tarea que continúa en marcha cuando se agota el presupuesto de espera, y pasar eso a un webhook escala mejor que mantener una petición abierta. El sondeo utiliza la capacidad de lectura de la cuenta, de forma independiente del envío de tareas. Un sondeo excesivo puede limitar las consultas de estado; consulta Límites de solicitudes.
Leer el resultado
Una tarea correcta lista sus archivos en output.assets[]. Tres cosas sobre esa lista en los endpoints de imagen:
- Puede contener más de un archivo. Cuando
num_outputses mayor que uno, recibe un recurso por imagen. Escriba el manejador como un bucle desde el principio; uno que leaassets[0]descarta en silencio todo lo demás que ha pagado. - La extensión la decide
mime, no el nombre del endpoint ni el prompt. Cuando un endpoint exponeoutput_format, ese campo elige la codificación; cuando no, la codificación es propia del endpoint ymimees la única forma de saber qué ha recibido. - Un archivo que aún se está copiando lleva
pending: truey no tieneurl. Los resultados se copian al almacenamiento propio de SpicyAPI antes de entregarse, lo que tarda unos segundos después de que la tarea informe de su éxito. Vuelva a leer la tarea en lugar de tratar la falta de enlace como un fallo.
Los enlaces de descarga duran unos veinte minutos y no necesitan clave de API; vuelva a leer la tarea para obtener uno nuevo. Los archivos generados se conservan como mucho catorce días, menos si la retención de su cuenta es más corta. Véase Resultados y descargas y Retención y destrucción.
Leer un rechazo
Una petición rechazada no cuesta nada ni crea nada, así que el endpoint de presupuesto sirve además como validador gratuito del cuerpo que está a punto de enviar.
Se informa de todos los problemas, no solo del primero. El mensaje los une con ; , de modo que un único presupuesto rechazado puede decirle todo lo que falla:
prompt: is required; loras.0.path: is required; loras.0.scale: must be at most 4; bogus: is not a supported fieldUn problema dentro de un array señala la entrada. El puntero es campo.índice.subcampo, con índice desde cero:
loras.1.scale: must be at most 4Pase ese puntero a quien tenga que corregirlo. Con varias entradas en juego, saber cuál se sale de rango es la diferencia entre un arreglo de una línea y una bisección.
Las formas que se encontrará:
| Mensaje | Qué significa | Qué hacer |
|---|---|---|
X: is required | X está en la lista required raíz | Añadirlo. En endpoints de edición suele ser prompt o el campo de imagen |
X: is not a supported field | X no está en properties; los campos desconocidos se rechazan, nunca se ignoran | Quitarlo, o usar la grafía de este endpoint — véase Tamaño de salida |
X: must be one of: … | El valor queda fuera de enum | El mensaje enumera los valores admitidos; enum y default están en el esquema |
X: must contain at least N items | Por debajo de minItems | Un array que el endpoint exige no puede enviarse vacío |
X: must contain at most N items | Por encima de maxItems | Lea el techo de este endpoint; no es el mismo en todos |
X: must be an array | El valor no tiene el tipo declarado | Envuelva la entrada única en una lista |
X: must be at most N characters | Por encima de maxLength | Los prompts también tienen techo por endpoint |
X.<n>.<sub>: is required | Un subcampo de la entrada <n> es obligatorio y no tiene valor por defecto | Añádalo solo a esa entrada |
X.<n>.<sub>: is not a supported field | El esquema de entrada fija additionalProperties: false | Quite esa clave de esa entrada |
X.<n>.<sub>: must be at most N | El subcampo se sale de su propio rango | Acótelo; los rangos son por subcampo, no por array |
Si el rechazo llega cuando esperaba que funcionara, la causa habitual es un esquema caducado. Vuelva a leer el catálogo tras un 400 y no guarde nunca una instantánea permanente: Cachear el catálogo explica cuánto vale una copia. El resto lo cubre Resolución de problemas.
Siguientes pasos
Catálogo de modelos y esquemas
El catálogo en vivo, los escalones de precio y su propia tabla de parámetros a partir de inputSchema
Contrato Spicy Schema
Nombres canónicos de campos, anotaciones x-ui, campos condicionales y formato de resultado
Medios
Subir una imagen y convertirla en una referencia spicy://
Presupuestos y compatibilidad
Poner precio a una petición exacta antes de pagarla
Intercambio de sujeto
Los endpoints de edición que toman imágenes y ningún prompt
Tutorial: convertir una foto en vídeo
El mismo recorrido para vídeo, con la CLI, el SDK y HTTP puro
Errores
Todos los códigos de error y en cuáles sirve reintentar
Integración en producción
Lo que hay que añadir antes de que dependan de ello usuarios reales
Tutorial de imagen a video
Empieza con una imagen de tu equipo y termina con un archivo de video descargado. Cada paso muestra cómo hacerlo con la CLI, con el SDK de TypeScript y con HTTP directo.
Sustitución de personas
Un mismo kit, dos formas. Los modelos de una llamada sustituyen una cara o una cabeza en una sola petición; los de dos llamadas analizan antes el clip para que elijas a quién cambiar.

