PHP-SDK
Das offizielle PHP-SDK für SpicyAPI (spicyapi/spicyapi) – mit Composer installieren, die erste Generierung schätzen und ausführen, eine lokale Datei hochladen, Webhooks sicher prüfen und jeden Fehlercode behandeln.
spicyapi/spicyapi ist das offizielle PHP-SDK für SpicyAPI. Es legt die Erzeugung von Bildern, Videos und Audio hinter einen einzigen SpicyClient: Er hängt Ihren API-Schlüssel an, packt den Antwort-Envelope in schlichte assoziative Arrays aus, wartet mit begrenztem Back-off auf einen Task, lädt lokale Dateien in einem Aufruf hoch und prüft Webhook-Signaturen, ohne einen der drei Fehler zu machen, die PHP-Code an dieser Stelle üblicherweise macht.
Es setzt PHP 8.1 oder neuer sowie ext-json und ext-hash voraus und hat keine Bibliotheksabhängigkeiten. ext-curl wird genutzt, wenn es vorhanden ist; fehlt es, weicht der Client auf den Stream-Wrapper https:// aus.
Ist das das richtige Werkzeug?
| Sie möchten … | Verwenden Sie |
|---|---|
| SpicyAPI aus Ihrem eigenen PHP-Code aufrufen | Dieses SDK |
| Es aus Node.js oder TypeScript aufrufen | Das TypeScript-SDK |
| Es aus Python, Go oder Java aufrufen | Das Python-, Go- oder Java-SDK |
| Ohne Code aus einem Terminal heraus generieren | Die CLI |
| Einen KI-Assistenten SpicyAPI für Sie aufrufen lassen | Den MCP-Server und den Agent Skill |
| Ein Chat- oder Textmodell nutzen | Einen etablierten PHP-Client für die Formate von OpenAI, Anthropic oder Gemini – siehe Text und Streaming |
Installieren
composer require spicyapi/spicyapiLegen Sie Ihren Schlüssel in die Umgebung, damit er weder in Ihrem Code noch in der Versionsverwaltung 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.
use SpicyApi\SpicyClient;
$client = new SpicyClient(); // liest SPICY_API_KEY aus der Umgebung
$quote = $client->quote('MODEL_ID_FROM_CATALOG', ['prompt' => 'a lantern in fog']);
printf("at most %s\n", $quote['maxCharge']); // entscheiden, bevor Sie Geld ausgeben
$task = $client->createTask(
model: $quote['model'],
input: ['prompt' => 'a lantern in fog'],
idempotencyKey: SpicyClient::idempotencyKey(),
quoteId: $quote['quoteId'],
expectedCost: $quote['estimatedCost'],
);
$final = $client->waitForTerminal($task['taskId']);
foreach (SpicyClient::readyAssets($final) as $asset) {
echo $asset['url'], "\n";
}Jeder Aufruf gibt das dekodierte data des Antwort-Envelopes als schlichtes assoziatives Array zurück; lesen Sie es also mit $quote['maxCharge'], nicht mit $quote->maxCharge.
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 die Eingabe 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. Vergleichen Sie sie mit SpicyClient::compareUsd(). Credits oder Punkte gibt es in dieser API nirgends.
waitForTerminal kehrt bei jedem Endzustand zurück, und ein Endzustand ist kein erfolgreicher Zustand. Prüfen Sie den Status, bevor Sie die Ausgabe lesen, und rufen Sie bei Endpunkten, die mit Text statt mit Dateien antworten, zuerst SpicyClient::outputText($final) auf.
Die erste Abfrage überspringen
waitSeconds hält die Verbindung offen, bis der Task fertig ist; ein kurzer Auftrag braucht damit gar keine Abfrageschleife. Einen fertigen Task sagt der Parameter nicht zu. Läuft das Budget ab, bekommen Sie stattdessen die gewöhnliche Annahmeantwort – gleiche Form, anderer state. Verzweigen Sie deshalb über den Status, nie darüber, dass Sie den Parameter mitgegeben haben:
$submitted = $client->createTask(
model: 'MODEL_ID_FROM_CATALOG',
input: ['prompt' => 'a lantern in fog'],
idempotencyKey: SpicyClient::idempotencyKey(),
waitSeconds: 30,
);
if (!SpicyClient::isTerminal($submitted)) {
$submitted = $client->waitForTerminal($submitted['taskId']);
}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 die Eingabe.
$uploaded = $client->uploadFile('/path/to/reference.png');
$task = $client->createTask(
model: 'MODEL_ID_FROM_CATALOG',
input: ['image' => $uploaded['uri'], 'prompt' => 'slow dolly in'],
idempotencyKey: SpicyClient::idempotencyKey(),
);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.
Webhooks
use SpicyApi\SpicyWebhook;
// Das Geheimnis kommt zuerst. Die übrigen Argumente sind optional: $_SERVER und die rohen
// Bytes von php://input werden gelesen, sofern ein Framework sie nicht schon verbraucht hat.
$delivery = SpicyWebhook::verifyRequest(getenv('SPICY_WEBHOOK_SECRET') ?: '');
// In einem Framework, das den Body puffert, übergeben Sie die exakten Bytes selbst:
$delivery = SpicyWebhook::verifyRequest(
secret: getenv('SPICY_WEBHOOK_SECRET') ?: '',
server: $_SERVER,
rawBody: $request->getContent(),
);Drei Fehler, die PHP-Code hier macht und die diese Klasse allesamt vermeidet:
- Den Body vor der Prüfung neu serialisieren.
json_decodeund danachjson_encodeverändert die Bytes, und die Signatur passt dann nie. Prüfen Sie die rohen Bytes. - Signaturen mit
==oder===vergleichen. Über das Zeitverhalten hinaus vergleicht==zwei Zeichenketten, die beide wie0e…aussehen, als Zahlen –"0e123" == "0e456"ergibttrue. Diese Klasse verwendethash_equals. - Die Zeitstempelprüfung auslassen. Eine gültige Signatur bleibt für immer gültig; ohne Frischefenster lässt sich eine mitgeschnittene Zustellung erneut einspielen.
Zustellungen werden wiederholt; entdoppeln Sie deshalb über die Zustellungs-ID. Das vollständige Zustellformat und den Wiederholungsplan finden Sie unter Webhooks.
Guthaben, Verbrauch und Verlauf
$balance = $client->getBalance(); // verfügbar / reserviert / gesamt, USD-Zeichenketten
$usage = $client->getUsage('2026-09-01', '2026-09-08'); // abgerechnete Ausgaben über [from, to)
foreach ($client->iterTasks(state: 'succeeded') as $summary) {
echo $summary['taskId'], "\n"; // jede Seite, Filter werden wiederholt
}held ist Geld, das von noch nicht abgerechneten Tasks reserviert ist – es ist also weder ausgegeben noch verfügbar. Datumsangaben sind UTC-Kalendertage im Format YYYY-MM-DD und bilden ein halboffenes Intervall [from, to) von höchstens 92 Tagen. Alle drei Aufrufe sehen nur den aufrufenden API-Schlüssel: Andere Schlüssel und Generierungen aus der Konsole sind nicht enthalten.
getUsage() ist für den Abgleich gedacht, nicht für den Fortschritt. Dahinter steht ein kontoweites Anfragebudget, das sich alle Schlüssel teilen, und dieser Begrenzer sperrt im Zweifelsfall: Wer ihn ständig abfragt, kann das ganze Konto von seinen eigenen Auswertungen aussperren. Verfolgen Sie einen Task stattdessen mit getTask().
listTasks() liefert eine Seite als {items, hasMore, nextCursor}. Von Hand zu blättern heißt: jeden Filter unverändert wiederholen, nur den Cursor bewegen und aufhören, sobald hasMore false oder nextCursor leer ist. Wer nur hasMore prüft, macht aus einem Aussetzer auf der Serverseite eine Endlosschleife kostenpflichtiger Aufrufe, die wie ein Hänger aussieht. iterTasks() erledigt all das.
Fehler
Fehlschläge werfen SpicyApiError mit $businessCode, $requestId und $retryAfterSeconds. Verzweigen Sie über den Business-Code, nie über die Meldung – Meldungen werden übersetzt, Codes nicht.
HTTP 503 teilen sich drei verschiedene Business-Codes, der Status allein sagt Ihnen also nicht, was zu tun ist:
| Code | Bedeutung | Was zu tun ist |
|---|---|---|
40003 | Hochgeladene Bytes passen nicht zum Ticket | Mit einem frischen Ticket neu beginnen |
40004 | Keine Bereitstellung bedient diese Parameterkombination | Den in der Meldung genannten Parameter ändern |
40201 | Guthaben reicht nicht | Guthaben aufladen |
409 | Der Idempotenzschlüssel wurde für eine andere Anfrage wiederverwendet | Die ursprüngliche Anfrage unter diesem Schlüssel senden – oder die geänderte unter einem neuen |
40901 | Der Preis hat sich vor dem Anlegen geändert | Neu schätzen, denselben Idempotenzschlüssel behalten |
503 | Eine Abhängigkeit ist kurz nicht erreichbar | Gemäß Retry-After warten |
50301 | Gerade keine nutzbare Bereitstellung und kein Preis | Katalog neu laden |
50302 | Synchrone Generierung bei der Ausführung fehlgeschlagen, erstattet | Mit einem neuen Idempotenzschlüssel wiederholen |
$error->guidance() liefert dieselbe Empfehlung zur Laufzeit. Jeder Code steht unter Fehler.
Zwei Dinge, die Ihnen Geld sparen
Bleiben Sie pro Absendung bei einem Idempotenzschlüssel und verwenden Sie ihn bei jedem erneuten Senden wieder – eine verlorene Antwort ist kein Beweis dafür, dass der Task nicht angelegt wurde. Siehe Idempotenz.
Ein erfolgreicher Task wird berechnet, auch wenn das Ergebnis enttäuscht. quote() reserviert nichts und legt nichts an.
Was dieses Paket nicht tut
- Textmodelle. Sie sprechen die Formate von OpenAI, Anthropic und Gemini; die etablierten PHP-Clients dafür funktionieren bereits gegen
https://api.spicyapi.ai/v1. Siehe Text und Streaming. - Code auf der Browserseite. Der Schlüssel gehört auf Ihren Server, nie in etwas, das Sie an Besucher ausliefern.
- 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.
Quellcode
Das Paket steht unter MIT-Lizenz und wird offen unter github.com/spicyapi-ai/spicy-php entwickelt. Sein README ist die kürzeste vollständige Führung durch den Client, und in examples/ liegen lauffähige Skripte; diese Seite ergänzt die Konzepte drumherum.
Nächste Schritte
Modellkatalog und Schemas
Wie Sie das inputSchema eines Modells lesen und gültige Eingaben wählen
Asynchrone Tasks
Task-Status, Polling und was jedes Feld bedeutet
Kostenschätzungen und Kompatibilität
Den exakten Preis einer Anfrage sehen, bevor Sie ihn zahlen
Webhooks
Zustellformat, Wiederholungsplan und Signaturprüfung
Fehler
Jeder Fehlercode und welche sich zu wiederholen lohnen
Java-SDK
Derselbe Ablauf in Java, mit einer versiegelten Fehlertaxonomie
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.
Java-SDK
Das offizielle Java-SDK für SpicyAPI (ai.spicyapi spicyapi-java) – installieren, die erste Generierung schätzen und ausführen, eine lokale Datei hochladen, Callbacks prüfen und vollständig über eine versiegelte Fehlertaxonomie verzweigen.

