08Fundamentos de la API
Tareas y estados
La imagen se genera en segundo plano. Al aceptar la solicitud recibes el id de la tarea: con él puedes consultar el estado hasta que llegue completed o failed, o esperar el webhook.
Consultar el estado
/creations/{id}Pon el id de la respuesta a la solicitud de generación. La tarea solo la ve la cuenta que la creó: un id ajeno o desconocido da 404 ERR_NOT_FOUND. Guarda el id por tu parte.
CREATION_ID="5b0214ae-9e39-460a-820a-f6ae3e24400b" curl --fail-with-body --max-time 20 \ "https://api.rendergrid.io/ api/ public/ v1/ creations/ $CREATION_ID" \ -H "Authorization: Bearer $RENDERGRID_API_KEY"
import os import requests API = "https://api.rendergrid.io/ api/ public/ v1" creation_id = "5b0214ae-9e39-460a-820a-f6ae3e24400b" key = os.environ["RENDERGRID_API_KEY"] response = requests.get( f"{API}/creations/{creation_id}", headers={"Authorization": f"Bearer {key}"}, timeout=(5, 20), ) response.raise_for_status() print(response.json())
// Node.js 22+, archivo .mjs const API = "https://api.rendergrid.io/ api/ public/ v1"; const id = "5b0214ae-9e39-460a-820a-f6ae3e24400b"; const key = process.env.RENDERGRID_API_KEY; const response = await fetch(`${API}/creations/${id}`, { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(20_000), }); if (!response.ok) { const body = await response.text(); throw new Error(`HTTP ${response.status}: ${body}`); } console.log(await response.json());
Estados
| Estado | Qué significa | Qué hacer |
|---|---|---|
queued | La solicitud está aceptada y espera su turno | Espera y pregunta de nuevo más tarde |
processing | La imagen se está generando | Espera y pregunta de nuevo más tarde |
completed | Listo | Descarga los archivos con los enlaces de result_urls |
failed | No se pudo obtener la imagen | Lee failure y decide si cambiar la solicitud |
completed y failed son finales: puedes dejar de consultar. Una respuesta 200 puede traer status: "failed": es el resultado de la tarea, no un error de la propia solicitud de estado.
Una solicitud fallida es gratis: el importe vuelve de inmediato al saldo.
Cómo es la respuesta
Mientras no hay resultado, la respuesta solo lleva id y status. El resto de los campos aparecen al final.
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "queued"
}
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "processing"
}Todavía no hay otros campos. Vuelve a preguntar pasados 5 segundos o más.
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "completed",
"result_urls": ["https:// cdn.rendergrid.io/ images/ example/ result.jpg"]
}result_urls son los enlaces ya hechos a los archivos. Úsalos tal cual: no los construyas a partir del id ni cuentes con la extensión del archivo.
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "failed",
"error": "The image or prompt was rejected by the safety filter. Try a different image or rephrase the prompt.",
"failure": {
"type": "declined",
"code": "content_policy",
"retryable": false
}
}error es un texto para mostrar. Construye la lógica con failure.type y failure.code: qué significan.
Pruébalo tú mismo
Es un esquema de aprendizaje: no hace ninguna solicitud a la API. Elige el desenlace y pulsa el botón.
queuedSolicitud aceptada. La tarea espera su turno.
processingLa imagen se está generando.
completedListo: la respuesta trae result_urls.
Pulsa «Enviar solicitud» y mostraremos qué devuelve GET /creations/ en cada paso.
Con qué frecuencia consultar
Una tarea con una misma clave: como máximo una vez cada 5 segundos. Un sondeo más frecuente recibirá 429 ERR_RATE_LIMIT: espera al menos lo que indique details.min_interval_seconds y al menos lo que indique Retry-After.
HTTP/1.1 429 Too Many Requests
Retry-After: 2
{
"error": {
"code": "ERR_RATE_LIMIT",
"message": "polled too soon — retry after the minimum interval",
"details": { "min_interval_seconds": 5 }
}
}- Deja de consultar en
completedy enfailed. - Ante un corte de conexión,
429y5xx, repite con una pausa y respetaRetry-After. - Limita el tiempo total de espera. Si se agota, guarda el
idy continúa más tarde: el tiempo de espera agotado de tu cliente no cancela la tarea. - Si consultan varios procesos, acuerda entre ellos un intervalo común.
Un ejemplo de bucle de espera. El tiempo de espera es un ajuste del ejemplo, no el plazo de trabajo del modelo.
import os import time import requests BASE = "https://api.rendergrid.io/ api/ public/ v1" KEY = os.environ["RENDERGRID_API_KEY"] SESSION = requests.Session() SESSION.headers["Authorization"] = f"Bearer {KEY}" TIMEOUT = (5, 20) # segundos: conexión, lectura def wait_for(creation_id: str, wait_seconds: int = 180) -> dict: url = f"{BASE}/creations/{creation_id}" deadline = time.monotonic() + wait_seconds while time.monotonic() < deadline: delay = 5.0 try: resp = SESSION.get(url, timeout=TIMEOUT) except (requests.Timeout, requests.ConnectionError): resp = None if resp is not None: if resp.status_code == 429 or resp.status_code >= 500: wait = resp.headers.get("Retry-After", "5") if wait.isascii() and wait.isdigit(): delay = max(5.0, int(wait)) else: resp.raise_for_status() creation = resp.json() if creation["status"] in ("completed", "failed"): return creation if delay >= deadline - time.monotonic(): break time.sleep(delay) # se acabó el tiempo: el id está guardado, el sondeo puede continuar más tarde raise TimeoutError(f"Still unresolved: {creation_id}")
const BASE = "https://api.rendergrid.io/ api/ public/ v1"; const KEY = process.env.RENDERGRID_API_KEY; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function waitFor(creationId, waitMs = 180_000) { const url = `${BASE}/creations/${creationId}`; const deadline = Date.now() + waitMs; while (Date.now() < deadline) { let delay = 5_000; let resp; try { const left = Math.min(20_000, deadline - Date.now()); resp = await fetch(url, { headers: { Authorization: `Bearer ${KEY}` }, signal: AbortSignal.timeout(Math.max(1, left)), }); } catch (error) { const network = error instanceof TypeError; if (!network && error.name !== "TimeoutError") throw error; } if (resp) { if (resp.status === 429 || resp.status >= 500) { const wait = resp.headers.get("Retry-After"); if (wait && /^[0-9]+$/.test(wait)) { delay = Math.max(delay, Number(wait) * 1_000); } } else { if (!resp.ok) { const text = await resp.text(); throw new Error(`HTTP ${resp.status}: ${text}`); } const creation = await resp.json(); if (["completed", "failed"].includes(creation.status)) { return creation; } } } if (delay >= deadline - Date.now()) break; await sleep(delay); } // se acabó el tiempo: el id está guardado, el sondeo puede continuar más tarde throw new Error(`Still unresolved: ${creationId}`); }
Archivos del resultado
Los archivos se conservan un día. Descarga la imagen a tu propio almacenamiento en cuanto recibas el enlace y, si la descarga falla de forma temporal, repite el intento. El sondeo no prolonga el plazo de conservación.
Que exista el registro de la tarea y un enlace en la respuesta no garantiza que el archivo siga disponible. El almacenamiento permanente es el tuyo.
En lugar de consultar, un webhook
Pasa webhook_url en la solicitud de generación y te avisaremos nosotros cuando la tarea pase a completed o failed. Deja el sondeo como vía de reserva: la notificación puede retrasarse o no llegar.
Preguntas frecuentes
¿Cuánto hay que esperar el resultado?
id y continúa más tarde.¿Qué hacer si la tarea pasa a failed?
failure.type y failure.code. El importe de una tarea así volvió al saldo automáticamente. Para un nuevo intento, envía una solicitud nueva con una clave de idempotencia nueva.¿Por qué mi id recibe un 404?
id y asegúrate de que la clave pertenece a la misma cuenta.