Python SDK
SpicyAPI 公式の Python SDK(spicyapi)のガイドです。インストール、見積もりと最初の生成、ローカルファイルのアップロード、Webhook の検証、すべてのエラーコードの読み方までをまとめています。
spicyapi は、SpicyAPI 公式の Python SDK です。画像・動画・音声の生成を、1 つのクライアントオブジェクトの後ろにまとめます。API キーを付ける、応答のエンベロープをただの辞書に変換する、ほどよく間隔を広げながらタスクの完了を待つ、ローカルファイルを 1 回の呼び出しでアップロードする、Webhook の署名を「内容によって処理時間が変わらない方法」で検証する。こうした作業を、すべて引き受けます。
必要なのは Python 3.11 以降だけで、実行時の依存パッケージはありません。これは意図した設計です。このパッケージが入るのは、あなたがすでに抱えている依存関係の中です。制約を 1 つ増やすたびに、衝突の可能性も 1 つ増えます。
このツールで合っている?
| やりたいこと | 使うもの |
|---|---|
| 自分の 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()、つまり GET /api/v1/models)から取得してください。記憶や古い Web ページから写してはいけません。モデルは追加・一時停止・終了されるからです。input_data は、そのモデル自身の inputSchema(list_models(include_schema=True) が返します)に従って組み立ててください。受け付けるフィールドは、モデルごとに違います。
金額は米ドルの十進文字列で返ります。浮動小数点数ではありません。2 進数の浮動小数点数では、ほとんどの十進の金額を正確に保持できないからです。比較や加算には decimal.Decimal を使ってください。この API には、クレジットやポイントの仕組みはどこにもありません。
wait_for_terminal は、終端状態のどれかに達した時点で戻ります。終端状態は、成功した状態という意味ではありません。出力を読む前に final["state"] を確認してください。
エンドポイントによっては、ファイルではなくテキストで応答します。モデルが文字起こしやキャプションを返す場合は、先に output_text(final) を読んでください。成果物の一覧しか見ないクライアントは、完全に成功したタスクを「何も生成されなかった」と報告してしまいます。
ローカルのファイルから始める
画像から動画を作る、被写体を差し替える、画像を編集する。どれも、まず素材を当社側に置く必要があります。upload_file は、チケットの発行、ストレージへの PUT、確定という 3 つのステップを 1 回の呼び出しで行い、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 の URL なら、アップロードは一切必要なく、そのまま入力に入れられます。画像は 10 MiB まで、音声と動画は 90 MiB までです。残りはメディアにまとめています。
Webhook
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 で重複を取り除いてください。配信の形式と再試行のスケジュールは、Webhook にすべて書いてあります。
エラー
失敗はすべて SpicyApiError として送出され、status、code、request_id、retry_after_seconds を持ちます。分岐は必ず code で行い、メッセージの文面では判断しないでください。メッセージは翻訳されますが、コードは変わりません。
HTTP 503 は、3 つの異なるビジネスコードで共有されています。 そのため、HTTP ステータスだけを見ても、次に何をすべきかは決められません。
| コード | 意味 | 対処 |
|---|---|---|
40003 | アップロードされたバイト列が、チケットと一致しない | チケットを取り直して、最初からやり直します |
40004 | そのパラメーターの組み合わせに対応できる構成がない | メッセージに書かれているパラメーターを変更します |
40201 | 残高が足りない | チャージします |
40901 | タスクが作成される前に価格が変わった | 見積もりを取り直します。冪等キーは同じものを使ってください |
503 | 依存している何かが、短時間だけ利用できない | Retry-After の秒数だけ待ってから再試行します |
50301 | そのモデルに、いま使える構成も価格もない | カタログを取り直します。連打しないでください |
50302 | 同期的な生成が上流で失敗し、返金された | 新しい冪等キーで再試行します |
err.recovery は、実行時にこれと同じ案内を返します。サポートに問い合わせるときは request_id を伝えてください。すべてのコードはエラーに一覧があります。
お金を守る 2 つのこと
1 回の送信につき、冪等キーは 1 つに保ってください。 タイムアウトや接続切れのあとも含め、その送信を送り直すときは毎回同じキーを使います。応答が失われたことは、タスクが作成されなかったことの証明にはなりません。新しいキーを使うと、「結果が分からないだけ」だったものが、課金される 2 つ目のタスクに変わります。冪等性を参照してください。
成功したタスクは、結果が期待外れでも課金されます。 価格が気になるときは、先に見積もりを取ってください。quote_task は何も確保せず、何も作成しません。
このパッケージが扱わないこと
- テキストモデル。 OpenAI、Anthropic、Gemini のリクエスト形式に対応しているので、公式の
openai、anthropic、google-genaiライブラリがそのまま使えます。ベース URL をhttps://api.spicyapi.ai/v1に向け、キーは同じものを設定してください。テキストとストリーミングを参照してください。 - ブラウザー・モバイル・デスクトップのアプリ。 このキーを、配布するアプリケーションの中に入れないでください。クライアントに埋め込まれたキーは、公開されたキーと同じです。呼び出しは、必ず自分のサーバーから行ってください。
- モデルを選んだり、そのフィールドを埋めたりすること。 SDK が渡すのは、カタログと各モデルのスキーマです。何を送るかは、あなたが決めます。
- タスクのキャンセル。 いったん受理されたタスクは、最後まで実行されます。プログラムを止めても、止まるのはあなたの側の待機だけです。
ソースコード
このパッケージは MIT ライセンスで、github.com/spicyapi-ai/spicy-python で公開のまま開発しています。README は、クライアント全体をいちばん短く見渡せる資料です。このページは、その周りにある考え方を補います。

