빠른 시작
API 키를 만들고, 첫 요청을 보내고, 결과를 내려받기까지 약 5분이면 됩니다.
이 페이지는 키 하나와 요청 하나로 첫 이미지를 만드는 데까지 안내합니다. 그다음의 영상, 오디오, 웹훅, 파일 업로드도 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. 작업 보내기
같은 터미널에 아래 내용을 붙여 넣으세요. 빠른 이미지 모델에 한 장을 요청하며, 비용은 1~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를 함께 보내 주세요.

