Schnellstart
API-Schlüssel erstellen, die erste Anfrage senden und das Ergebnis herunterladen – in etwa fünf Minuten.
Diese Seite bringt dich mit einem Schlüssel und einer Anfrage zu deinem ersten generierten Bild. Alles Weitere – Video, Audio, Webhooks, Uploads – ist dieselbe Anfrage mit anderem model und anderem input.
Bevor du loslegst
- Ein PopNow-Konto. Registriere dich auf popnow.ai. Die Gratis-Credits zur Anmeldung funktionieren auch mit der API; wenn du mehr brauchst, kaufst du ein Credit-Paket. Einen eigenen API-Tarif gibt es nicht.
- Ein Terminal mit
curl. Die Beispiele nutzen bash. Unter Windows nimm WSL oder Git Bash.
1. API-Schlüssel erstellen
Öffne die API-Konsole und wähle Create key. Kopiere den Schlüssel sofort – der vollständige Wert wird nur einmal angezeigt. Leg ihn dann in eine Umgebungsvariable, damit er nie im Code landet:
export POPNOW_API_KEY="sk-popnow-..."Jeder Schlüssel beginnt mit sk-popnow- und verbraucht die Credits deines Kontos. Bewahre ihn nur auf deinem Server auf; Einschränkungen, Rotation und was bei einem Leck zu tun ist, steht unter Authentifizierung.
2. Einen Task senden
Füge das in dasselbe Terminal ein. Es bittet ein schnelles Bildmodell um ein Bild und kostet ein, zwei Credits:
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"
}
}'Was die einzelnen Teile tun:
modelist die Modell-ID – welches Modell läuft und welche Aufgabe es erledigt. Alle IDs findest du unter Modelle.inputwird gegen das Eingabeschema genau dieses Modells geprüft. Unbekannte Felder werden abgelehnt, ein Tippfehler fällt also sofort auf, statt still ignoriert zu werden.Idempotency-Keymacht Wiederholungen sicher: Schickst du nach einem Timeout denselben Schlüssel noch einmal, bekommst du den ursprünglichen Task zurück statt einer zweiten Abbuchung. Siehe Idempotenz.?wait=60hält die Verbindung bis zu 60 Sekunden offen, sodass ein schnelles Bild direkt in dieser Antwort zurückkommt.
3. Ergebnis lesen
Ein fertiger Task sieht so aus:
{
"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_…"
}stateistsucceeded. Ein Task, der nicht fertig werden konnte, steht auffailedund trägt einenerrorCode; siehe Fehler.output.assets[0].urlist ein signierter Link zur Datei. Er gilt etwa 20 Minuten, braucht keinen API-Schlüssel, und einen frischen bekommst du jederzeit, indem du den Task erneut liest.creditsist das, was der Task tatsächlich gekostet hat, in ganzen Credits (1 Credit = 0,01 $).costenthält denselben Betrag als US-Dollar-String.
Braucht das Modell länger als 60 Sekunden – bei Videomodellen immer –, kommt stattdessen ein 202 mit state: "queued" und einer taskId. Frag den Task ab, bis er fertig ist:
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=job_..." \
-H "Authorization: Bearer $POPNOW_API_KEY"Prüfe alle paar Sekunden, bis state auf succeeded, failed oder expired steht. In Produktion übergibst du besser eine callBackUrl und lässt dich per Webhook benachrichtigen.
Dieselbe Anfrage im Code
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"))Die Antworthülle
Jede JSON-Antwort hat dieselben vier Felder:
{ "code": 200, "msg": "success", "data": { }, "request_id": "req_…" }code ist ein Geschäftscode, kein HTTP-Status: 200 heißt Erfolg, alles andere steht unter Fehler. Verzweige nach code, nie nach dem Wortlaut von msg. Gib beim Support die request_id an.

