08Основы API
Задачи и статусы
Картинка делается в фоне. После приёма запроса у вас есть id задания: по нему можно спрашивать статус, пока не придёт completed или failed, или дождаться вебхука.
Спросить статус
/creations/{id}Подставьте id из ответа на запрос генерации. Задание видно только аккаунту, который его создал: чужой или неизвестный id даст 404 ERR_NOT_FOUND. Сохраняйте id у себя.
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+, файл .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());
Статусы
| Статус | Что значит | Что делать |
|---|---|---|
queued | Запрос принят и ждёт своей очереди | Ждите и спросите позже |
processing | Картинка рисуется | Ждите и спросите позже |
completed | Готово | Скачайте файлы по ссылкам из result_urls |
failed | Получить картинку не удалось | Прочитайте failure и решите, менять ли запрос |
completed и failed — конечные: опрос можно прекращать. Ответ 200 может нести status: "failed": это итог задания, а не ошибка самого запроса статуса.
Неудачный запрос бесплатен: сумма сразу возвращается на баланс.
Как выглядит ответ
Пока результата нет, в ответе только id и status. Остальные поля появляются в конце.
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "queued"
}
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "processing"
}Других полей пока нет. Спросите ещё раз через 5 секунд или больше.
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "completed",
"result_urls": [
"https:// cdn.rendergrid.io/ images/ example/ result.jpg"
]
}result_urls — готовые ссылки на файлы. Берите их как есть: не собирайте из id и не рассчитывайте на расширение файла.
{
"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 — текст для показа. Логику стройте по failure.type и failure.code: что они значат.
Попробуйте сами
Это учебная схема, запросов к API она не делает. Выберите исход и нажмите кнопку.
queuedЗапрос принят. Задание ждёт очереди.
processingКартинка рисуется.
completedГотово: в ответе есть result_urls.
Нажмите «Отправить запрос»: покажем, что вернёт GET /creations/ на каждом шаге.
Как часто спрашивать
Одно задание одним ключом — не чаще раза в 5 секунд. Более частый опрос получит 429 ERR_RATE_LIMIT: ждите не меньше, чем details.min_interval_seconds, и не меньше, чем 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 }
}
}- Прекращайте опрос на
completedиfailed. - При обрыве связи,
429и5xxповторяйте с паузой и учитывайтеRetry-After. - Ограничьте общее время ожидания. Если оно вышло, сохраните
idи продолжите позже: тайм-аут вашего клиента задание не отменяет. - Если опрашивают несколько процессов, согласуйте между ними общий интервал.
Пример цикла ожидания. Время ожидания в нём — настройка примера, а не срок работы модели.
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) # секунд: подключение, чтение 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) # время вышло: id сохранён, опрос можно продолжить позже 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); } // время вышло: id сохранён, опрос можно продолжить позже throw new Error(`Still unresolved: ${creationId}`); }
Файлы результата
Файлы хранятся сутки. Скачайте картинку в своё хранилище сразу, как получили ссылку, а при временной ошибке скачивания повторите попытку. Опрос срок хранения не продлевает.
Запись о задании и ссылка в ответе не гарантируют, что файл ещё доступен. Постоянное хранилище — ваше.
Вместо опроса — вебхук
Передайте webhook_url в запросе генерации — мы сами сообщим, когда задание стало completed или failed. Опрос оставьте запасным путём: уведомление может задержаться или не дойти.
Частые вопросы
Сколько ждать результат?
id и продолжите позже.Что делать, если задание стало failed?
failure.type и failure.code. Сумма за такое задание вернулась на баланс автоматически. Для новой попытки отправьте новый запрос с новым ключом повтора.Почему на мой id приходит 404?
id и убедитесь, что ключ принадлежит тому же аккаунту.