HiAPI
블로그

튜토리얼

HiAPI 작업 출력 URL 만료(expireAt): 만료 전에 다운로드하고 결과를 이전하세요

종료 상태의 output[].url에는 expireAt이 붙어 있고 만료되면 404가 됩니다—어떻게 판단하고, 제때 다운로드하며, 만료 후 어떻게 복구할지 정리합니다.

Oct 22, 2026
HiAPI 작업 출력 URL 만료(expireAt): 만료 전에 다운로드하고 결과를 이전하세요

POST /v1/tasks로 이미지나 영상을 생성하면 작업이 끝난 뒤 data.output[0].url에서 temp.hiapi.ai 링크를 받게 됩니다. 그때는 열리지만 며칠 뒤 다시 접속하면 HTML「Not Found」페이지로 바뀝니다:

HTTP/2 404
content-type: text/html

반환되는 것은 이미지/영상 바이트가 아니라 Cloudflare의 404 페이지입니다. 원인은 단 하나: 작업 출력 URL은 유효기간이 있는 임시 링크이며, 종료 상태의 expireAt(Unix 타임스탬프)이 되면 temp.hiapi.ai의 객체가 정리되어 핫링크가失效합니다.

먼저 종료 상태의 필드를 이해하기

작업 종료 상태(GET /v1/tasks/{taskId})가 성공했을 때의 주요 필드는 다음과 같습니다:

{
  "code": 200,
  "data": {
    "taskId": "tk-hiapi-xxxxxxxx",
    "status": "success",
    "storage": "temp",
    "created": 1791828181,
    "completed": 1791828201,
    "output": [
      {
        "artifactId": "...",
        "type": "image",
        "url": "https://temp.hiapi.ai/....png",
        "expireAt": 1792432981
      }
    ]
  },
  "message": "success"
}
  • data.status == "success"여야 종료 상태 성공입니다(실패는 "fail", 대기/처리 중은 queued / handling / archiving).
  • data.output은 배열이며, 각 요소에 자체 url과 expireAt이 있습니다.
  • expireAt은 Unix 정수 타임스탬프입니다(ISO 문자열 아님). 만료 여부는 이것만 보면 됩니다: now >= expireAt이면 만료.
  • data.storage의 값은 "temp"입니다—이 자체가 힌트입니다: 임시 저장소이며 장기 참조용이 아닙니다.

유효기간은 얼마나 될까요? 한 샘플을 측정해 보니 expireAt - completed = 604800초(정확히 7일)였습니다. 하지만 「7일」을 코드에 하드코딩하지 마세요—각 출력의 expireAt을 기준으로 하며, 모델/저장 정책에 따라 다를 수 있습니다.

흔한 원인(발생 확률 순)

  1. 핫링크를 데이터베이스에 장기 참조로 저장: 저장 시 temp.hiapi.ai/...라는 임시 URL을 넣어 두면 expireAt이 지나면 일괄 404가 됩니다. 가장 흔한 함정입니다.
  2. 종료 상태를 받고 즉시 다운로드하지 않음: 작업이 끝난 뒤 한참(TTL 초과) 지나서야 바이트를 가져옴.
  3. 다시 폴링하면 링크가 「갱신」된다고 생각: 같은 taskId로 다시 GET해도 반환되는 것은 같은 url과 같은 expireAt입니다—메타데이터는 영속되지만 객체 자체는 만료 후 재생성되지 않으며, 다시 GET해도 새 링크를 주지 않습니다.
  4. 404를 작업 실패로 오인: 작업은 이미 오래전에 success였고 출력 자산만 만료된 것일 뿐, 이는 별개의 문제입니다.

복구 단계

  1. 종료 상태가 오면 즉시 바이트를 다운로드하세요. 폴링에서 data.status == "success"를 확인한 후, 곧바로 각 output[].url에 GET을 보내 바이너리를 받아오세요. 대기시키거나 미루지 마세요.
  2. 자신의 객체 스토리지로 이전하세요(R2 / S3 / 로컬 디스크). 그리고 자신의 영속 URL로 바꾸세요.
  3. 데이터베이스에는 자신의 영속 URL만 저장하고, temp.hiapi.ai 핫링크는 절대 저장하지 마세요.
  4. 다운로드 전에 만료되지 않았는지 확인: now < expireAt일 때만 다운로드하고, 이미 만료됐다면 재실행 로직으로 넘어가세요.
  5. 만료되면 작업을 다시 실행하는 수밖에 없습니다. 「taskId로 새 링크를 받는」 방법은 없습니다—같은 taskId로 다시 GET해도 받는 것은 그 만료된 url입니다. 다운로드 가능한 결과를 다시 얻으려면 작업을 다시 제출해야 합니다(재과금).
  6. 배치 작업의 다운로드 순서를 제어하세요: 한 배치에서 가장 먼저 완료된 항목의 expireAt도 가장 먼저 만료됩니다. 완료 순서대로 즉시 다운로드하고, 배치 전체가 끝날 때까지 기다렸다가 일괄 다운로드하지 마세요. 그러면 먼저 완료된 항목이 만료에 임박할 수 있습니다.

최소 검증 예시

키가 통하는지, 작업 API가 결과를 내는지, expireAt을 직접 확인하세요. model id는 맨 id를 사용하세요(z-image, /text-to-image 같은 접미사를 붙이면 400이 납니다):

# 1. 작업 제출
curl -s https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "z-image",
    "input": { "prompt": "a red apple on a wooden table" }
  }'
# → {"code":200,"data":{"taskId":"tk-hiapi-..."},"message":"success"}

# 2. 이전 단계의 taskId로 종료 상태를 폴링하여 url과 expireAt 읽기
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-xxxx \
  -H "Authorization: Bearer $HIAPI_API_KEY"
# data.status가 "success"로 바뀌면 data.output[0].url / .expireAt이 생깁니다

인증이 실패하면 HTTP 401 + {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}}가 반환됩니다—이는 키 문제이지 만료 문제가 아닙니다. 작업을 찾을 수 없으면 {"code":404,"data":null,"message":"task not found"}입니다—보통 taskId를 잘못 적었거나 다른 환경의 키를 사용한 경우입니다.

관련 링크

FAQ

질문: expireAt은 정확히 어떤 형식인가요? 답변: Unix 정수 타임스탬프(초)입니다. 예를 들어 1792432981이며 ISO 문자열이 아닙니다. now >= expireAt으로 만료를 판단하면 됩니다.

질문: 링크가 만료된 후 작업을 다시 GET해서 링크를 「연장」할 수 있나요? 답변: 안 됩니다. 같은 taskId로 다시 GET해도 받는 것은 그 원본 url과 원본 expireAt이며 객체는 이미 정리되었습니다. 다운로드 가능한 결과를 다시 얻으려면 작업을 다시 실행해야 합니다(재과금).

질문: 만료 후 접근하면 403인가요, 404인가요? 답변: HTTP 404이며, body는 text/html의 Cloudflare「Not Found」페이지입니다. 이미지 바이트도 아니고 XML의 AccessDenied도 아닙니다. 다운로드 로직이 200만 인정한다면 「비200은 모두 실패로 처리」하도록 하세요.

질문: 유효기간은 고정 7일인가요? 답변: 측정 샘플은 7일(604800초)이었지만, 각 출력의 expireAt을 기준으로 하세요. 코드에 일수를 하드코딩하지 마세요.

질문: 배치 작업은 어떻게 다운로드하는 것이 가장 안정적일까요? 답변: 완료 순서대로, 먼저 success된 항목의 바이트를 먼저 받으세요. 가장 먼저 완료된 출력의 expireAt도 가장 먼저 만료되므로, 마지막까지 미뤘다가 일괄 다운로드하면 만료에 임박하기 쉽습니다.

영구 AI 아티팩트로 빌드 시작하기

API 키를 받아 태스크 기반의 하나의 API로 이미지, 비디오, 오디오 모델을 호출하세요.

API 문서 보기