spicyapiDokumentation
SDKs
Hauptinhalt

Go-SDK

Das offizielle Go-SDK für SpicyAPI (github.com/spicyapi-ai/spicy-go) – installieren, die erste Generierung schätzen und ausführen, eine lokale Datei hochladen, den Task-Verlauf durchgehen und jeden Fehlercode behandeln.

spicy-go ist das offizielle Go-SDK für SpicyAPI. Es legt die Erzeugung von Bildern, Videos und Audio hinter einen einzigen *spicy.Client: Er hängt Ihren API-Schlüssel an, dekodiert den Antwort-Envelope in typisierte Structs, wartet mit begrenztem Back-off auf einen Task, lädt lokale Dateien in einem Aufruf hoch und gibt jedem Fehlschlag einen einzigen Fehlertyp, den Sie mit errors.As abfangen.

Es setzt Go 1.23 oder neuer voraus und kommt allein mit der Standardbibliothek aus. Das ist Absicht: Dieses Paket landet in Ihrem Abhängigkeitsgraphen, und jedes Modul, das es mitzieht, müssen Sie mit prüfen.

Ist das das richtige Werkzeug?

Sie möchten …Verwenden Sie
SpicyAPI aus Ihrem eigenen Go-Code aufrufenDieses SDK
Es aus Node.js oder TypeScript aufrufenDas TypeScript-SDK
Es aus Python, PHP oder Java aufrufenDas Python-, PHP- oder Java-SDK
Ohne Code aus einem Terminal heraus generierenDie CLI
Einen KI-Assistenten SpicyAPI für Sie aufrufen lassenDen MCP-Server und den Agent Skill
Ein Chat- oder Textmodell nutzenEinen etablierten Go-Client für die Formate von OpenAI, Anthropic oder Gemini – siehe Text und Streaming

Installieren

Go löst Module direkt aus ihrem Repository auf, es gibt also keinen Umweg über eine Registry und nichts, worauf Sie warten müssten. Dieser Befehl funktioniert schon heute:

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

Legen Sie Ihren Schlüssel danach in die Umgebung, damit er weder in Ihrem Code noch in der History-Datei Ihrer Shell auftaucht:

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

Ihr erstes Ergebnis

Preis erfragen, entscheiden, Task anlegen, warten, Dateien lesen. Eine Kostenschätzung ist kostenlos und reserviert nichts.

client, err := spicy.New(spicy.Options{}) // liest SPICY_API_KEY aus der Umgebung
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)

// Legen Sie ihn vor dem Absenden neben Ihren eigenen Datensatz zum Auftrag: Sein
// ganzer Zweck ist, den Absturz zu überleben, der die Antwort verschluckt hat.
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 ist ein Platzhalter. Holen Sie sich eine echte ID aus dem authentifizierten Katalog – client.ListModels, also GET /api/v1/models – und nie aus dem Gedächtnis oder von einer alten Seite: Modelle kommen hinzu, werden pausiert und eingestellt. Bauen Sie Input aus dem inputSchema genau dieses Modells, das ListModels zurückgibt; jedes Modell nimmt andere Felder an.

Beträge sind Dezimalzeichenketten in US-Dollar, nie Floats, denn binäre Gleitkommazahlen können die meisten Dezimalbeträge nicht exakt speichern. Credits oder Punkte gibt es in dieser API nirgends.

Ein Endzustand ist kein erfolgreicher Zustand: failed, canceled und expired beenden das Warten genauso. Prüfen Sie final.State.

Die erste Abfrage überspringen

WaitSeconds bittet den Dienst, die Verbindung offen zu halten, bis der Task fertig ist; bei einem schnellen Modell kommt das Ergebnis dadurch bereits mit dem Absenden zurück.

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

// Task ist nil, sobald die Wartezeit abgelaufen ist. Das ist der normale Ausgang,
// kein Fehler – die Generierung läuft weiter, fragen Sie also ab hier nach.
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)

Das ist eine Optimierung, nie eine Zusage. Code, der task.Task ohne die Nil-Prüfung liest, funktioniert genau bis zur ersten Generierung, die länger dauert als das Budget – und läuft dann im Produktivbetrieb in einen Panic.

Mit einer lokalen Datei beginnen

Bild-zu-Video, Motivtausch und Bildbearbeitung brauchen Ihr Material zuerst auf unserer Seite. UploadFile erledigt den dreistufigen Upload – Ticket, PUT in den Speicher, Commit – in einem Aufruf und gibt eine spicy://-URI zurück. Diese URI kommt in Input.

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

Eine öffentlich erreichbare HTTPS-Adresse können Sie direkt in die Eingabe schreiben; dafür ist gar kein Upload nötig. Bilder werden bis 10 MiB angenommen, Audio und Video bis 90 MiB; siehe Medien.

Guthaben, Verbrauch und Verlauf

Alle drei beziehen sich auf den aufrufenden API-Schlüssel: Andere Schlüssel desselben Kontos und Generierungen, die in der Konsole gestartet wurden, sind nicht enthalten, und dass sie fehlen, ist kein Fehler.

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 wiederholt jeden Filter auf jeder Seite und bewegt nur den Cursor.
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 beendet den Durchlauf vorzeitig
    }); err != nil {
    return err
}

Datumsangaben sind UTC-Kalendertage in einem halboffenen Intervall [from, to) von höchstens 92 Tagen. Setzen Sie From und To fest, sobald ein Durchlauf Mitternacht UTC überschreiten kann. Leer gelassen, berechnet der Server sein eigenes Fenster – to ist der morgige Tag in UTC – auf jeder Seite neu; ein Durchlauf, der um 23:59 beginnt und um 00:01 weitergeht, stellt also zwei verschiedene Fragen und klebt die Antworten aneinander. Gemeldet wird das nirgends.

GetUsage ist für den Abgleich gedacht, nicht für den Fortschritt. Dahinter steht ein kontoweites Budget, das sich alle Schlüssel teilen, und dieser Begrenzer sperrt im Zweifelsfall: Wer ihn ständig abfragt, kann jeden anderen Schlüssel von seinen eigenen Auswertungen aussperren. Verfolgen Sie einen Task stattdessen mit WaitForTerminal. Abrechnungen können außerdem verspätet eintreffen, sodass sich eine heute gelesene Zahl morgen noch ändert.

Fehler

Fehlschläge kommen als *spicy.APIError zurück, erreichbar über errors.As:

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

Verzweigen Sie über Code, nie über die Meldung – Meldungen werden übersetzt, Codes nicht. HTTP 503 teilen sich drei verschiedene Business-Codes, der Status allein genügt also nicht, um zu entscheiden, was zu tun ist:

CodeBedeutungWas zu tun ist
40003Hochgeladene Bytes passen nicht zum TicketMit einem frischen Ticket neu beginnen
40004Keine Bereitstellung bedient diese ParameterkombinationDen in der Meldung genannten Parameter ändern
40201Guthaben reicht nichtGuthaben aufladen
40901Der Preis hat sich vor dem Anlegen geändertNeu schätzen, denselben Idempotenzschlüssel behalten
503Eine Abhängigkeit ist kurz nicht erreichbarGemäß RetryAfter warten
50301Gerade keine nutzbare Bereitstellung und kein PreisKatalog neu laden, nicht dauerhaft nachfragen
50302Synchrone Generierung bei der Ausführung fehlgeschlagen, erstattetMit einem neuen Idempotenzschlüssel wiederholen

Jeder Code steht unter Fehler. Nennen Sie RequestID, wenn Sie den Support kontaktieren.

Zwei Dinge, die Ihnen Geld sparen

Bleiben Sie pro Absendung bei einem Idempotenzschlüssel. Verwenden Sie ihn für jedes erneute Senden wieder, auch nach einem Timeout. Eine verlorene Antwort ist kein Beweis dafür, dass der Task nicht angelegt wurde – ein frischer Schlüssel macht aus einem unbekannten Ausgang einen zweiten kostenpflichtigen Task. Genau deshalb verlangt CreateTask den Schlüssel. Siehe Idempotenz.

Ein erfolgreicher Task wird berechnet, auch wenn das Ergebnis enttäuscht. Quote reserviert nichts, holen Sie also zuerst eine Kostenschätzung ein, wenn es auf den Preis ankommt.

Was dieses Paket nicht tut

  • Textmodelle. Sie sprechen die Formate von OpenAI, Anthropic und Gemini – die etablierten Go-Clients dafür funktionieren mit demselben Schlüssel bereits gegen https://api.spicyapi.ai/v1. Siehe Text und Streaming.
  • Anwendungen auf der Clientseite. Liefern Sie diesen Schlüssel niemals in einer Binärdatei aus, die Sie verteilen. Rufen Sie von Ihrem Server aus auf.
  • Ein Modell auswählen oder seine Felder ausfüllen. Es reicht Ihnen den Katalog und das Schema jedes Modells; was Sie senden, entscheiden Sie.
  • Einen Task abbrechen. Ist ein Task erst angenommen, läuft er bis zum Ende. Den context abzubrechen, stoppt nur Ihr Warten.

Quellcode

Das Modul steht unter MIT-Lizenz und wird offen unter github.com/spicyapi-ai/spicy-go entwickelt. Sein README ist die kürzeste vollständige Führung durch den Client; diese Seite ergänzt die Konzepte drumherum.

Nächste Schritte

Auf dieser Seite