가이드
본문프로덕션 연동
문제가 생겨도 복구할 수 있는 연동을 위한 출시 전 점검표입니다. 알맞은 모델, 키와 잔액 보호, 비용 확인, 끊기지 않는 작업 추적, 믿을 수 있는 콜백, 공개 전에 해 볼 테스트를 다룹니다.
실제 사용자나 실제 돈이 내 연동에 걸리기 전에 이 페이지를 점검표로 쓰세요. 절마다 무엇을 해야 하는지, 왜 중요한지, 자세한 내용은 어디에 있는지 적었습니다. 아직 첫 호출을 해 보지 않았다면 계정 설정과 빠른 시작부터 보세요.
모델과 프로토콜 고르기
- 내 키로 실제로 호출할 수 있는 모델을 고릅니다. API 키로
GET /api/v1/models를 호출하고,enabled와available이 모두true인 모델만 쓰세요. 같은 응답에서 모델의inputSchema(모델이 받는 필드 목록)와examples도 읽으세요. 웹사이트의 모델 페이지는 모델이 무엇을 할 수 있는지 알려 줄 뿐, 내 키가 지금 그 모델을 호출할 수 있다는 증거는 아닙니다. 모델을 보세요. - 알맞은 진입점을 씁니다. 이미지, 영상 등 미디어 작업은
/api/v1아래의 작업 API를 씁니다(createTask다음에recordInfo또는 콜백). 텍스트 모델은/v1아래의 OpenAI·Anthropic 호환 클라이언트나/v1beta아래의 Gemini 호환 클라이언트로도 호출할 수 있습니다. 텍스트와 스트리밍을 보세요. - 인증에는 API 키만 씁니다. 콘솔 로그인 쿠키는 API 자격 증명이 아니며, 절대로 코드에 복사해 넣으면 안 됩니다.
키와 잔액 보호하기
- 키는 서버에 둡니다. 백엔드의 환경 변수(
SPICY_API_KEY)에 넣고, 브라우저 코드·모바일 앱·공개 저장소에는 절대 넣지 마세요. 인증을 보세요. - 환경과 서비스마다 키를 하나씩 씁니다. 키 이름은 그 키를 쓰는 곳을 따라 지으세요(예: "production-worker"). 그러면 다른 키를 멈추지 않고 하나만 폐기할 수 있습니다.
- 운영용 키에 한도를 겁니다. 운이 나쁜 하루를 감당할 만큼의 일 한도, 월 예산, 허용할 모델, 그리고 서버에서 호출한다면 IP 허용 목록까지 설정하세요. 키별 제한을 보세요. 키를 편집할 때는 비워 둔 한도 칸이 한도 없음을 뜻한다는 점을 기억하세요.
- 만료일을 확인합니다. 만료일이 있는 키는 그날(UTC)이 끝나는 시점에 작동을 멈추고, 폐기된 키와 똑같이
401을 돌려줍니다. 날짜를 달력에 적어 두거나, 오래 돌아갈 백엔드라면 만료일을 정하지 마세요. - 일괄 처리 도중에 잔액이 떨어지지 않게 합니다. 잔액 때문에 거부된 작업은
40201을 돌려주며 대기열에 들어가지도 않습니다. 알림에서 잔액 부족 알림을 켜고, 자동 충전도 검토하세요. - 팀 한도도 적용됩니다. 키가 팀에 속해 있다면, 키 자체의 한도에 닿지 않았더라도 팀의 일·월 한도 때문에 작업이
40202로 멈출 수 있으며, 모든 작업은 팀 소유자의 잔액에서 결제됩니다. 지출 한도를 보세요. - 웹훅 서명 키 교체를 계획합니다. 콘솔에서 키를 교체하면 겹치는 기간이 없습니다. 예전 키는 그 즉시 서명에 쓰이지 않고, 아직 재시도 중인 전송도 새 키로 서명됩니다. 한가한 시간대에 교체하고, 새 키를 곧바로 수신 측에 배포하고, 그사이 놓친 것은
recordInfo로 복구하세요. 웹훅을 보세요.
서버에서 입력 준비하기
- 현재 스키마로 검증합니다.
inputSchema에 있는 필드 타입, 허용값, 조건부 필수 항목을 따르고, 모델을 바꾼 뒤에는 다시 검증하세요. 모델마다 스키마가 다릅니다. - 지원되는 방식으로 미디어를 보냅니다. 공개적으로 접근할 수 있는
https://URL이나 지원되는 Base64 입력을 쓰세요. 로컬 파일이라면 업로드 URL을 요청하고, 파일 바이트를PUT으로 올리고,files/{fileId}/commit을 호출한 다음, 돌려받은spicy://URI를 모델의 입력 필드에 넣으세요. 미디어를 보세요. - 업로드한 파일은 유효 기간 안에 씁니다.
spicy://URI는 확정 응답의expiresAt까지(기본 1일) 쓸 수 있습니다. 쓰지도 않을 업로드 URL을 한꺼번에 요청하지 마세요. 쓰지 않은 URL도 제한에 포함됩니다. 레이트 제한을 보세요.
과금을 받아들이기 전에 견적 받기
- 돈을 쓰기 전에 가격을 보여 줍니다.
model,input,callBackUrl을 빠짐없이POST /api/v1/jobs/quote에 보내세요. 비용을 낼 사람에게estimatedCost,maxCharge, 통화(USD),expiresAt을 보여 주세요. 견적은 무료입니다. 작업을 만들지도, 금액을 묶어 두지도 않습니다. - 확인받은 그대로 제출합니다. 견적은 5분 동안 유효합니다. 확인을 받은 뒤 같은 요청에
quoteId와expectedCost를 더해createTask로 보내세요. -
40901을 처리합니다. 견적을 받은 뒤 견적이 만료됐거나, 입력이 바뀌었거나, 가격이 바뀌었다는 뜻입니다. 새 견적을 받아 새 금액을 보여 주세요. 더 높은 금액을 몰래 받아들이는 일은 절대 없어야 합니다. 견적을 보세요. - 금액은 정확하게 다룹니다. 금액은
"0.008"같은 십진수 문자열입니다. 부동소수점이 아니라 십진 연산으로 저장하고 더하세요. 과금을 보세요.
업무 단위 작업을 기록해 두기
네트워크 호출이 중간에 실패했을 때 복구할 수 있게 해 주는 것은 내 쪽의 기록입니다.
- 보내기 전에 저장합니다: 내 주문 ID나 작업 ID, 나중에 알아볼 수 있을 만큼의 짧은 요청 설명(비밀 값이나 프롬프트 전문은 넣지 않습니다), 그리고 보낼
Idempotency-Key. - 접수된 뒤에 저장합니다: 응답의
taskId와request_id. - 같은 제출에는 같은 키를 재사용합니다. 24시간 안에 같은 계정, 같은 API 키, 같은 요청으로 원래
Idempotency-Key를 다시 보내면 두 번째 과금 대신 원래 작업을 돌려받습니다. 멱등성을 보세요. - 시간 초과는 "실패"가 아니라 "알 수 없음"으로 다룹니다. 새 작업을 만들지 정하기 전에, 원래 키로 원래 제출부터 복구하세요. 문제 해결을 보세요.
- 재시도의 비용을 알아 둡니다. 이미 실패한 작업을 다시 시도하면 그 시점의 조건과 가격으로 새 작업이 만들어집니다.
콜백과 결과를 믿을 수 있게 처리하기
- 모든 콜백을 검증합니다. 파싱하기 전에 받은 요청 바이트 그대로 서명과 타임스탬프를 확인하고, 그다음 중복을 걸러 이벤트를 저장하세요. 웹훅을 보세요.
- 빠르게 응답합니다. 곧바로
2xx로 응답하고, 오래 걸리는 처리는 내 대기열에서 하세요. - 중복과 지연을 예상합니다. 무엇을 할지는 콜백이 도착한 순서가 아니라 작업의
state를 보고 정하세요. - 폴링을 대비책으로 남겨 둡니다. 콜백이 늦으면 1초마다 조회하지 말고, 간격을 점점 늘려 가며
recordInfo를 읽으세요. - 알맞은 신호를 읽습니다.
createTask의 HTTP202는 작업이 접수됐다는 뜻입니다.state: "succeeded"는 생성이 끝났다는 뜻입니다.settled: true는 과금액이 확정됐다는 뜻입니다.
동시 실행 수 제한과 결과 보관
- 계정마다 동시에 진행 중인 작업 수를 제한하고, 내가 보내는 요청에도 마감 시간을 두세요. 접수된 작업은 정산될 때까지 금액을 묶어 둡니다.
-
429에는Retry-After를 따릅니다. 여러 클라이언트가 1초마다 동시에 폴링하는 상황도 피하세요. 레이트 제한을 보세요. - 카탈로그 데이터는 짧게, 외부에 공유하지 않는 캐시에만 둡니다. 견적을 영구적인 가격표로 취급하지 마세요.
- 남겨야 할 결과는 보관합니다. 다운로드 링크는 20분 동안 유효하고, 생성된 미디어는 최대 약 14일, 업로드한 파일은 1일 동안 보관됩니다. 이 기간은 더 짧게 줄일 수 있고,
POST /api/v1/jobs/purge로 작업의 내용을 더 일찍 지울 수도 있습니다. 보관 기간 설정을 줄이면 이미 실행한 작업의 결과도 지워질 수 있습니다. 보관과 파기를 보세요. - 연결을 끊어서 작업을 멈추려 하지 않습니다. 접수된 작업은 계속 실행되며 취소할 수 없습니다.
출시 전에 검증하기
먼저 무료 호출부터 해 보세요. 카탈로그(GET /api/v1/models), 잔액(GET /api/v1/chat/credit), 그리고 견적입니다. 그다음 내 비용 확인 절차를 거쳐 작은 실제 생성을 한 번 실행하세요. 이 생성도 다른 작업과 똑같이 과금됩니다. 내 연동이 다음 상황을 모두 처리하는지 확인하세요.
| 상황 | 만드는 방법 | 연동이 해야 할 일 |
|---|---|---|
| 성공 | 평범한 작은 작업 | 결과를 저장하고, settled가 true가 되면 최종 cost를 보여 줍니다 |
| 잘못된 입력 | 스키마를 벗어난 값을 보냅니다 | 문제를 보여 주고, 재시도하지 않습니다(400) |
| 지원되지 않는 조합 | 모델이 처리할 수 없는 설정(그런 설정이 있다면) | 다른 값을 요청하고, 재시도하지 않습니다(40004) |
| 잔액 부족 | 잔액이 너무 적은 계정의 키 | 사용자에게 잔액 충전을 안내하고, 재시도하지 않습니다(40201) |
| 지출 한도 도달 | 일 한도를 아주 낮게 건 키 | 어느 한도에 닿았는지 보여 주고, 재시도하지 않습니다(40202) |
| 폐기되었거나 만료된 키 | 테스트용 키를 폐기하고 그 키로 호출합니다 | 운영자에게 알리고, 재시도하지 않습니다(401) |
| 보낸 뒤 시간 초과 | createTask 직후 연결을 끊습니다 | 같은 Idempotency-Key로 다시 보내 원래 작업을 돌려받습니다 |
| 모델이 콘텐츠를 거절 | 원할 때 일으키기 어렵습니다. 테스트에서 state: "failed"와 errorCode: "content_rejected"가 담긴 recordInfo 응답을 흉내 내세요 | errorMessage의 이유를 보여 주고, 자동으로 재시도하지 않습니다 |
| 중복 콜백 | 받았던 콜백을 다시 보냅니다 | 한 번만 처리합니다 |
| 만료된 다운로드 링크 | 20분 넘게 기다립니다 | 새 링크를 요청합니다 |
request_id, taskId, 시각, state, 금액을 로그에 남기세요. API 키와 프롬프트 전문은 일반 로그에 남기지 마세요.
관련 문서
견적과 프로토콜 호환성 · 모델 카탈로그와 스키마 · 미디어 · 웹훅 · 오류 · 문제 해결과 복구 · 과금 · 보관과 파기

