HiAPI
블로그

튜토리얼

hiapi API로 gpt-image-2/text-to-image 사용하는 방법: 파라미터, 코드 및 실행 가능한 예제

Jun 25, 2026
hiapi API로 gpt-image-2/text-to-image 사용하는 방법: 파라미터, 코드 및 실행 가능한 예제

이 튜토리얼은 hiapi 통합 작업 API를 통해 gpt-image-2/text-to-image로 이미지를 생성하는 데 필요한 최소한의 코드를 보여준 뒤, 각 파라미터를 하나씩 설명하고 코드가 정상 동작한 후 채택해야 할 프로덕션 수준의 패턴(콜백, 멱등성, 오류 처리)을 다룹니다.

사전 요구사항

API 키가 필요합니다. hiapi 콘솔의 API 키 페이지에서 생성하세요. 키는 sk-로 시작합니다. gpt-image-2/text-to-image의 모델 페이지에는 현재 이미지 한 장당 가격이 나와 있으며, 전체 내역은 가격 페이지에서 확인할 수 있습니다.

이 가이드의 모든 호출은 통합 비동기 작업 엔드포인트로 전송됩니다:

  • POST https://api.hiapi.ai/v1/tasks — 생성 작업 생성
  • GET https://api.hiapi.ai/v1/tasks/{taskId} — 작업 상태 폴링

플랫폼 공통 참조 문서는 hiapi API 문서에 있습니다.

최소 실행 예제(curl)

단일 생성은 두 단계 상호작용입니다. 먼저 작업을 생성한 다음 완료될 때까지 기다립니다.

# 1. Create the task
curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/text-to-image",
    "input": {
      "prompt": "a calico cat curled up on a sunlit windowsill, soft focus background",
      "aspect_ratio": "1:1",
      "resolution": "1K"
    }
  }'
# => {"code":200,"data":{"taskId":"tk-hiapi-01KVY...."},"message":"success"}

# 2. Poll until status == "success"
TASK_ID="tk-hiapi-01KVY...."
curl -s "https://api.hiapi.ai/v1/tasks/$TASK_ID" \
  -H "Authorization: Bearer sk-YOUR_KEY"
# => {"code":200,"data":{"status":"success","output":[{"url":"https://..."}], ...}}

이미지 URL은 data.output[0].url에 있습니다. 즉시 다운로드하세요. output[0].expireAt이 매우 짧기 때문에 이 URL은 가져오기용일 뿐 영구적으로 삽입하는 용도가 아닙니다.

Python: 생성 + 폴링 + 디스크에 저장

import os
import time
import urllib.request
import requests  # pip install requests

API_BASE = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"]  # sk-...

def create_task(prompt: str, aspect_ratio: str = "1:1", resolution: str = "1K") -> str:
    payload = {
        "model": "gpt-image-2/text-to-image",
        "input": {
            "prompt": prompt,
            "aspect_ratio": aspect_ratio,
            "resolution": resolution,
        },
    }
    r = requests.post(API_BASE, json=payload,
                      headers={"Authorization": f"Bearer {TOKEN}"},
                      timeout=60)
    r.raise_for_status()
    body = r.json()
    if body.get("error"):
        raise RuntimeError(f"create failed: {body['error']}")
    return body["data"]["taskId"]

def wait_task(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(f"{API_BASE}/{task_id}",
                         headers={"Authorization": f"Bearer {TOKEN}"},
                         timeout=30)
        r.raise_for_status()
        task = r.json().get("data") or {}
        status = task.get("status")
        if status == "success":
            return task
        if status == "fail":
            raise RuntimeError(f"task failed: {task.get('error')}")
        time.sleep(poll_s)
    raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")

if __name__ == "__main__":
    task_id = create_task(
        "a calico cat curled up on a sunlit windowsill, soft focus background",
        aspect_ratio="3:2",
        resolution="1K",
    )
    task = wait_task(task_id)
    url = task["output"][0]["url"]
    urllib.request.urlretrieve(url, "cat.png")
    print(f"saved cat.png from task {task_id}")

Node.js: fetch를 사용한 동일한 흐름

// Node 18+ has global fetch
const API_BASE = "https://api.hiapi.ai/v1/tasks";
const TOKEN = process.env.HIAPI_API_KEY;

async function createTask(prompt, aspectRatio = "1:1", resolution = "1K") {
  const res = await fetch(API_BASE, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-image-2/text-to-image",
      input: { prompt, aspect_ratio: aspectRatio, resolution },
    }),
  });
  const body = await res.json();
  if (body.error) throw new Error(`create failed: ${body.error.code} ${body.error.message}`);
  return body.data.taskId;
}

async function waitTask(taskId, { timeoutMs = 600_000, pollMs = 5_000 } = {}) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const res = await fetch(`${API_BASE}/${taskId}`, {
      headers: { "Authorization": `Bearer ${TOKEN}` },
    });
    const task = (await res.json()).data || {};
    if (task.status === "success") return task;
    if (task.status === "fail") throw new Error(`task failed: ${JSON.stringify(task.error)}`);
    await new Promise(r => setTimeout(r, pollMs));
  }
  throw new Error(`task ${taskId} timed out`);
}

(async () => {
  const id = await createTask(
    "a calico cat curled up on a sunlit windowsill, soft focus background",
    "16:9",
    "1K",
  );
  const task = await waitTask(id);
  const url = task.output[0].url;
  const img = await fetch(url).then(r => r.arrayBuffer());
  const { writeFileSync } = await import("node:fs");
  writeFileSync("cat.png", Buffer.from(img));
  console.log(`saved cat.png from task ${id}`);
})();

파라미터 참조

요청 본문에는 항상 두 개의 최상위 필드가 포함됩니다. model(문자열, 순수 모델 ID gpt-image-2/text-to-image)과 input(모델별 파라미터 객체)입니다.

input 필드 필수 여부 유형 설명
prompt 예 string 원하는 이미지에 대한 텍스트 설명입니다.
aspect_ratio 예 string 다음 중 하나: 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9 또는 auto.
resolution 아니오 string 1K(기본값), 2K 또는 4K. 픽셀 크기는 선택한 종횡비에 따라 조정됩니다.
callback 아니오 object { "url": "https://yours.example/hook", "when": "final" } — 다음 섹션을 참조하세요.

생성에 성공하면 {"code":200, "data":{"taskId":"tk-hiapi-..."}, "message":"success"}가 반환됩니다. GET /v1/tasks/{taskId}가 반환하는 data.status는 handling, success, fail 중 하나입니다. 성공 시 data.output은 배열이며, 첫 번째 요소에 이미지의 url과 expireAt 타임스탬프가 포함됩니다.

다른 hiapi 이미지 모델(예: z-image, qwen-image)은 다소 다른 input 필드를 사용합니다. aspect_ratio는 gpt-image-2/text-to-image가 채택한 규약입니다. 모델을 전환할 때는 모델 페이지에서 정확한 input 구조를 확인하세요.

프로덕션 수준 패턴

폴링 대신 콜백 사용

5초마다 폴링하는 것은 프로토타입 개발에는 문제없지만, 프로덕션 트래픽에서는 hiapi가 완료된 작업을 푸시하여 워커를 해제하기를 원할 것입니다. input에 callback 블록을 추가하세요:

{
  "model": "gpt-image-2/text-to-image",
  "input": {
    "prompt": "an astronaut sketching the moon",
    "aspect_ratio": "3:2",
    "resolution": "1K",
    "callback": {
      "url": "https://your-app.example.com/webhooks/hiapi",
      "when": "final"
    }
  }
}

when: "final"은 작업이 종료 상태(success 또는 fail)에 도달하면 한 번 트리거됩니다. 엔드포인트가 수신하는 페이로드 구조는 GET /v1/tasks/{id}와 동일하므로 핸들러는 폴링의 파싱 로직을 재사용할 수 있습니다. 콜백이 어떤 요청에 속하는지 알 수 있도록 작업 생성 시 저장한 taskId와 taskId를 대조하세요.

생성 작업을 멱등적으로 만들기

워커가 POST /v1/tasks 이후, taskId를 저장하기 전에 충돌하면 동일한 이미지를 두 번 생성할 수 있습니다. 저비용 해결책은 생성 응답을 받는 순간, 요청을 커밋하는 동일한 트랜잭션에서 (your_request_id → taskId)를 데이터베이스에 저장하는 것입니다. 워커가 재시도하면 새 작업을 생성하는 대신 기존 taskId를 찾아 폴링을 재개합니다.

인증 오류를 올바르게 처리

hiapi 인증 실패는 HTTP 200을 반환하고 응답 본문에 오류 페이로드를 포함합니다:

{"error":{"code":"permission_denied","message":"This API key cannot use the selected model. ...","type":"hiapi_error"}}

따라서 200 상태 코드만으로는 성공을 의미하지 않습니다. 항상 먼저 body.error를 확인하세요. 존재한다면 error.code(permission_denied, invalid_request 등)와 error.message를 살펴보세요. 메시지에 있는 request_id는 도움이 필요할 때 지원 티켓에 붙여넣는 값입니다.

즉시 다운로드하고 직접 재호스팅

data.output[0].url은 짧은 유효기간의 URL이며, 응답에 expireAt이 포함됩니다. hiapi의 URL을 제품의 <img src>에 직접 넣지 마세요. 작업이 성공하면 즉시 바이트 스트림을 다운로드하여 자체 스토리지(S3, R2, Supabase Storage 등)에 업로드한 뒤 그곳에서 서비스하세요.

합리적인 타임아웃 설정

합리적인 기본값은 POST 요청 타임아웃 60초(작업 생성은 빠르며, 실제로는 API가 수신을 확인하기를 기다리는 것뿐입니다), 폴링 루프 전체 예산 10분, 폴링 간격 5초입니다. 10분을 초과하는 작업은 거의 항상 작업이 조용히 fail 상태로 들어갔음을 의미하므로, 무한정 기다리는 것보다 타임아웃하고 로그에 마지막 작업 응답 본문을 출력하는 것이 더 유용합니다.

자주 묻는 질문

gpt-image-2와 gpt-image-2/text-to-image의 차이는 무엇인가요?

gpt-image-2는 모델 계열이고, gpt-image-2/text-to-image는 텍스트 프롬프트를 새 이미지로 변환하기 위해 호출하는 특정 엔드포인트입니다. 이 계열의 다른 변형은 서로 다른 input 구조를 노출합니다(예: 이미지 편집은 참조 이미지를 받습니다). 확실하지 않다면 모델 페이지에서 확인한 순수 모델 ID를 사용하세요.

aspect_ratio: auto는 어떤 역할을 하나요?

auto는 모델이 프롬프트에 따라 종횡비를 결정하게 합니다. 강한 레이아웃 요구사항이 없을 때 사용하세요. 그렇지 않으면 다운스트림 크롭을 예측 가능하게 하기 위해 비율을 직접 고정하세요.

왜 내 요청이 HTTP 200과 함께 permission_denied를 반환하나요?

API 키가 잘못되었거나(오타, 폐기됨, sk- 접두사 누락) 해당 키의 플랜에 gpt-image-2/text-to-image가 포함되지 않았기 때문입니다. API 키 콘솔을 열어 키 문자열을 확인하고, 가격 페이지에서 플랜을 확인하세요. 항상 body.error.code를 확인하고 HTTP 상태 코드만 믿지 마세요.

하나의 요청으로 여러 이미지를 생성할 수 있나요?

gpt-image-2/text-to-image는 작업당 이미지 한 장만 생성합니다. data.output은 배열이지만 이 모델에서는 길이가 항상 1입니다. N개의 변형을 생성하려면 N개의 작업을 동시에 시작하고 위의 callback 패턴을 사용하여 N개의 워커 스레드가 계속 대기하지 않도록 하세요.

실행 중인 작업을 취소하려면 어떻게 하나요?

통합 작업 API는 현재 취소 엔드포인트를 제공하지 않습니다. 가장 간단한 완화 방법은 사용자가 더 이상 결과를 필요로 하지 않을 때 클라이언트 워커가 결과를 폐기하도록 하는 것입니다. 이미 실행된 생성에는 여전히 과금이 되므로 취소를 강제하는 올바른 위치는 POST /v1/tasks를 호출하기 전입니다.

다른 이미지 모델로 전환하려면 어떻게 하나요?

model을 새 순수 ID(예: z-image/text-to-image)로 변경하고 해당 모델의 구조에 맞게 input을 조정하세요. 모델마다 구조가 완전히 같지는 않습니다. 일부는 size를, 일부는 aspect_ratio를 받으며, 소수는 resolution을 받지 않습니다. 모델 카탈로그에는 사용 가능한 모든 모델이 나열되어 있으며, 각 모델 페이지에 해당 input 필드가 문서화되어 있습니다.

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

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

API 문서 보기