작업
작업을 만들고 상태를 따라가며 결과를 읽는 방법, 그리고 wait, 작업 목록, 재시도, 삭제 사용법.
모든 생성은 하나의 작업입니다. 호출 한 번으로 만들면 알아서 진행되고, 결과가 준비되면 조회하거나, 첫 요청에서 기다리거나, 웹훅으로 받으면 됩니다.
POST /jobs/createTasktaskIdGET /jobs/recordInfostateGET output.assets[].url
작업 만들기
curl -X POST "https://api.popnow.ai/api/v1/jobs/createTask" \
-H "Authorization: Bearer $POPNOW_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"model": "alibaba/wan-3.0/image-to-video",
"input": {
"image_url": "https://media.popnow.ai/movie/lighthouse.webp",
"prompt": "Waves roll in slowly, the camera drifts toward the lighthouse",
"resolution": "480p",
"duration_seconds": 5
},
"callBackUrl": "https://your-app.example.com/hooks/popnow"
}'본문
| 필드 | 필수 | 의미 |
|---|---|---|
model | 예 | 모델의 모델 ID |
input | 예 | 해당 모델의 필드. 입력 스키마로 검증됩니다 |
callBackUrl | 아니요 | 완료된 작업을 받을 공개 HTTPS URL. 웹훅 참고 |
quoteId, expectedCredits | 아니요 | jobs/quote로 확인한 가격을 고정 |
헤더
| 헤더 | 의미 |
|---|---|
Authorization: Bearer sk-popnow-… | API 키 |
Idempotency-Key | 꼭 보내는 것을 권장합니다. 같은 키로 재시도하면 원래 작업이 돌아옵니다. 멱등성 참고 |
X-PopNow-Retention | 선택. 이 작업의 결과물과 프롬프트를 보관할 초 단위 시간. 보관 기간을 줄일 수만 있고 늘릴 수는 없습니다 |
Accept-Language | 선택. 오류 메시지 언어. 오류 참고 |
응답
새 작업은 HTTP 202로 돌아옵니다.
{
"code": 200,
"msg": "success",
"data": {
"taskId": "job_01JH8Z4Q5W2N7R3K9M6P1C0VXD",
"state": "queued",
"estimatedCredits": 34,
"estimatedCost": "0.34",
"deadlineAt": "2026-10-16T09:40:00Z"
},
"request_id": "req_…"
}202는 접수됐다는 뜻이지 끝났다는 뜻이 아닙니다. estimatedCredits는 잔액에서 잡아 둔 크레딧, 즉 이 작업이 쓸 수 있는 최대 금액입니다(estimatedCost는 같은 금액을 달러로 표시). 생성에 실패하면 아무것도 만들어지지 않고 잡아 두지도 않으며, 이유는 code로 알 수 있습니다(오류).
상태
queuedrunningsucceededfailedexpired| 상태 | 종료? | 의미 |
|---|---|---|
queued | 아니요 | 접수됨, 시작 대기 중 |
running | 아니요 | 생성 중 |
succeeded | 예 | 완료. 파일은 output.assets에 있습니다 |
failed | 예 | 끝내지 못함. errorCode와 errorMessage를 보세요. 잡아 둔 크레딧은 돌아옵니다 |
expired | 예 | 마감 시간까지 끝나지 않음. 잡아 둔 크레딧은 돌아옵니다 |
canceled | 예 | 예전 기록에만 나타납니다. 지금은 접수된 작업을 취소할 수 없습니다 |
모르는 상태가 오면 "아직 안 끝났다"고 보고 계속 조회하세요.
wait로 폴링 건너뛰기
createTask에 ?wait=<초>(최대 60)를 붙이면, 작업이 끝나거나 시간이 다 될 때까지 연결을 유지합니다.
- 시간 안에 끝남 → HTTP
200과 함께recordInfo와 같은 형태의 전체 작업 기록이 옵니다.data.state를 확인하세요. 종료가 항상 성공은 아닙니다. - 끝나지 않음 → 평소처럼
202가 오고, 폴링을 이어 가거나 웹훅을 기다리면 됩니다.
이미지와 짧은 오디오에 알맞고, 영상은 거의 항상 60초를 넘깁니다. 일찍 연결을 끊어도 작업은 멈추거나 취소되지 않습니다.
작업 읽기
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=job_01JH8Z4Q5W2N7R3K9M6P1C0VXD" \
-H "Authorization: Bearer $POPNOW_API_KEY"| 필드 | 의미 |
|---|---|
taskId, model, state | 어떤 작업, 어떤 모델, 어디까지 왔는지 |
input | 실제로 실행된 입력. seed를 생략했다면 선택된 값도 포함 |
output.assets[] | 결과 파일. 각각 url, expiresAt, mime과, 해당되면 width, height, durationSeconds, bytes, role이 있습니다 |
errorCode, errorMessage | 작업이 실패한 이유. 분기는 errorCode, 표시는 errorMessage |
credits, cost, settled | settled가 false인 동안 credits는 잡아 둔 금액이고, true가 되면 최종 청구액입니다. cost는 같은 금액의 달러 표시 |
createdAt, completedAt, deadlineAt | 타임스탬프. deadlineAt은 끝나지 않은 작업이 만료되는 시각 |
retention.outputsExpireAt | 이 작업의 파일이 삭제되는 시각 |
contentState | present. 내용이 지워지면 expired 또는 purged |
서로 다른 세 가지 만료 시각
deadlineAt: 작업이 실행될 수 있는 시간. 지나면expired가 되고 잡아 둔 크레딧이 돌아옵니다.output.assets[].expiresAt: 그 서명 링크 하나가 유효한 시간으로, 약 20분입니다. 작업을 다시 읽으면 새 링크가 나오고 파일 자체는 그대로 있습니다.retention.outputsExpireAt: 저장된 파일이 삭제되는 시각. 남기고 싶은 파일은 그 전에 내려받거나 에셋 라이브러리에 저장하세요.
output에 담기는 것
대부분의 작업은 파일 하나를 돌려줍니다. 여러 개를 돌려주는 경우도 있습니다. 변형을 여러 장 만드는 모델은 이미지 여러 장을, 영상 이어 만들기는 이어 붙인 전체 영상(role: "video")과 새로 만든 부분(role: "segment")을, 레이어 분리는 바탕 이미지와 투명 레이어(각각 layer 객체 포함)를 돌려줍니다. 음성-텍스트 변환 결과는 output.text에 있습니다.
결과 링크는 가진 사람이면 누구나 쓸 수 있는 링크입니다. 만료되기 전까지는 URL만 있으면 내려받을 수 있으니, 받을 때 API 키는 보내지 마세요.
웹훅을 기본으로, 폴링은 보조로
폴링도 되지만 웹훅이 양쪽 모두에게 더 싸게 먹힙니다. 결과가 나오는 즉시 알 수 있고 그사이 요청을 낭비하지 않습니다. 탄탄한 연동은 둘 다 씁니다. 평소에는 웹훅으로 받고, 가끔 recordInfo로 웹훅을 못 받은 작업을 훑어 줍니다.
폴링할 때는 간격을 두세요. 이미지는 23초, 영상은 1015초마다 확인하고 deadlineAt이 되면 멈춥니다.
작업 목록
GET /api/v1/jobs는 이 키로 만든 작업을 최신순으로 돌려주며, 입력과 결과는 담지 않습니다.
curl "https://api.popnow.ai/api/v1/jobs?state=failed&from=2026-10-01&limit=50" \
-H "Authorization: Bearer $POPNOW_API_KEY"필터: from과 to(UTC 날짜, 최대 92일 간격, 기본은 최근 7일), state, model, limit(최대 100). hasMore가 true이면 같은 필터로 nextCursor를 cursor에 넘기세요.
실패한 작업 재시도
POST /api/v1/jobs/retry에 { "taskId": "…" }를 보내면, failed 또는 expired 작업의 원래 입력으로 오늘 가격에 맞춰 새 작업을 만듭니다. 원래 작업은 바뀌지 않습니다. 원래 작업이 아직 끝나지 않았으면 409가 오고, 성공한 작업은 재시도할 수 없으니 새로 만드세요.
작업 내용 삭제
POST /api/v1/jobs/purge에 { "taskId": "…" }를 보내면 작업의 파일, 결과, 저장된 프롬프트를 지웁니다. 결제 기록은 남습니다. 청구액, 모델, 상태, 타임스탬프는 그대로이며 응답의 billingRetained: true가 이를 알려 줍니다. 종료된 작업만 지울 수 있고, 여러 번 호출해도 안전합니다.

