Qwen-ImageAPI 레퍼런스
코드에서 Qwen-Image 모델로 이미지를 생성하고 편집하세요. 세 단계 빠른 시작, 모든 필드, 이미지당 크레딧, 웹훅과 멱등성을 다룹니다.
개발자 API는 신청제입니다.
이미지 API는 베타이며 필드는 바뀔 수 있습니다. 스튜디오에는 영향이 없습니다.
빠른 시작호출 세 번이면 됩니다
키를 설정하고, 가격 상한을 걸어 작업을 보낸 다음, 결과를 읽으세요.
- 01
키 설정
개발자 API는 신청제입니다. 스튜디오의 API 키 메뉴에서 신청하세요. 키는 한 번만 표시되므로 환경 변수에 보관하세요.
export API_KEY="sk_test_…" - 02
작업 보내기
Idempotency-Key와 max_credits 상한을 넣어 이미지를 POST 요청으로 보내세요. 편집 모델은 image_url도 받습니다. 202와 대기 중인 작업을 받으며, 크레딧이 보류됩니다.
curl https://api.pershot.app/v1/images/generations \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen-image-2512", "prompt": "A ceramic mug on a walnut table, soft window light, product photo", "size": "1K", "aspect_ratio": "1:1", "max_credits": 2 }'{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "image", "status": "queued", "money_status": "reserved", "queue_position": 2, "requested_model": "qwen-image-2512", "credits_quoted": 2, "credits_charged": null } - 03
결과 읽기
status가 succeeded가 될 때까지 작업을 GET으로 조회하세요. outputs[].url은 서명된 링크이며 24시간 후 만료되므로, 보관할 파일은 다운로드하세요.
curl https://api.pershot.app/v1/jobs/job_01J9ZK4T8W \ -H "Authorization: Bearer $API_KEY"
파라미터와한도
API가 검증에 사용하는 것과 같은 스키마로 생성된 OpenAPI 문서에서 읽어 옵니다. 알 수 없는 필드는 거부됩니다.
| 필드 | 유형 | 허용 값 | 참고 |
|---|---|---|---|
model필수 | string | qwen-image-2512-lightning · qwen-image-2512 · qwen-image-edit-2511-lightning · qwen-image-edit-2511 | 모델 ID. |
prompt필수 | string | 2–2,000자 | 생성할 내용: 피사체, 카메라, 조명. |
size기본값 "1K" | string | 1K · 2K | 초안과 첫 프레임에는 1K, 디테일에는 2K. |
aspect_ratio기본값 "1:1" | string | 16:9 · 9:16 · 1:1 | 프레임 형태. |
image_url선택 | string | https URL | 동영상의 첫 프레임, 편집 모델의 원본 이미지. 공개 https URL 또는 업로드 URL. |
seed선택 | integer | 0–2,147,483,647 | 같은 입력으로 결과를 재현합니다. |
quote_id선택 | string | qt_… | POST /v1/quotes에서 받은 견적으로 실행하며, 견적은 10분 동안 유효합니다. |
max_credits선택 | number | > 0 | 이 작업에 들 수 있는 최대 비용. 이를 넘으면 작업은 거부되며, 절대 청구되지 않습니다. |
webhook_url선택 | string | https URL | 작업 이벤트를 받는 https URL. |
end_user_id선택 | string | 1–128자 | 승인된 개발자 계정용(신청제): 이 요청에 붙이는 내 사용자 ID로, 사용량에 표시됩니다. |
project_id선택 | string | prj_… | |
shot_id선택 | string | sht_… | |
routing_preference선택 | string | stability · speed |
quote_id와 max_credits 중 정확히 하나만 보내세요. 이 엔드포인트는 model "auto"를 받지 않습니다. 동영상은 먼저 POST /v1/auto/plan을 호출한 뒤, 선택된 모델을 max_credits와 함께 보내세요.
- 모델
qwen-image-2512-lightning생성 · Qwen-Image-2512 · Lightning 4-stepqwen-image-edit-2511-lightning편집 · Qwen-Image-Edit-2511 · Lightningqwen-image-2512생성 · Qwen-Image-2512qwen-image-edit-2511편집 · Qwen-Image-Edit-2511- 요청 속도와 동시 실행
- 키당 분당 60회 요청, 계정당 기본 동시 작업 3개. 키를 늘려도 동시 실행 수는 늘어나지 않습니다.
- AI 에이전트용
- AI 에이전트용 텍스트: 입력, 허용 값, 설정별 가격, 요청 예시
qwen-image-2512-lightningqwen-image-2512qwen-image-edit-2511-lightningqwen-image-edit-2511
한도
API가 검사하는 것과 같은 표에서 읽어 옵니다. 각 행에는 누가 한도를 검사하는지, 한도를 넘으면 어떻게 되는지가 나와 있습니다.
- 강제 적용당사가 검사하며, 견적이나 보류 전에 400으로 응답합니다.
- 공급사공급업체가 검사합니다. 공급업체가 거부한 작업은 실패하며, 비용은 청구되지 않습니다.
- 권장아무도 검사하지 않습니다. 범위 안에 머물면 더 좋은 결과를 얻을 수 있습니다.
| 한도 | 값 | 단위 | 검사 주체 | 한도 초과 시 |
|---|---|---|---|---|
| 요청 | ||||
프롬프트 길이prompt | 2~2,000 | 문자 | 강제 적용 | 견적이나 보류 전에 prompt에 대해 400 invalid_request를 반환합니다. |
이미지 크기size | 1K, 2K기본값 1K | – | 강제 적용 | size에 대해 400 invalid_request를 반환합니다. |
화면 비율aspect_ratio | 16:9, 9:16, 1:1기본값 1:1 | – | 강제 적용 | aspect_ratio에 대해 400 invalid_request를 반환합니다. |
| 보내는 이미지 | ||||
원본 이미지image_url | 없음 | – | 강제 적용 | 편집 모델은 image_url이 필요하고 생성 모델은 이를 거부합니다. image_url에 대해 400 invalid_request를 반환합니다. |
| 출력 | ||||
| 출력 픽셀 | 1K16:91344×7689:16768×13441:11024×10242K16:92048×11529:161152×20481:12048×2048 | px | 강제 적용 | 정확히 이 크기로 요청합니다. |
| 출력 변 길이 | 256~2,048 | 변당 px | 공급사 | 위의 모든 크기가 범위 안에 들어갑니다. 더 큰 크기는 공급업체가 거부합니다. |
| 출력 형식 | JPEG | – | 강제 적용 | 모든 이미지는 JPEG입니다. |
| 링크 | ||||
| 출력 링크 | 24 | 시간 | 강제 적용 | 그 이후에는 링크가 403으로 응답합니다. 작업을 다시 GET하면 새 링크를 받을 수 있습니다. 파일 자체는 12개월 동안 보관되며(날짜는 작업의 outputs_expire_at), 에셋에 저장했거나 프로젝트에 사용 중인 결과물은 더 오래 보관됩니다. |
| 한도 | 값 | 단위 | 검사 주체 | 한도 초과 시 |
|---|---|---|---|---|
| 요청 | ||||
프롬프트 길이prompt | 2~2,000 | 문자 | 강제 적용 | 견적이나 보류 전에 prompt에 대해 400 invalid_request를 반환합니다. |
이미지 크기size | 1K, 2K기본값 1K | – | 강제 적용 | size에 대해 400 invalid_request를 반환합니다. |
화면 비율aspect_ratio | 16:9, 9:16, 1:1기본값 1:1 | – | 강제 적용 | aspect_ratio에 대해 400 invalid_request를 반환합니다. |
| 보내는 이미지 | ||||
원본 이미지image_url | 정확히 1개 | – | 강제 적용 | 편집 모델은 image_url이 필요하고 생성 모델은 이를 거부합니다. image_url에 대해 400 invalid_request를 반환합니다. |
업로드 크기file | 최대 10 | MB | 강제 적용 | POST /v1/uploads가 file에 대해 400 invalid_request로 응답합니다. |
업로드 형식file | JPEG, PNG, WebP | – | 강제 적용 | 파일 이름이 아니라 파일 자체에서 형식을 읽습니다. 그 밖의 형식은 file에 대해 400 invalid_request를 반환합니다. |
| 출력 | ||||
| 출력 픽셀 | 1K16:91344×7689:16768×13441:11024×10242K16:92048×11529:161152×20481:12048×2048 | px | 강제 적용 | 정확히 이 크기로 요청합니다. |
| 출력 변 길이 | 512~2,048 | 변당 px | 공급사 | 위의 모든 크기가 범위 안에 들어갑니다. 더 큰 크기는 공급업체가 거부합니다. |
| 출력 형식 | JPEG | – | 강제 적용 | 모든 이미지는 JPEG입니다. |
| 링크 | ||||
| 업로드 링크 | 7 | 일 | 강제 적용 | 그 이후에는 링크가 403으로 응답합니다. 파일을 다시 업로드하세요. |
| 출력 링크 | 24 | 시간 | 강제 적용 | 그 이후에는 링크가 403으로 응답합니다. 작업을 다시 GET하면 새 링크를 받을 수 있습니다. 파일 자체는 12개월 동안 보관되며(날짜는 작업의 outputs_expire_at), 에셋에 저장했거나 프로젝트에 사용 중인 결과물은 더 오래 보관됩니다. |
당사는 다른 호스트의 이미지를 가져오지 않으므로, 그런 링크의 크기는 공급업체가 검사합니다. 공급업체가 거부한 작업에는 비용이 청구되지 않습니다. 같은 한도가 JSON으로도 반환됩니다. GET /v1/models는 모든 모델에 대해 limits 객체를 반환합니다.
요금계산 과정까지 공개합니다
모델과 크기에 따라 이미지 1장당 하나의 가격이 크레딧으로 정해집니다(US$1 = 100 크레딧). 생성과 편집은 가격이 따로 매겨집니다.
| 모델 | 1K | 2K |
|---|---|---|
qwen-image-2512-lightning생성 | 1 크레딧≈ $0.01$10당 이미지 약 1,000장 | 3 크레딧≈ $0.03$10당 이미지 약 333장 |
qwen-image-edit-2511-lightning편집 | 2 크레딧≈ $0.02$10당 이미지 약 500장 | 4 크레딧≈ $0.04$10당 이미지 약 250장 |
qwen-image-2512생성 | 2 크레딧≈ $0.02$10당 이미지 약 500장 | 6 크레딧≈ $0.06$10당 이미지 약 166장 |
qwen-image-edit-2511편집 | 3 크레딧≈ $0.03$10당 이미지 약 333장 | 10 크레딧≈ $0.10$10당 이미지 약 100장 |
웹훅과멱등성
재시도해도 두 번 청구되지 않으며, 폴링할 필요가 없습니다.
- 멱등성
- 모든 생성 POST 요청에는 Idempotency-Key(눈에 보이는 ASCII 문자 1~255자)가 필요합니다. 24시간 이내에 같은 키로 요청하면 HTTP 200과 함께 같은 작업이 반환되므로, 시간 초과 후 재시도해도 두 번째 작업이 생성되거나 청구되지 않습니다.
- 거부된 프롬프트
- 사전 검사에서 거부된 프롬프트(422 content_rejected)는 아무것도 생성하지 않으므로, 같은 키를 새 프롬프트와 함께 다시 사용할 수 있습니다.
- 이벤트
job.queuedjob.processingjob.succeededjob.failedjob.cancelled- 서명
- X-Signature에는 유닉스 시간인 t와, t, 마침표, 원본 본문을 이어 붙인 값을 whsec_ 시크릿으로 계산한 HMAC-SHA256인 v1이 담깁니다. 5분보다 오래된 타임스탬프는 거부하고, X-Event-Id로 중복을 제거하세요.
- 전송
- 10초 이내에 2xx로 응답하면 전송된 것으로 간주합니다. 전송에 실패하면 1분, 5분, 30분, 2시간, 6시간 후에 재시도합니다. 리디렉션은 따르지 않습니다.
{
"id": "evt_01J9ZKB1QX",
"type": "job.succeeded",
"created_at": "2026-09-29T14:02:31Z",
"data": {
"job": {
"id": "job_01J9ZK4T8W",
"object": "job",
"kind": "image",
"status": "succeeded",
"money_status": "settled",
"requested_model": "qwen-image-2512",
"credits_charged": 2,
"outputs": [
{
"kind": "image",
"url": "https://…/job_01J9ZK4T8W.png?sig=…"
}
]
}
}
}import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received, before any JSON parsing.
export function verifyWebhook(header, rawBody, secret, toleranceSec = 300) {
let t = null;
const signatures = [];
for (const item of (header ?? "").split(",")) {
const [key, value] = item.split("=", 2);
if (key === "t") t = Number(value);
if (key === "v1") signatures.push(Buffer.from(value, "hex"));
}
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
return signatures.some((s) => s.length === expected.length && timingSafeEqual(s, expected));
}
// verifyWebhook(req.headers["x-signature"], rawBody, process.env.WEBHOOK_SECRET)
// Answer 2xx quickly, and skip an X-Event-Id you have already handled.오류와대처 방법
모든 오류는 code, message, param, request_id가 담긴 error 객체라는 같은 형태를 가집니다. 가장 자주 만나게 될 오류는 다음과 같습니다:
| 코드 | HTTP | 대처 방법 |
|---|---|---|
invalid_request | 400 | param에 표시된 필드를 수정하세요. |
unauthorized | 401 | 키와 Bearer 헤더를 확인하세요. |
insufficient_credits | 402 | 충전한 뒤 같은 Idempotency-Key로 재시도하세요. |
forbidden_model | 403 | 스튜디오에서 키의 허용 목록에 모델이나 도구를 추가하거나, 다른 키를 사용하세요. 화질 향상 같은 도구는 별도로 추가해야 합니다. |
quote_expired | 409 | 새 견적을 받으세요. 견적은 10분 동안 유효합니다. |
price_changed | 409 | 가격이 상한보다 올랐습니다. 다시 견적을 받거나 max_credits를 높이세요. |
content_rejected | 422 | 청구된 금액은 없습니다. 프롬프트나 이미지를 바꾸세요. |
rate_limited | 429 | Retry-After만큼 기다린 뒤 재시도하세요. |
upstream_unavailable | 503 | 모델을 이용할 수 없습니다. 나중에 다시 시도하세요. 시작되지 않은 작업은 청구되지 않습니다. |