API 레퍼런스

비동기 작업

이미지, 동영상, 음악 작업은 하나의 지속적인 수명 주기를 공유합니다. 한 번 제출하고, task_id를 저장하고, 최종 상태를 확인한 뒤 결과를 가져옵니다. 작업 실행기 하나를 만들고 모델별로 엔드포인트 분류만 고르세요.

#모든 비동기 모델에 하나의 수명 주기

  1. 1

    한 번만 제출

    고유한 Idempotency-Key를 사용하고 응답을 즉시 저장하세요.

    POST /v1/{capability}
  2. 2

    task_id 저장

    워커가 작업을 확인 처리하기 전에 저장하세요.

    task_id
  3. 3

    폴링 또는 웹훅 수신

    상태는 대소문자를 구분하지 않고 비교하며, 최종 상태에서 멈추세요.

    GET /{task_id}
  4. 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_STARTprocessingqueued아니요게이트웨이가 접수했으며 아직 채널로 전달되지 않았습니다.
SUBMITTEDqueuedqueued아니요업스트림으로 전송되어 제공업체가 확인했습니다.
QUEUEDqueuedqueued아니요제공업체 대기열에서 기다리는 중입니다.
IN_PROGRESSprocessingin_progress아니요생성 중입니다. progress에는 "60%" 같은 백분율 문자열이 담깁니다.
SUCCESSsucceededcompleted예완료되었습니다. /content에서 결과를 가져오세요.
FAILUREfailedfailed예최종 실패했습니다. fail_reason에 이유가 있으며, 사전 차감된 한도는 환불됩니다.
UNKNOWNunknownunknown아니요제공업체가 게이트웨이가 매핑할 수 있는 상태를 더 이상 보고하지 않습니다. 기한을 정해 폴링을 계속한 뒤 대조하세요 — 성공이나 실패로 처리하지 마세요.

“실행 중 아님”이 아니라 최종 상태 집합으로 판단

succeeded / completed와 failed만 멈추는 지점으로 보고, 나머지는 모두 — 이 표에 없는 값도 포함해 — 아직 실행 중으로 처리하세요. 새로운 중간 상태는 생길 수 있지만, 새 최종 상태는 호환성을 깨는 변경이므로 생기지 않습니다.

UNKNOWN은 실패가 아님

제공업체가 게이트웨이가 매핑할 수 있는 상태를 더 이상 보고하지 않으면 작업이 UNKNOWN에 머물 수 있습니다. 기한을 정해 폴링하고, 사람이나 대조 작업으로 넘기세요 — 실패로 처리하면 재시도로 이중 과금되고, 성공으로 처리하면 빈 결과를 내보내게 됩니다.

#안전한 폴링 루프

폴링하는 계열의 최종 상태 값에서 멈추고, 나머지 상태에는 실제 시간 기준 기한을 두며, 백오프를 적용해 멈춘 작업이 무한 루프가 되지 않게 하세요.

poll.py
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)

재시작 후 이어서 진행

task_id, 엔드포인트 분류, 모델, 생성 시각, 자체 비즈니스 식별자를 저장하세요. 재시작된 워커는 두 번째 작업을 제출해 과금하지 않고도 폴링을 이어 갈 수 있습니다.

#결과 보관

/content는 성공한 뒤에만 가져오세요. 반환된 플랫폼 URL을 비즈니스 레코드에 저장하고, 보관 요건상 별도 저장소가 필요하면 비공개 사본을 다운로드하세요.

아직 해결되지 않았나요?

요청 ID나 오류 메시지를 보내 주시면 확인해 드리겠습니다.