Avvio rapido
Crea una chiave API, invia la tua prima richiesta e scarica il risultato in circa cinque minuti.
Questa pagina ti porta da zero alla prima immagine generata, con una chiave e una richiesta. Tutto il resto — video, audio, webhook, caricamenti — è la stessa richiesta con un altro model e un altro input.
Prima di iniziare
- Un account PopNow. Registrati su popnow.ai. I crediti gratuiti dell’iscrizione valgono anche per l’API; quando te ne servono altri, acquista un pacchetto di crediti. Non esiste un piano API separato.
- Un terminale con
curl. Gli esempi usano bash. Su Windows usa WSL o Git Bash.
1. Crea una chiave API
Apri la console API e scegli Create key. Copia subito la chiave: il valore completo compare una volta sola. Poi mettila in una variabile d’ambiente, così non finisce mai nel codice:
export POPNOW_API_KEY="sk-popnow-..."Ogni chiave inizia con sk-popnow- e usa i crediti del tuo account. Tienila solo sul server; restrizioni, rotazione e cosa fare se trapela sono in Autenticazione.
2. Invia un’attività
Incolla questo nello stesso terminale. Chiede un’immagine a un modello veloce e costa uno o due crediti:
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"
}
}'Cosa fa ogni parte:
modelè l’ID del modello: quale modello gira e per quale compito. Trovi tutti gli ID in Modelli.inputviene validato con lo schema di input di quel modello. I campi sconosciuti vengono rifiutati, quindi un refuso dà subito errore invece di essere ignorato in silenzio.Idempotency-Keyrende sicuri i nuovi tentativi: se rimandi la stessa chiave dopo un timeout, ricevi l’attività originale invece di un secondo addebito. Vedi Idempotenza.?wait=60tiene aperta la connessione fino a 60 secondi, così un’immagine veloce torna in questa stessa risposta.
3. Leggi il risultato
Un’attività completata appare così:
{
"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. Un’attività che non è riuscita a terminare indicafailede riporta unerrorCode; vedi Errori.output.assets[0].urlè un link firmato al file. Funziona per circa 20 minuti, non richiede la chiave API e puoi ottenerne uno nuovo rileggendo l’attività.creditsè quanto è costata l’attività, in crediti interi (1 credito = 0,01 $);costriporta lo stesso importo come stringa in dollari USA.
Se il modello ha bisogno di più di 60 secondi — succede con tutti i modelli video —, la risposta è un 202 con state: "queued" e un taskId. Interroga l’attività finché non è conclusa:
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=job_..." \
-H "Authorization: Bearer $POPNOW_API_KEY"Controlla ogni pochi secondi finché state diventa succeeded, failed o expired. In produzione conviene passare una callBackUrl e farsi avvisare da un webhook.
La stessa richiesta nel codice
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"))L’involucro della risposta
Tutte le risposte JSON hanno gli stessi quattro campi:
{ "code": 200, "msg": "success", "data": { }, "request_id": "req_…" }code è un codice applicativo, non uno stato HTTP: 200 significa successo, tutti gli altri valori sono elencati in Errori. Decidi in base a code, mai al testo di msg. Indica il request_id quando contatti l’assistenza.

