블로그/developers·2026년 10월 8일·6분·eroq 팀 작성
GPT Image, Nano Banana, Seedream API: 엔드포인트 하나
GPT Image 2.5, Nano Banana Pro, Seedream 5.0 Pro, Flux 3를 eroq 엔드포인트 하나로 호출하는 방법을 curl과 JS로 설명해요.
이미지 생성 업체가 다섯 곳이면 보통 SDK도 다섯 개, 키도 다섯 개, 결제 대시보드도 다섯 개, 그리고 "비동기"에 대한 생각도 다섯 가지가 돼요. eroq에서는 엔드포인트가 하나이고 바뀌는 건 model뿐이에요. OpenAI의 GPT Image 2.5, Google의 Nano Banana, ByteDance의 Seedream, Black Forest Labs의 Flux 3, xAI의 Grok Imagine 2.0이 모두 POST /v1/images/generations를 거치고, 같은 본문, 같은 비동기 방식, 테이크당 정액 크레딧 가격으로 동작해요. 스튜디오와 같은 엔진, 가격, 정책이에요. 레퍼런스는 /docs/images에 있고, 이 글은 그 실전 버전이에요.
모델 ID
| 모델 | model ID |
제작사 | 테이크당 크레딧 | 일반적인 렌더 시간 |
|---|---|---|---|---|
| GPT Image 2.5 Sunburst | gpt-image-2-5-sunburst |
OpenAI | 31 | 약 15초 |
| GPT Image 2.5 Flare | gpt-image-2-5-flare |
OpenAI | 31 | 약 15초 |
| Nano Banana Pro | nano-banana-pro |
124 | 약 25초 | |
| Nano Banana 2.1 | nano-banana-2-1 |
31 | 약 8초 | |
| Seedream 5.0 Pro | seedream-5-0-pro |
ByteDance | 36 | 약 20초 |
| Flux 3 Image | flux-3-image |
Black Forest Labs | 32 | 약 20초 |
| Grok Imagine 2.0 | grok-imagine-2-0 |
xAI | 32 | 약 15초 |
모든 모델이 다섯 가지 포맷에서 같은 가격이에요. Flux 3 Image와 Grok Imagine 2.0은 Hobby 플랜부터, 나머지 다섯 개는 Creator부터 열려요. 그 아래 플랜에서는 호출이 403 plan_required로 응답하고 아무것도 청구하지 않아요.
렌더 제출하기
curl https://eroq.ai/v1/images/generations \
-H "Authorization: Bearer $EROQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nano-banana-pro",
"prompt": "An aerial view of a harbour city at blue hour, lit windows and light trails along the quays, layered haze between the towers, crisp architectural detail, cinematic wide shot",
"aspect": "16:9",
"batch": 2
}'
호출은 배치 비용을 청구하고 곧바로 202로 응답해요. 잡은 테이크마다 하나씩이에요.
{
"object": "image.generation",
"jobs": [
{ "id": "b7e6c2d4-…", "poll": "/v1/images/generations/b7e6c2d4-…" },
{ "id": "4f19a0e3-…", "poll": "/v1/images/generations/4f19a0e3-…" }
],
"created": 1791450000,
"model": "nano-banana-pro",
"failed": 0,
"usage": { "credits_spent": 248, "credits_remaining": 752 }
}
이 엔진들에서 중요한 필드는 다음과 같아요.
model: 항상 보내세요. 생략하면 기본값은eroq-uncensored이고, 모르는 ID는 유효한 ID 목록과 함께400 invalid_body로 응답해요.prompt: 요청 내용 전체예요. 글자는 큰따옴표로 묶어요.aspect:1:1(기본값),3:4,4:3,9:16,16:9이고, 네이티브로 렌더돼요.batch: 1~4테이크이고, 선결제돼요.failed는 시작하지 못한 테이크 수이고, 이미 환불됐어요.store: 영구 공개 URL이 필요하면true예요. 시작한 10 MB마다 2 크레딧이 추가돼요.folder_id: 렌더를 라이브러리 폴더 중 하나에 바로 넣어 줘요.
이 엔진들이 무시하는 것
위의 엔진들은 텍스트 투 이미지 전용이라서, 일부 필드는 아무 효과가 없어요.
references는 버려져요. 사진과 맞아야 하는 얼굴이나 제품이라면eroq-one(최대 열 장)이나eroq-krea2(최대 네 장)로 요청을 보내세요.negative_prompt와cfg_scale은 검증은 통과하지만 이 엔진들에서는 쓰이지 않아요. 원하는 결과를 프롬프트로 묘사하세요.edit: true는400 edit_unsupported로,aspect: "retain"은400 retain_requires_reference로 응답해요. 둘 다 이미지 작업이니 Eroq One으로 보내세요.
잡이 끝날 때까지 폴링하기
const BASE = 'https://eroq.ai/v1'
const headers = {
Authorization: `Bearer ${process.env.EROQ_API_KEY}`,
'Content-Type': 'application/json',
}
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
export async function generate(body) {
const res = await fetch(`${BASE}/images/generations`, { method: 'POST', headers, body: JSON.stringify(body) })
const json = await res.json()
if (!res.ok) throw Object.assign(new Error(json.error.message), { status: res.status, code: json.error.code })
// One job per take: each succeeds, or fails and refunds, on its own
return Promise.all(json.jobs.map(job => waitFor(job.id)))
}
async function waitFor(id, { every = 2500, timeout = 11 * 60_000 } = {}) {
const started = Date.now()
while (Date.now() - started < timeout) {
const res = await fetch(`${BASE}/images/generations/${id}`, { headers })
const job = await res.json()
if (!res.ok) return { id, error: job.error?.code ?? `http_${res.status}` }
if (job.status === 'succeeded') {
const [image] = job.data
return { id, url: image.url, libraryId: image.library_id, ms: job.generation_ms }
}
if (job.status === 'failed') return { id, error: job.error.code } // credits already back
await sleep(every) // processing: phase is "queued" or "generating"
}
return { id, error: 'client_timeout' }
}
폴링은 무료이고, 몇 초에 한 번이 의도된 주기예요. status가 succeeded나 failed가 될 때까지 계속하세요. image.generation.succeeded와 image.generation.failed 웹훅은 대체가 아니라 추가 알림이에요. 서명을 검증하는 방법은 비동기 API 가이드에서 볼 수 있어요.
성공하면 data[0].url은 30분간 유효한 서명된 URL이에요. 잡 ID는 24시간 유지되고, 잡(또는 library_id로 작품)을 다시 가져오면 새 URL이 발급돼요. 사용자에게 바뀌지 않는 주소가 필요하면 store: true를 보내세요. generation_ms는 렌더의 실제 소요 시간이고, 서버 기한인 10분을 넘겨도 처리 중인 잡은 generation_timeout으로 실패 처리되고 환불돼요. 위의 클라이언트 타임아웃이 그 바로 뒤에 있는 이유예요.
배치, 간단히
배치는 호출 한 번, 프롬프트 하나, 최대 네 테이크예요. 각 테이크는 독립된 잡이니 병렬로 폴링하고 가장 잘 나온 것을 남기세요. 실패한 테이크는 다른 테이크에 영향 없이 자동으로 환불돼요. 또한 배치는 분당 속도 제한에서 호출 한 번으로 계산돼요. 서로 다른 프롬프트 네 개라면 호출을 네 번 보내세요.
오류
| 상태 | code |
무슨 일이 있었나 | 해야 할 일 |
|---|---|---|---|
| 400 | invalid_body |
필드가 검증에 실패함 | 본문을 고치세요. 메시지에 필드 이름이 나와요 |
| 400 | content_blocked |
이용 정책에 따라 청구 전에 거부됨 | 프롬프트를 바꾸고, 그대로 재시도하지 마세요 |
| 400 | edit_unsupported |
텍스트 전용 엔진에 이미지 작업을 보냄 | eroq-one을 쓰세요 |
| 402 | insufficient_credits |
잔액이 가격 × 배치보다 적음 | 충전하세요. 반복문으로 재시도하지 마세요 |
| 403 | plan_required |
모델에 더 높은 플랜이 필요함, 청구 전 | 업그레이드하거나 플랜에 포함된 모델을 고르세요 |
| 429 | rate_limit_exceeded |
이 키로 이번 분에 호출이 너무 많음 | Retry-After만큼 기다리세요 |
| 502 | generation_failed |
렌더를 시작하지 못함 | 청구되지 않아요. 재시도하세요 |
| 503 | model_unavailable |
이 배포에서 엔진이 오프라인임 | 청구되지 않아요. 다른 ID를 고르세요 |
| 404 | not_found |
모르는 잡 ID이거나 24시간이 지남 | ID와 이미지를 제때 저장하세요 |
failed로 끝난 잡에는 error.code로 content_blocked(제공사가 거부), generation_failed, generation_timeout 중 하나가 담기고, 크레딧은 이미 지갑에 돌아와 있어요. 플랜은 모든 키의 분당 한도를 높여 줘요. Creator는 2배, Studio는 4배예요.
작업별로 라우팅하기
const ENGINE = {
text: 'gpt-image-2-5-sunburst', // posters, packaging, UI mockups
keyArt: 'gpt-image-2-5-flare', // dramatic, cinematic frames
detail: 'seedream-5-0-pro', // texture, architecture, landscapes
hero: 'nano-banana-pro', // the final frame, top fidelity
draft: 'nano-banana-2-1', // fast iteration
explore: 'grok-imagine-2-0', // many directions, characterful
daylight: 'flux-3-image', // natural light and typography
}
model: "auto"를 쓰면 eroq의 라우터가 플랜에서 열리는 엔진 중 하나를 고르고, 고른 모델의 비용을 청구해요. 고른 모델은 model로 돌려줘요. 124 크레딧 / 이미지인 Nano Banana Pro가 될 수도 있으니, 비용이 중요할 때는 모델을 직접 지정하세요. 테이크당 계산은 2026년 AI 이미지 비용에, 라우팅 선택의 이유는 2026년 최고의 AI 이미지 모델에 있어요.
MCP와 CLI
같은 모델이 MCP 서버의 generate_image 도구(렌더를 기다렸다가 이미지를 돌려주며, 오래 걸리는 것에는 get_image_status가 있어요) 뒤에도, CLI 뒤에도 있어요. CLI에서는 eroq image "a foggy harbour at dawn" -m seedream-5-0-pro --aspect 16:9 -o harbour.webp처럼 써요. 둘의 설정 방법은 /docs/mcp에 있어요.
자주 묻는 질문
OpenAI, Google, ByteDance의 API 키가 필요한가요?
아니요. eroq 키 하나로 모든 모델을 쓸 수 있고, 모든 비용은 하나의 지갑에서 eroq 크레딧으로 청구돼요.
eroq를 통해 Nano Banana Pro나 GPT Image 2.5에 참조 이미지를 보낼 수 있나요?
아니요. eroq에서 이 둘은 텍스트 투 이미지 엔진이라 참조는 버려져요. 이미지 기반 작업에는 참조를 최대 열 장까지 읽고 지시로 편집하는 eroq-one을 쓰세요.
이미지 URL은 얼마나 오래 유효한가요?
data의 서명된 URL은 30분, 잡은 24시간이에요. 다시 가져오면 새 URL을 받을 수 있고, 영구 공개 URL이 필요하면 store: true로 제출하세요.
실패하거나 차단된 렌더에도 크레딧이 드나요?
아니요. 정책으로 거부된 프롬프트는 청구 전에 응답하고, 실패했거나 제공사에서 거부된 잡은 자동으로 환불돼요.
키를 받고, 모델 ID를 고르고, /docs/images로 요청을 하나 보내 보세요.
