开始使用
正文快速开始
创建 API 密钥、发出第一个请求、下载生成结果,大约五分钟。
这一页带你从零开始,用一个密钥、一个请求生成第一张图。之后的一切——视频、音频、Webhook、上传素材——都是同一个请求,只是换了 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会按这个模型自己的输入 schema 校验。不认识的字段直接拒绝,写错字段名会马上报错,而不是被悄悄忽略。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,让 Webhook 来通知你。
用代码发同一个请求
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。

