모델 카탈로그와 스키마
인증된 최신 카탈로그에서 호출 가능한 모델과 가격을 읽고 현재 JSON Schema에 맞는 요청을 구성합니다.
createTask.model에는 인증된 GET /api/v1/models 응답의 정확한 model 값을 사용합니다. input은 같은 항목의 현재 inputSchema가 정의합니다. 호출 가능한 ID의 유일한 기준은 이 런타임 응답입니다.
정적 페이지에서 ID를 복사하지 마세요
출시 시점 사본, 모델 계열 페이지와 개발사 카탈로그는 탐색용입니다. 예정·비활성·이름 변경 항목을 포함할 수 있으며 최신 카탈로그가 비었다고 대체 자료로 사용하면 안 됩니다. 유료 작업 전에 인증된 카탈로그를 읽고 enabled: true와 available: true를 모두 확인하세요.
예시의 MODEL_ID_FROM_CATALOG는 실제 모델이 아닌 자리표시자입니다. 자신의 최신 카탈로그에서 받은 model 값으로 바꾸세요. 카탈로그 조회는 무료입니다.
모델과 검증된 입력 선택
요청 스키마는 모델마다 다릅니다. 안전하게 실행하려면 최신 모델과 서버에서 검증한 예시 입력 하나를 함께 선택하세요.
const response = await fetch(
'https://api.spicyapi.ai/api/v1/models?includeSchema=1&includeExamples=1',
{ headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` } },
);
const envelope = await response.json();
if (!response.ok || envelope.code !== 200) throw new Error(envelope.msg);
const selected = envelope.data.items.find(
(item) => item.enabled && item.available && item.examples?.length,
);
if (!selected) throw new Error('No callable model with a validated example');
const createTaskBody = {
model: selected.model,
input: selected.examples[0].input,
};각 예시는 서버가 현재 스키마로 검증한 완전한 input이므로 그대로 제출할 수 있습니다.
코드로 카탈로그 조회
GET /api/v1/models
GET /api/v1/models/{model}curl "https://api.spicyapi.ai/api/v1/models?modality=video" \
-H "Authorization: Bearer $SPICY_API_KEY"목록은 페이지 구분 없이 키로 볼 수 있고 필터에 맞는 모든 모델을 한 응답에 담습니다. 모든 매개변수는 선택 사항입니다.
| 매개변수 | 의미 |
|---|---|
modality | image, video, audio 또는 text |
provider | 모델 개발사. 대소문자를 구별하여 정확히 일치해야 합니다(예: ByteDance). 항목의 provider에서 복사하세요. |
task | 작업 하나. 예: text-to-image, edit(이미지 편집), image-to-video, text-to-video, reference-to-video, speech-to-text, video-analyze, video-edit, video-extend, character-animation, chat. 현재 목록은 카탈로그의 tasks에서 읽으세요. 이미지 편집은 두 표기를 받습니다. 모델은 .../edit로 공개되지만 tasks는 image-to-image로 분류하며 필터는 둘 다 허용합니다. |
search | 모델 ID나 표시 이름 어디든 포함된 텍스트. 대소문자 구별 없이 최대 128자 |
includeSchema | true 또는 1이면 항목별 inputSchema 포함 |
includeExamples | true 또는 1이면 현재 스키마로 검증한 항목별 examples 포함 |
단일 모델 엔드포인트 GET /api/v1/models/{model}은 항상 inputSchema와 examples를 포함합니다. includeSchema와 includeExamples는 목록에서만 의미가 있습니다. ID의 슬래시는 그대로 둘 수 있습니다. HTTP 클라이언트가 경로 매개변수를 단일 구간으로 처리할 때만 퍼센트 인코딩하세요. 없거나 현재 제공되지 않는 모델은 404를 반환합니다.
목록 응답을 줄인 예시입니다.
{
"code": 200,
"msg": "success",
"data": {
"total": 1,
"items": [
{
"model": "MODEL_ID_FROM_CATALOG",
"family": "…",
"displayName": "…",
"provider": "…",
"modality": "video",
"tasks": ["image-to-video"],
"async": true,
"enabled": true,
"available": true,
"availability": "available",
"taskTimeoutSeconds": 1200,
"maxOutputDurationSeconds": 10,
"quantityField": "duration_seconds",
"pricing": [
{ "variant": "generate_audio=false;resolution=720p", "unit": "per_second", "price": "0.05", "currency": "USD" },
{ "variant": "generate_audio=true;resolution=720p", "unit": "per_second", "price": "0.08", "currency": "USD" }
],
"startingPrice": { "variant": "generate_audio=false;resolution=720p", "unit": "per_second", "price": "0.05", "currency": "USD" },
"badges": ["audio_output"],
"relatedModels": [],
"version": "v1",
"updatedAt": "2026-09-16T16:47:57Z"
}
]
},
"request_id": "req_01k3m8x9q2z4v7n5p6r8s0t1w2"
}위 가격은 설명용입니다. 목록에서 inputSchema와 examples는 요청했을 때만 나타납니다.
클라이언트가 사용할 필드
| 필드 | 용도 |
|---|---|
model | createTask.model로 보낼 정확한 값. publisher/model/task 형식 |
family | 관련 엔드포인트를 묶는 안정적인 제품 계열 식별자 |
displayName | 사람이 읽는 엔드포인트 이름 |
provider | 모델을 만든 연구소 등 모델 개발사 |
modality / tasks | 카탈로그의 미디어 분류와 수행 작업. modality는 탐색과 modality 필터를 제어하며 결과물 유형을 보장하지 않습니다. 예를 들어 speech-to-text는 audio로 분류되지만 텍스트를 반환합니다. 출력 형식 참조 |
toolkit | 속한 도구 계열. 현재는 subject-swap만 있습니다. 도구 모음에 속하지 않으면 필드가 없으므로 키 존재보다 값을 확인하세요. badges와 마찬가지로 분류일 뿐 승인·가격·검증에 영향을 주지 않습니다. 피사체 교체 참조 |
async | true: 작업 생성 후 폴링이나 webhook으로 수집. false: 응답에서 결과 반환 |
inputSchema | 폼 생성과 요청 검증용 JSON Schema 2020-12 |
examples | 현재 스키마로 검증한 입력. 목록에서는 요청한 경우에만 반환 |
enabled | 지금 호출할 수 있는지 여부. 공개되었지만 아직 열리지 않은 항목과 플랫폼이 일시 중지한 항목도 목록에 포함되며 값은 false입니다. 작업 제출 전에 available과 함께 확인 |
available | 지금 호출 가능한지 여부. false는 현재 가격이 없는 경우 등 호출 실패를 의미 |
availability | 안내하는 단계: planned, available, preview(필드·출력 변경 가능), maintenance(일시 장애, 복구 예정) |
pricing / startingPrice | 계정 적용 가격. 가격 읽기 참조 |
quantityField | 값이 과금 수량이 되는 입력 필드. 영상은 주로 duration_seconds. 빈 값이면 호출당 한 단위. 항상 카탈로그에서 읽기 |
taskTimeoutSeconds | 작업 하나의 플랫폼 실행 기한. 미디어 길이가 아님 |
maxOutputDurationSeconds | 모델이 만들 수 있는 최장 출력. duration_seconds 속성의 maximum에서 가져오며 최대값이 선언되지 않으면 생략 |
badges | commercial_use, no_watermark 등 기능·라이선스 태그. 모르는 값은 무시 |
relatedModels | 운영팀이 선정한 대안·다음 단계의 호출 가능한 모델 ID |
version / updatedAt | 변경 추적. 이후 조회와 비교하여 변경 여부 확인 |
mature와 policyTier는 정보용 라벨이며 요청 승인 여부에 관여하지 않습니다.
가격 읽기
pricing의 항목 하나가 가격 구간 하나입니다.
| 필드 | 의미 |
|---|---|
unit | per_image, 출력 미디어의 per_second, per_request, per_1k_tokens |
price | USD 단위 가격의 십진 문자열. 이미 계정 요율이 반영되며 계정마다 다를 수 있음 |
variant | 구간을 선택하는 설정. 단일 가격이면 빈 값, 필드 하나면 값만 표시(예: 720p), 여러 필드면 이름순으로 정렬한 field=value를 ;로 연결(예: generate_audio=false;resolution=480p) |
currency | 항상 USD |
regularPrice, offerLabel, offerPercent, offerEndsAt | 고객 혜택 적용 중에만 존재. 할인 전 가격, 혜택명, 비율과 종료 시각 |
startingPrice는 최저 구간이며 선택한 설정의 가격이 아닙니다. 구간 선택 필드는 존재하는 경우 inputSchema["x-pricing"].variantFields에 나옵니다. 없으면 quantityField를 제외한 x-ui.affects_price: true 필드입니다. 생략한 필드는 스키마 default로 계산합니다.
- 미디어 모델: 비용은
price × quantity입니다. 수량은 입력의quantityField값이고quantityField가 비었으면 한 단위입니다. 일부 엔드포인트는 여기에 추가 입력마다 별도 비용을 더합니다. 주로 참조 이미지 한 장마다 부과됩니다. 반올림 수준의 차이가 아닌 실제 청구 요소입니다. 참조 이미지 배열을 받는 편집 엔드포인트에서 배열을 채우면 금액이 몇 배가 될 수 있지만unit,quantity,variant와 구간price는 단일 이미지와 그대로입니다. 따라서 위 계산만 쓰면 눈에 띄는 신호 없이 과소 계산됩니다. 기계 판별 기준은x-ui.affects_price: true이면서quantityField도 아니고x-pricing.variantFields에도 없는 필드입니다. 가격 구간 선택 없이 금액을 바꿉니다. 이런 엔드포인트는pricing을 최저 기준으로 보고 실제 금액은 견적으로 확인하세요. - 텍스트 모델(
per_1k_tokens): 숫자 하나로 비용을 설명할 수 없습니다.price는 출력 토큰 1,000개당 요율뿐입니다. 입력과 캐시 입력은 보통 더 낮은 별도 요율을 적용하고 각 호출의 실측 사용량으로 과금합니다. 전체 토큰 수에price를 곱하지 마세요. 입력·캐시 입력·출력의 백만 토큰당 가격은 모델 페이지와 공개 카탈로그의price.perMillionTokens에 표시됩니다.
네이티브 API의 정확한 요청 하나를 결제 전에 견적하려면 POST /api/v1/jobs/quote를 사용하세요. 최종 과금은 작업 기록의 cost와 settled: true, 과금에서 확인합니다.
카탈로그 캐시
- 응답은 최대 60초 캐시할 수 있습니다(
Cache-Control: private, max-age=60). 가격이 계정별이므로 계정별 비공개 캐시에만 보관하고 공유·공개 CDN 캐시에 두지 마세요. - 그 외에도 작업마다 다시 읽지 마세요. 카탈로그는 작업 제출과 독립된 계정 읽기 허용량을 사용합니다. 매 호출 전 조회는 여전히 읽기 용량을 낭비합니다. 호출 제한을 참고하세요.
- 일정 간격(예: 수분마다),
400검증 오류 후, 해당 모델 제출이 거절되었을 때 새로 읽으세요. - 사용한 기록의
version과updatedAt을 저장하여 이후 조회에서 변경되었는지 확인하세요. - 스키마 사본을 하드코딩해 배포하지 말고 최신 카탈로그에 호출 가능한 항목이 없다고 정적 페이지로 대체하지 마세요.
공통 Schema와 Playground 규칙
inputSchema는 JSON Schema 2020-12를 사용합니다. 표준 키워드는 서버 검증을 제어하며 속성별 x-ui 객체는 Playground 순서·표현과 견적 갱신 힌트만 설명합니다. 모르는 표시용 확장은 무시해야 하며 required, 열거값, 범위나 조건 분기를 대체하지 않습니다. Spicy Schema 계약을 참고하세요.
자체 모델별 매개변수 표 만들기
이 사이트는 모델별 정적 매개변수 표를 제공하지 않습니다. 모델과 필드는 매주 바뀌어 정적 사본이 실제와 달라지며 오래된 매개변수를 읽으면 400 오류나 잘못된 가격으로 이어집니다. 매개변수의 기준은 카탈로그가 반환하는 inputSchema 하나입니다. Playground도 같은 문서를 렌더링하고 SDK도 이를 기준으로 검증합니다.
스키마 각 요소를 표로 표시하기
| 스키마 요소 | 매개변수 표 표현 |
|---|---|
properties의 키 | 매개변수 이름. 모델 간 필드명이 통일되어 같은 의미에는 어디서든 같은 이름 사용 |
required에 포함 여부 | 필수·선택 여부 |
anyOf / allOf | 조건부 필수. anyOf는 이 중 하나 이상 제공, allOf의 if → then은 A를 주면 B도 제공 |
type | 유형 |
description | 도움말. 영어 설명을 그대로 표시할 수 있으며 직접 작성할 필요 없음 |
enum | 허용값. x-ui.enum_labels가 있으면 사람이 읽는 라벨로 표시 |
minimum / maximum | 허용 범위. x-ui.step은 증분, x-ui.unit은 단위 접미사(s, px) |
minItems / maxItems | 배열의 허용 항목 수. 생략하면 이용자가 실제로 마주칠 한도를 알 수 없음 |
items | 배열 항목 하나의 구조. items.type이 object면 자체적으로 완전한 객체 스키마입니다. required, additionalProperties와 하위 필드별 type, description, 범위, default를 읽고 자유 텍스트 상자가 아닌 중첩 표로 표시 |
default | 필드 생략 시 적용하는 기본값 |
x-ui.order | 정렬 기준, 큰 값 우선. properties의 키 순서로 정렬하지 않기. JSON 객체 키 순서는 계약에 포함되지 않음 |
x-ui.primary | 주요 입력으로 위에 고정 |
x-ui.advanced | 고급 영역으로 접어도 되는 필드 |
x-ui.affects_price | 가격 영향 표시. 값을 바꾸면 새 견적 요청 |
x-ui.widget | 편집 가능한 폼의 컨트롤. 13가지 값은 Spicy Schema 참조 |
조건 분기는 inputSchema 루트에만 두 형식으로 나타납니다. anyOf는 각 분기가 required 필드만 나열하여 ‘하나 이상 제공’을 뜻하고, allOf는 if → then으로 ‘A 제공 시 B도 제공’을 뜻합니다. 계열에서 추측하지 말고 oneOf, not, dependentSchemas를 기대하지 마세요. 새 엔드포인트는 Spicy Schema의 표준 필드를 따르고 오래된 엔드포인트는 자신의 최신 스키마를 따릅니다.
조회하기
const modelId = 'MODEL_ID_FROM_CATALOG'; // the exact `model` value from GET /api/v1/models
const res = await fetch(`https://api.spicyapi.ai/api/v1/models/${modelId}`, {
headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` },
});
const { data } = await res.json();
const schema = data.inputSchema;
const rows = Object.entries(schema.properties)
.sort(([, a], [, b]) => (b['x-ui']?.order ?? 0) - (a['x-ui']?.order ?? 0))
.map(([name, prop]) => ({
name,
required: (schema.required ?? []).includes(name),
type: prop.type,
description: prop.description,
values: prop.enum
? prop.enum.map((v) => prop['x-ui']?.enum_labels?.[v] ?? v)
: prop.minimum !== undefined || prop.maximum !== undefined
? [`${prop.minimum ?? ''}–${prop.maximum ?? ''}${prop['x-ui']?.unit ?? ''}`]
: [],
default: prop.default,
affectsPrice: prop['x-ui']?.affects_price === true,
advanced: prop['x-ui']?.advanced === true,
}));예시는 의도적으로 스칼라까지만 다룹니다. 배열은 enum이나 범위가 아니라 items, minItems, maxItems로 허용 내용을 정의하므로 values를 비워 둡니다. 배포 전에 확장하세요. 항목 구조나 길이 한도 없이 매개변수를 단순 array로만 표시하면 독자가 활용할 수 없습니다.
단일 모델 기록도 examples를 반환합니다. 각 예시는 서버가 현재 스키마로 이미 검증한 완전한 입력이므로 문서의 최소 실행 예시로 쓰거나 그대로 제출할 수 있습니다. 수작업 예시는 스키마 변경으로 낡지만 examples는 그렇지 않으므로 더 안전합니다.
modelId만 바꾸면 같은 코드가 모든 모델에 적용되며 새 모델이 추가되어도 사용할 수 있습니다. 전체 카탈로그 표는 GET /api/v1/models?includeSchema=1의 items를 순회하고 카탈로그 캐시에 따라 캐시하세요.
description보다 긴 도움말
description은 폼 라벨에 맞춘 한 문장입니다. 더 긴 설명이 필요하면 공개 카탈로그가 매개변수별 추가 설명을 제공합니다.
curl "https://api.spicyapi.ai/console/v1/catalog/models/MODEL_ID_FROM_CATALOG?locale=en"단일 모델 기록의 paramNotes는 매개변수 이름을 키로 하는 객체이며 locale로 문서의 열 가지 언어 중 하나를 선택합니다. 라벨에 담기 어려운 내용, 즉 값의 실제 측정 기준, 눈에 띄게 느려지는 설정, 스키마는 받지만 결과가 아쉬울 수 있는 입력을 설명합니다. 자체 호스팅 파일을 가리키는 매개변수에서는 파일을 가져오는지, 언제 가져오는지, 사용할 수 없으면 어떻게 되는지를 알려 주는 유일한 설명인 경우가 많습니다.
두 경계를 기억하세요. paramNotes는 키가 필요 없는 공개 카탈로그에 있고 인증된 GET /api/v1/models에는 없으므로 별도로 읽어 스키마 옆에 캐시합니다. 또한 설명이지 검증 규칙이 아닙니다. 요청 승인 여부를 결정하는 기준은 여전히 inputSchema뿐입니다.

