spicyapi문서
SDK
본문

Python SDK

SpicyAPI 공식 Python SDK(spicyapi) 안내입니다. 설치부터 견적과 첫 생성, 로컬 파일 업로드, 웹훅 검증, 모든 오류 코드까지 다룹니다.

spicyapi는 SpicyAPI의 공식 Python SDK입니다. 이미지·영상·오디오 생성을 클라이언트 객체 하나 뒤에 놓습니다. API 키를 대신 붙여 주고, 응답 봉투를 평범한 딕셔너리로 바꿔 주고, 알맞은 백오프로 작업이 끝날 때까지 기다려 주고, 로컬 파일을 한 번의 호출로 업로드하고, 웹훅 서명을 상수 시간 비교로 검증합니다.

Python 3.11 이상이 필요하며, 런타임 의존성이 하나도 없습니다. 일부러 그렇게 만들었습니다. 이 패키지는 이미 내가 책임지고 있는 의존성 트리 안으로 들어가고, 패키지가 더하는 제약 하나하나가 충돌이 날 기회를 하나씩 늘리기 때문입니다.

나에게 맞는 도구인가요?

하고 싶은 일쓸 도구
내 Python 코드에서 SpicyAPI 호출하기이 SDK
Node.js나 TypeScript에서 호출하기TypeScript SDK
Go, PHP, Java에서 호출하기Go, PHP, Java SDK
코드를 짜지 않고 터미널에서 생성하기CLI
AI 어시스턴트가 대신 SpicyAPI를 호출하게 하기MCP 서버와 Agent Skill
채팅·텍스트 모델 쓰기SpicyAPI를 가리키도록 설정한 공식 openai, anthropic, google-genai 라이브러리. 텍스트와 스트리밍을 보세요

설치

pip install spicyapi

그런 다음 키를 환경 변수에 넣으세요. 그래야 코드에도, 셸 기록 파일에도 키가 남지 않습니다.

export SPICY_API_KEY="sk-spicy-..."

첫 결과

가격을 묻고, 판단하고, 작업을 만들고, 기다리고, 파일을 읽습니다. 견적은 무료이며 아무것도 예약하지 않습니다.

import os, uuid
from spicyapi import SpicyClient, output_assets

client = SpicyClient()  # 환경 변수에서 SPICY_API_KEY를 읽습니다

model = client.get_model("MODEL_ID_FROM_CATALOG")
quote = client.quote_task(model=model["model"], input_data={"prompt": "a lantern in fog"})
print(quote["estimatedCost"], quote["maxCharge"])   # 돈을 쓰기 전에 판단하세요

task = client.create_task(
    model=model["model"],
    input_data={"prompt": "a lantern in fog"},
    idempotency_key=str(uuid.uuid4()),
    quote_id=quote["quoteId"],
    expected_cost=quote["estimatedCost"],
)
final = client.wait_for_terminal(task["taskId"])
for asset in output_assets(final):                  # 메서드가 아니라 모듈 수준 헬퍼입니다
    print(asset["url"])

MODEL_ID_FROM_CATALOG는 자리표시자입니다. 실제 ID는 인증된 카탈로그에서 가져오세요. client.list_models()이고, HTTP로는 GET /api/v1/models입니다. 기억이나 오래된 페이지에서 가져오면 안 됩니다. 모델은 계속 추가되고, 멈추고, 퇴역합니다. input_data는 그 모델 자신의 inputSchema를 보고 구성하세요. list_models(include_schema=True)가 돌려줍니다. 모델마다 받는 필드가 다릅니다.

금액은 부동소수점이 아니라 미국 달러를 적은 십진 문자열로 돌아옵니다. 이진 부동소수점은 대부분의 십진 금액을 정확히 담지 못하기 때문입니다. 비교와 덧셈은 decimal.Decimal로 하세요. 이 API 어디에도 크레딧이나 포인트는 없습니다.

wait_for_terminal은 어떤 종료 상태에서든 값을 돌려줍니다. 종료 상태라고 해서 성공한 것은 아닙니다. 출력을 읽기 전에 final["state"]부터 확인하세요.

파일이 아니라 텍스트로 답하는 엔드포인트도 있습니다. 모델이 전사본이나 캡션을 만든다면 output_text(final)를 먼저 읽으세요. 결과 파일 목록만 훑는 클라이언트는 완벽하게 성공한 작업을 두고 아무것도 만들지 못했다고 보고합니다.

로컬 파일에서 시작하기

이미지-투-비디오, 피사체 교체, 이미지 편집은 모두 내 소재가 먼저 이쪽에 올라와 있어야 합니다. upload_file은 티켓 발급, 스토리지로 PUT, 커밋이라는 세 단계 업로드를 한 번의 호출로 끝내고 spicy:// URI를 돌려줍니다. 입력에 넣는 값이 바로 그 URI입니다.

uploaded = client.upload_file("/path/to/reference.png")
task = client.create_task(
    model="MODEL_ID_FROM_CATALOG",
    input_data={"image": uploaded["uri"], "prompt": "slow dolly in"},
    idempotency_key=str(uuid.uuid4()),
)

공개적으로 접근할 수 있는 HTTPS 주소라면 업로드 없이 입력에 바로 넣어도 됩니다. 이미지는 10 MiB까지, 오디오와 영상은 90 MiB까지 받습니다. 나머지는 미디어를 보세요.

웹훅

verify_webhook은 모듈 수준 함수라서, 요청 핸들러가 클라이언트를 만들지 않고도 쓸 수 있습니다. 상수 시간으로 비교하며, 서명이 유효할 때만 타임스탬프를 확인합니다.

from spicyapi import verify_webhook

delivery = verify_webhook(
    raw_body=request.body,                      # 파싱하기 전의 정확한 바이트
    signature=request.headers["X-Webhook-Signature"],
    timestamp=request.headers["X-Webhook-Timestamp"],
    payload_version=request.headers["X-Webhook-Payload-Version"],
    secret=os.environ["SPICY_WEBHOOK_SECRET"],
)

검증은 원본 바이트로 하세요. json.loads 뒤에 json.dumps를 거치면 바이트가 달라지고, 서명은 다시는 맞지 않습니다. 전송은 재시도되므로 전송 ID로 중복을 걸러 내세요. 전체 전송 형식과 재시도 일정은 웹훅에 있습니다.

오류

모든 실패는 SpicyApiError로 올라오며, 여기에 status, code, request_id, retry_after_seconds가 담깁니다. 분기는 언제나 code로 하고, 메시지 문구로는 절대 하지 마세요. 메시지는 번역되지만 코드는 번역되지 않습니다.

HTTP 503은 서로 다른 비즈니스 코드 세 개가 함께 씁니다. 그래서 HTTP 상태만 읽어서는 무엇을 해야 할지 정할 수 없습니다.

코드의미대응
40003업로드한 바이트가 티켓과 맞지 않습니다새 티켓을 받아 처음부터 다시 하세요
40004그 파라미터 조합을 처리할 배포가 없습니다메시지에 이름이 나온 파라미터를 바꾸세요
40201잔액이 모자랍니다충전하세요
40901작업이 만들어지기 전에 가격이 바뀌었습니다견적을 다시 받되 멱등 키는 그대로 두세요
503의존하는 구성 요소를 잠시 쓸 수 없습니다Retry-After만큼 기다린 뒤 다시 시도하세요
50301지금 이 모델에 쓸 수 있는 배포나 가격이 없습니다카탈로그를 새로 읽으세요. 몰아치듯 재시도하지 마세요
50302동기 생성이 상위에서 실패했고 환불됐습니다새 멱등 키로 다시 시도하세요

err.recovery는 실행 중에도 같은 안내를 돌려줍니다. 지원팀에 문의할 때는 request_id를 함께 알려 주세요. 모든 코드는 오류에 정리돼 있습니다.

돈을 아껴 주는 두 가지

제출 하나에 멱등 키 하나를 유지하세요. 같은 제출을 다시 보낼 때는 시간이 초과됐든 연결이 끊겼든 그 키를 그대로 다시 쓰세요. 응답을 받지 못했다는 사실이 작업이 만들어지지 않았다는 증거는 아닙니다. 새 키를 쓰면 결과를 모르는 상태가 돈이 드는 두 번째 작업으로 바뀝니다. 멱등성을 보세요.

성공한 작업은 결과가 마음에 들지 않아도 과금됩니다. 가격이 중요하다면 먼저 견적을 받으세요. quote_task는 아무것도 예약하지 않고 아무것도 만들지 않습니다.

이 패키지가 하지 않는 일

  • 텍스트 모델. 텍스트 모델은 OpenAI, Anthropic, Gemini의 통신 형식을 쓰므로 공식 openai, anthropic, google-genai 라이브러리가 이미 그대로 작동합니다. 같은 키로 https://api.spicyapi.ai/v1을 가리키기만 하면 됩니다. 텍스트와 스트리밍을 보세요.
  • 브라우저·모바일·데스크톱 앱. 이 키를 애플리케이션 안에 담아 배포하지 마세요. 클라이언트에 컴파일해 넣은 키는 공개된 키나 마찬가지입니다. 내 서버에서 호출하세요.
  • 모델 고르기와 필드 채우기. SDK는 카탈로그와 모델별 스키마를 건네줄 뿐이고, 무엇을 보낼지는 직접 정합니다.
  • 작업 취소. 작업이 접수되면 끝까지 실행됩니다. 내 프로그램을 멈춰도 멈추는 것은 내 쪽의 기다림뿐입니다.

소스

이 패키지는 MIT 라이선스이고 **github.com/spicyapi-ai/spicy-python**에서 공개적으로 개발됩니다. 저장소의 README는 이 클라이언트를 가장 짧게 한 바퀴 둘러보는 문서이고, 이 페이지는 그 주변 개념을 채워 줍니다.

다음 단계

이 페이지에서