Быстрый старт
Создайте API-ключ, отправьте первый запрос и скачайте результат — примерно за пять минут.
Эта страница проведёт вас от нуля до первого сгенерированного изображения: один ключ, один запрос. Всё остальное — видео, аудио, вебхуки, загрузка файлов — тот же запрос, только с другими model и input.
Что понадобится
- Аккаунт PopNow. Зарегистрируйтесь на popnow.ai. Бесплатные кредиты за регистрацию работают и в API; когда понадобится больше, купите пакет кредитов. Отдельного тарифа для API нет.
- Терминал с
curl. Примеры написаны для bash. В Windows используйте WSL или Git Bash.
1. Создайте API-ключ
Откройте API-консоль и нажмите Create key. Сразу скопируйте ключ: целиком он показывается только один раз. Затем положите его в переменную окружения, чтобы он никогда не попал в код:
export POPNOW_API_KEY="sk-popnow-..."Каждый ключ начинается с sk-popnow- и расходует кредиты вашего аккаунта. Храните его только на сервере; ограничения, ротация и что делать при утечке — в разделе Аутентификация.
2. Отправьте задачу
Вставьте это в тот же терминал. Запрос просит быструю модель нарисовать одно изображение и стоит один-два кредита:
export POPNOW_API_KEY="sk-popnow-..." # your key from the API console
curl -X POST "https://api.popnow.ai/api/v1/jobs/createTask?wait=60" \
-H "Authorization: Bearer $POPNOW_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"model": "alibaba/z-image-turbo/text-to-image",
"input": {
"prompt": "A small red fox curled up in a teacup, soft morning light, studio photo"
}
}'Что делает каждая часть:
model— ID модели: какая модель работает и над какой задачей. Все ID собраны на странице Модели.inputпроверяется по схеме входных данных этой модели. Неизвестные поля отклоняются, поэтому опечатка сразу даёт ошибку, а не тихо игнорируется.Idempotency-Keyделает повтор безопасным: отправьте тот же ключ после таймаута — и получите исходную задачу, а не второе списание. См. Идемпотентность.?wait=60держит соединение открытым до 60 секунд, и быстрое изображение приходит прямо в этом ответе.
3. Прочитайте результат
Завершённая задача выглядит так:
{
"code": 200,
"msg": "success",
"data": {
"taskId": "job_01JH8Z4Q5W2N7R3K9M6P1C0VXD",
"model": "alibaba/z-image-turbo/text-to-image",
"state": "succeeded",
"output": {
"assets": [
{
"url": "https://…signed-link…",
"expiresAt": "2026-10-16T09:20:00Z",
"mime": "image/png",
"width": 1024,
"height": 1024
}
]
},
"credits": 2,
"cost": "0.02",
"settled": true
},
"request_id": "req_…"
}stateравенsucceeded. Задача, которую не удалось выполнить, получаетfailedиerrorCode; см. Ошибки.output.assets[0].url— подписанная ссылка на файл. Она действует около 20 минут и не требует API-ключа; новую можно получить, просто прочитав задачу ещё раз.credits— сколько задача стоила в целых кредитах (1 кредит = 0,01 $),cost— та же сумма строкой в долларах США.
Если модели нужно больше 60 секунд (а видео-моделям нужно всегда), вместо этого придёт 202 с state: "queued" и taskId. Запрашивайте задачу, пока она не завершится:
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=job_..." \
-H "Authorization: Bearer $POPNOW_API_KEY"Проверяйте раз в несколько секунд, пока state не станет succeeded, failed или expired. В продакшене лучше передать callBackUrl и получать результат вебхуком.
Тот же запрос в коде
const API = 'https://api.popnow.ai/api/v1';
const headers = {
Authorization: `Bearer ${process.env.POPNOW_API_KEY}`,
'Content-Type': 'application/json',
};
const created = await fetch(`${API}/jobs/createTask`, {
method: 'POST',
headers: { ...headers, 'Idempotency-Key': crypto.randomUUID() },
body: JSON.stringify({
model: 'alibaba/z-image-turbo/text-to-image',
input: { prompt: 'A small red fox curled up in a teacup, soft morning light' },
}),
}).then((r) => r.json());
if (created.code !== 200) throw new Error(`${created.code} ${created.msg}`);
// Poll until the task reaches a final state.
let task;
do {
await new Promise((r) => setTimeout(r, 3000));
const res = await fetch(`${API}/jobs/recordInfo?taskId=${created.data.taskId}`, { headers });
task = (await res.json()).data;
} while (task.state === 'queued' || task.state === 'running');
console.log(task.state, task.output?.assets?.[0]?.url);import os, time, uuid, requests
API = "https://api.popnow.ai/api/v1"
headers = {"Authorization": f"Bearer {os.environ['POPNOW_API_KEY']}"}
created = requests.post(
f"{API}/jobs/createTask",
headers={**headers, "Idempotency-Key": str(uuid.uuid4())},
json={
"model": "alibaba/z-image-turbo/text-to-image",
"input": {"prompt": "A small red fox curled up in a teacup, soft morning light"},
},
timeout=30,
).json()
if created["code"] != 200:
raise RuntimeError(f'{created["code"]} {created["msg"]}')
# Poll until the task reaches a final state.
while True:
time.sleep(3)
task = requests.get(
f"{API}/jobs/recordInfo",
headers=headers,
params={"taskId": created["data"]["taskId"]},
timeout=30,
).json()["data"]
if task["state"] not in ("queued", "running"):
break
print(task["state"], task.get("output", {}).get("assets", [{}])[0].get("url"))Обёртка ответа
У каждого JSON-ответа одни и те же четыре поля:
{ "code": 200, "msg": "success", "data": { }, "request_id": "req_…" }code — бизнес-код, а не HTTP-статус: 200 означает успех, остальные значения перечислены в разделе Ошибки. Ветвитесь по code, а не по тексту msg. При обращении в поддержку указывайте request_id.

