API 레퍼런스
비동기 작업
이미지, 동영상, 음악 작업은 하나의 지속적인 수명 주기를 공유합니다. 한 번 제출하고, task_id를 저장하고, 최종 상태를 확인한 뒤 결과를 가져옵니다. 작업 실행기 하나를 만들고 모델별로 엔드포인트 분류만 고르세요.
#모든 비동기 모델에 하나의 수명 주기
- 1
한 번만 제출
고유한 Idempotency-Key를 사용하고 응답을 즉시 저장하세요.
POST /v1/{capability} - 2
task_id 저장
워커가 작업을 확인 처리하기 전에 저장하세요.
task_id - 3
폴링 또는 웹훅 수신
상태는 대소문자를 구분하지 않고 비교하며, 최종 상태에서 멈추세요.
GET /{task_id} - 4
결과 가져와 저장
성공 후 /content를 호출하고 반환된 플랫폼 URL을 저장하세요.
GET /{task_id}/content
#엔드포인트 분류
| 기능 | 제출 | 폴링 | 결과물 |
|---|---|---|---|
| 이미지 | /v1/images/tasks | /v1/images/tasks/{task_id} | /v1/images/tasks/{task_id}/content |
| 동영상 | /v1/videos | /v1/videos/{task_id} | /v1/videos/{task_id}/content |
| 음악 | /v1/music/generations | /v1/music/tasks/{task_id} | /v1/music/tasks/{task_id}/content |
#상태 값
수명 주기는 하나지만 전송 용어는 두 가지입니다. 이미지, 음악, 3D 작업은 OpenAI 작업 용어로, 동영상과 모든 웹훅 페이로드는 OpenAI 동영상 용어로 상태를 보고합니다. 한쪽 계열용으로 작성한 상태 검사는 다른 쪽에서 아무 오류 없이 절대 일치하지 않습니다 — 이 표가 둘의 대응 관계입니다.
| 수명 주기 | 이미지 · 음악 · 3D | 동영상 · 웹훅 | 최종 | 의미 |
|---|---|---|---|---|
| NOT_START | processing | queued | 아니요 | 게이트웨이가 접수했으며 아직 채널로 전달되지 않았습니다. |
| SUBMITTED | queued | queued | 아니요 | 업스트림으로 전송되어 제공업체가 확인했습니다. |
| QUEUED | queued | queued | 아니요 | 제공업체 대기열에서 기다리는 중입니다. |
| IN_PROGRESS | processing | in_progress | 아니요 | 생성 중입니다. progress에는 "60%" 같은 백분율 문자열이 담깁니다. |
| SUCCESS | succeeded | completed | 예 | 완료되었습니다. /content에서 결과를 가져오세요. |
| FAILURE | failed | failed | 예 | 최종 실패했습니다. fail_reason에 이유가 있으며, 사전 차감된 한도는 환불됩니다. |
| UNKNOWN | unknown | unknown | 아니요 | 제공업체가 게이트웨이가 매핑할 수 있는 상태를 더 이상 보고하지 않습니다. 기한을 정해 폴링을 계속한 뒤 대조하세요 — 성공이나 실패로 처리하지 마세요. |
“실행 중 아님”이 아니라 최종 상태 집합으로 판단
UNKNOWN은 실패가 아님
#안전한 폴링 루프
폴링하는 계열의 최종 상태 값에서 멈추고, 나머지 상태에는 실제 시간 기준 기한을 두며, 백오프를 적용해 멈춘 작업이 무한 루프가 되지 않게 하세요.
import time, requests
# The two vocabularies. Pick the one that matches the endpoint you poll.
TASK_DONE, TASK_FAILED = {"succeeded"}, {"failed"} # images / music / 3D
VIDEO_DONE, VIDEO_FAILED = {"completed"}, {"failed"} # videos + webhooks
DEADLINE_SECONDS = 15 * 60
def wait_for_image_task(task_id, api_key):
started = time.monotonic()
delay = 2
while True:
response = requests.get(
f"https://www.aisplice.store/v1/images/tasks/{task_id}",
headers={"Authorization": f"Bearer {api_key}"},
timeout=30,
)
response.raise_for_status()
task = response.json()
status = task.get("status", "")
if status in TASK_DONE:
return task
if status in TASK_FAILED:
raise RuntimeError((task.get("error") or {}).get("message", "task failed"))
# queued / processing / unknown all mean "not finished". Wait — but
# never forever: hand an overdue task to reconciliation.
if time.monotonic() - started > DEADLINE_SECONDS:
raise TimeoutError(f"task {task_id} still {status} after the deadline")
time.sleep(delay)
delay = min(delay * 1.5, 15)재시작 후 이어서 진행
#결과 보관
/content는 성공한 뒤에만 가져오세요. 반환된 플랫폼 URL을 비즈니스 레코드에 저장하고, 보관 요건상 별도 저장소가 필요하면 비공개 사본을 다운로드하세요.
아직 해결되지 않았나요?
요청 ID나 오류 메시지를 보내 주시면 확인해 드리겠습니다.