spicyapiドキュメント
SDK
本文

Go SDK

SpicyAPI 公式の Go SDK(github.com/spicyapi-ai/spicy-go)のガイドです。インストール、見積もりと最初の生成、ローカルファイルのアップロード、タスク履歴の読み取り、すべてのエラーコードの扱い方までをまとめています。

spicy-go は、SpicyAPI 公式の Go SDK です。画像・動画・音声の生成を、1 つの *spicy.Client の後ろにまとめます。API キーを付ける、応答のエンベロープを型付きの構造体にデコードする、上限付きのバックオフでタスクを待つ、ローカルファイルを 1 回の呼び出しでアップロードする、そしてあらゆる失敗を errors.As で判別できる単一のエラー型にまとめる。こうした作業を、すべて引き受けます。

必要なのは Go 1.23 以降だけで、使っているのは標準ライブラリだけです。これは意図した設計です。このパッケージは、あなたの依存グラフに入ります。引きずり込むモジュールが 1 つ増えるたびに、あなたが監査すべき対象も 1 つ増えます。

このツールで合っている?

やりたいこと使うもの
自分の Go のコードから SpicyAPI を呼び出すこの SDK
Node.js や TypeScript から呼び出すTypeScript SDK
Python、PHP、Java から呼び出すPython、PHP、Java の各 SDK
コードを書かずに、ターミナルから生成するCLI
AI アシスタントに、SpicyAPI を代わりに呼び出してもらうMCP サーバーと Agent Skill
チャットモデルやテキストモデルを使うOpenAI、Anthropic、Gemini 形式に対応した、定評のある Go 用クライアント。テキストとストリーミングを参照

インストール

Go はモジュールをリポジトリから直接解決するので、レジストリを経由するステップも、公開を待つ必要もありません。次のコマンドは、今日そのまま動きます。

go get github.com/spicyapi-ai/spicy-go

キーは環境変数に入れてください。そうすれば、コードにもシェルの履歴ファイルにも残りません。

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

最初の結果

価格を尋ねて、判断して、タスクを作成し、待って、ファイルを読み取ります。見積もりは無料で、何も確保しません。

client, err := spicy.New(spicy.Options{}) // 環境変数から SPICY_API_KEY を読み取ります
if err != nil {
    return err
}

request := spicy.CreateTaskInput{
    Model: "MODEL_ID_FROM_CATALOG",
    Input: map[string]any{"prompt": "a lantern in fog"},
}

quote, err := client.Quote(ctx, request)
if err != nil {
    return err
}
log.Printf("this will cost at most %s", quote.MaxCharge)

// 送信する前に、この値を自分の側のジョブ記録と一緒に保存しておきます。存在意義は
// まさに「応答を失った、その障害のあとにも残っていること」だからです。
key, err := spicy.NewIdempotencyKey()
if err != nil {
    return err
}

request.Model = quote.Model
request.QuoteID = quote.QuoteID
request.ExpectedCost = quote.EstimatedCost

task, err := client.CreateTask(ctx, request, key, spicy.CreateTaskOptions{})
if err != nil {
    return err
}

final, err := client.WaitForTerminal(ctx, task.TaskID, spicy.WaitOptions{})
if err != nil {
    return err
}
for _, asset := range final.ReadyAssets() {
    log.Println(asset.URL)
}

MODEL_ID_FROM_CATALOG は仮の値です。実際の ID は、認証付きのカタログ(client.ListModels、つまり GET /api/v1/models)から取得してください。記憶や古い Web ページから写してはいけません。モデルは追加・一時停止・終了されるからです。Input は、そのモデル自身の inputSchema(ListModels が返します)に従って組み立ててください。受け付けるフィールドは、モデルごとに違います。

金額は米ドルの十進文字列で、浮動小数点数ではありません。2 進数の浮動小数点数では、ほとんどの十進の金額を正確に保持できないからです。この API には、クレジットやポイントの仕組みはどこにもありません。

終端状態は、成功した状態という意味ではありません。failed、canceled、expired も、どれも待機を終わらせます。final.State を確認してください。

最初のポーリングを省く

WaitSeconds は、タスクが終わるまで接続を保つようサービスに依頼するものです。速いモデルなら、送信したその応答に結果が入ってきます。

seconds := 30
task, err := client.CreateTask(ctx, request, key, spicy.CreateTaskOptions{WaitSeconds: &seconds})
if err != nil {
    return err
}

// 待ち時間を使い切ると、Task は nil になります。これはエラーではなく、ごく普通の
// 結果です。生成はまだ動いているので、ここからはポーリングに切り替えます。
final := task.Task
if final == nil {
    final, err = client.WaitForTerminal(ctx, task.TaskID, spicy.WaitOptions{})
    if err != nil {
        return err
    }
}
log.Println(final.State, final.Cost)

これは最適化であって、保証ではありません。 nil の確認をせずに task.Task を読むコードは、待ち時間より遅い生成が初めて来るまでは動きます。そして本番で panic します。

ローカルのファイルから始める

画像から動画を作る、被写体を差し替える、画像を編集する。どれも、まず素材を当社側に置く必要があります。UploadFile は、チケットの発行、ストレージへの PUT、確定という 3 つのステップを 1 回の呼び出しで行い、spicy:// の URI を返します。Input に入れるのは、この URI です。

uploaded, err := client.UploadFile(ctx, "/path/to/reference.png", "")
// uploaded.URI -> "spicy://f/fil_..."

公開されている HTTPS の URL なら、アップロードは一切必要なく、そのまま入力に入れられます。画像は 10 MiB まで、音声と動画は 90 MiB までです。メディアを参照してください。

残高・利用状況・履歴

この 3 つは、いずれも呼び出しに使った API キーの範囲に限られます。同じアカウントのほかのキーや、Web コンソールから始めた生成は含まれません。含まれていないことは、不具合ではありません。

balance, err := client.GetBalance(ctx)
if err != nil {
    return err
}
log.Printf("%s available, %s held by accepted tasks", balance.Available, balance.Held)

usage, err := client.GetUsage(ctx, spicy.UsageOptions{From: "2026-09-01", To: "2026-09-08"})
if err != nil {
    return err
}
log.Printf("%d calls, %s settled over [%s,%s)", usage.TotalCalls, usage.TotalSpend, usage.From, usage.To)

// EachTask はすべてのフィルターをページごとに繰り返し、動かすのはカーソルだけです。
if err := client.EachTask(ctx, spicy.ListTasksOptions{From: "2026-09-01", To: "2026-09-08"},
    func(task spicy.TaskListItem) bool {
        log.Println(task.TaskID, task.State, task.Cost)
        return true // false を返すと、途中で打ち切ります
    }); err != nil {
    return err
}

日付は UTC の暦日で、半開区間 [from, to) を作ります。長さは最大 92 日です。UTC の 0 時をまたぎうる走査では、From と To を必ず固定してください。 空のままにすると、サーバーはページごとに自分で期間を計算し直します(to は UTC の翌日です)。23:59 に始まって 00:01 に続く走査は、2 つの異なる問いを投げ、その答えをつなぎ合わせてしまいます。それを知らせるものは、どこにもありません。

GetUsage は突き合わせのための機能であって、進捗を見るためのものではありません。この呼び出しは、すべてのキーで共有されるアカウント単位の予算の後ろにあり、その制限はフェイルクローズで働きます。つまり、ポーリングすると、ほかのすべてのキーが自分の利用状況を読めなくなることがあります。1 件のタスクを追うには、代わりに WaitForTerminal を使ってください。精算は遅れて確定することもあるので、今日読んだ数字が明日変わることもあります。

エラー

失敗は *spicy.APIError として返り、errors.As で取り出せます。

var apiErr *spicy.APIError
if errors.As(err, &apiErr) {
    log.Println(apiErr.Status, apiErr.Code, apiErr.RequestID, apiErr.RetryAfter)
}

分岐は必ず Code で行い、メッセージでは判断しないでください。メッセージは翻訳されますが、コードは変わりません。HTTP 503 は、3 つの異なるビジネスコードで共有されています。 そのため、ステータスだけを見ても、次に何をすべきかは決められません。

コード意味対処
40003アップロードされたバイト列が、チケットと一致しないチケットを取り直して、最初からやり直します
40004そのパラメーターの組み合わせに対応できる構成がないメッセージに書かれているパラメーターを変更します
40201残高が足りないチャージします
40901タスクが作成される前に価格が変わった見積もりを取り直します。冪等キーは同じものを使ってください
503依存している何かが、短時間だけ利用できないRetryAfter の秒数だけ待ってから再試行します
50301いま使える構成も価格もないカタログを取り直します。連打しないでください
50302同期的な生成が上流で失敗し、返金された新しい冪等キーで再試行します

すべてのコードはエラーに一覧があります。サポートに問い合わせるときは RequestID を伝えてください。

お金を守る 2 つのこと

1 回の送信につき、冪等キーは 1 つに保ってください。 タイムアウトのあとも含め、送り直すときは毎回同じキーを使います。応答が失われたことは、タスクが作成されなかったことの証明にはなりません。新しいキーを使うと、「結果が分からないだけ」だったものが、課金される 2 つ目のタスクに変わります。CreateTask がキーを必須にしているのは、まさにこのためです。冪等性を参照してください。

成功したタスクは、結果が期待外れでも課金されます。 Quote は何も確保しないので、価格が気になるときは先に見積もりを取ってください。

このパッケージが扱わないこと

  • テキストモデル。 OpenAI、Anthropic、Gemini のリクエスト形式に対応しています。それらに対応した定評のある Go 用クライアントが、同じキーのまま https://api.spicyapi.ai/v1 に対してそのまま動きます。テキストとストリーミングを参照してください。
  • クライアント側のアプリケーション。 このキーを、配布するバイナリの中に入れないでください。呼び出しは、必ず自分のサーバーから行ってください。
  • モデルを選んだり、そのフィールドを埋めたりすること。 SDK が渡すのは、カタログと各モデルのスキーマです。何を送るかは、あなたが決めます。
  • タスクのキャンセル。 いったん受理されたタスクは、最後まで実行されます。context をキャンセルしても、止まるのはあなたの側の待機だけです。

ソースコード

このモジュールは MIT ライセンスで、github.com/spicyapi-ai/spicy-go で公開のまま開発しています。README は、クライアント全体をいちばん短く見渡せる資料です。このページは、その周りにある考え方を補います。

次のステップ

このページの内容