SDK dla PHP
Oficjalne SDK SpicyAPI dla PHP (spicyapi/spicyapi): instalacja przez Composera, wycena i pierwsza generacja, wysyłanie plików z dysku, bezpieczna weryfikacja webhooków i obsługa wszystkich kodów błędów.
spicyapi/spicyapi to oficjalne SDK SpicyAPI dla PHP. Generowanie obrazów, wideo i dźwięku chowa za jednym SpicyClient: dołącza twój klucz API, rozpakowuje strukturę odpowiedzi do zwykłych tablic asocjacyjnych, czeka na zadanie z ograniczonym wydłużaniem odstępów, wysyła pliki z dysku jednym wywołaniem i weryfikuje podpisy webhooków, nie popełniając przy tym żadnego z trzech błędów, które kod w PHP popełnia w tym miejscu najczęściej.
Wymaga PHP 8.1 lub nowszego oraz rozszerzeń ext-json i ext-hash, a nie ma żadnych zależności bibliotecznych. Z ext-curl korzysta, jeśli jest dostępne; bez niego klient sięga po opakowanie strumieniowe https://.
Czy to właściwe narzędzie?
| Chcesz… | Użyj |
|---|---|
| Wywoływać SpicyAPI z własnego kodu w PHP | Tego SDK |
| Wywoływać je z Node.js albo TypeScriptu | SDK dla TypeScriptu |
| Wywoływać je z Pythona, Go albo Javy | SDK dla Pythona, SDK dla Go albo SDK dla Javy |
| Generować z terminala, bez pisania kodu | CLI |
| Pozwolić, żeby asystent AI wywoływał SpicyAPI za ciebie | Serwer MCP i Agent Skill |
| Korzystać z modelu czatu albo modelu tekstowego | Uznanego klienta PHP dla formatów OpenAI, Anthropic albo Gemini – zobacz Tekst i streaming |
Instalacja
composer require spicyapi/spicyapiKlucz trzymaj w zmiennej środowiskowej, żeby nigdy nie pojawił się w twoim kodzie ani w systemie kontroli wersji:
export SPICY_API_KEY="sk-spicy-..."Pierwszy wynik
Zapytaj o cenę, zdecyduj, utwórz zadanie, poczekaj, odczytaj pliki. Wycena jest bezpłatna i niczego nie blokuje.
use SpicyApi\SpicyClient;
$client = new SpicyClient(); // odczytuje SPICY_API_KEY ze zmiennej środowiskowej
$quote = $client->quote('MODEL_ID_FROM_CATALOG', ['prompt' => 'a lantern in fog']);
printf("at most %s\n", $quote['maxCharge']); // zdecyduj, zanim wydasz pieniądze
$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";
}Każde wywołanie zwraca zdekodowane data ze struktury odpowiedzi jako zwykłą tablicę asocjacyjną, więc czytaj je przez $quote['maxCharge'], a nie $quote->maxCharge.
MODEL_ID_FROM_CATALOG to symbol zastępczy. Prawdziwy identyfikator bierz z uwierzytelnionego katalogu na żywo — $client->listModels(), czyli GET /api/v1/models — a nigdy z pamięci ani ze starej strony: modele są dodawane, wstrzymywane i wycofywane. Dane wejściowe buduj na podstawie inputSchema tego konkretnego modelu, które zwraca listModels(); każdy model przyjmuje inne pola.
Kwoty to dziesiętne łańcuchy znaków w dolarach amerykańskich, nigdy liczby zmiennoprzecinkowe, bo binarne liczby zmiennoprzecinkowe nie potrafią dokładnie zapisać większości kwot dziesiętnych. Porównuj je przez SpicyClient::compareUsd(). W tym API nigdzie nie ma kredytów ani punktów.
waitForTerminal kończy się na każdym stanie końcowym, a stan końcowy to jeszcze nie stan udany. Zanim sięgniesz po wynik, sprawdź stan, a przy endpointach, które odpowiadają tekstem zamiast plikami, najpierw czytaj SpicyClient::outputText($final).
Pomiń pierwsze odpytanie
waitSeconds trzyma połączenie otwarte aż do końca zadania, więc krótka praca w ogóle nie potrzebuje pętli odpytującej. Nie obiecuje jednak zakończonego zadania. Gdy budżet czasu się wyczerpie, dostaniesz zwykłą odpowiedź o przyjęciu zadania — ten sam kształt, inny state — więc rozgałęziaj logikę po stanie, nigdy po samym fakcie, że przekazałeś ten parametr:
$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']);
}Zacznij od pliku z dysku
Generowanie wideo z obrazu, podmiana osoby i edycja obrazu wymagają, żeby twój materiał najpierw trafił na naszą stronę. uploadFile wykonuje wysyłkę w trzech krokach — pozwolenie na wysyłkę, PUT do magazynu, commit — w jednym wywołaniu i zwraca URI spicy://. To właśnie ten URI trafia do danych wejściowych.
$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(),
);Publicznie dostępny adres HTTPS możesz podać w danych wejściowych wprost i wtedy nie musisz niczego wysyłać. Limit dla obrazów to 10 MiB, dla dźwięku i wideo – 90 MiB; zobacz Media.
Webhooki
use SpicyApi\SpicyWebhook;
// Najpierw sekret. Pozostałe argumenty są opcjonalne: $_SERVER i surowe bajty
// z php://input zostaną odczytane za ciebie, chyba że framework już je pochłonął.
$delivery = SpicyWebhook::verifyRequest(getenv('SPICY_WEBHOOK_SECRET') ?: '');
// We frameworku, który buforuje treść żądania, sam podaj dokładne bajty:
$delivery = SpicyWebhook::verifyRequest(
secret: getenv('SPICY_WEBHOOK_SECRET') ?: '',
server: $_SERVER,
rawBody: $request->getContent(),
);Trzy sposoby, na jakie kod w PHP zwykle to psuje – a których ta klasa unika:
- Ponowna serializacja treści przed weryfikacją.
json_decode, a po nimjson_encode, zmienia bajty i podpis już nigdy się nie zgodzi. Weryfikuj surowe bajty. - Porównywanie podpisów przez
==albo===. Poza kwestią czasu wykonania==na dwóch łańcuchach, które oba wyglądają jak0e…, porównuje je jak liczby —"0e123" == "0e456"dajetrue. Tutaj używane jesthash_equals. - Pominięcie sprawdzenia znacznika czasu. Prawidłowy podpis zostaje prawidłowy na zawsze; bez okna świeżości przechwycone dostarczenie da się odtworzyć.
Dostarczenia są ponawiane, więc odsiewaj duplikaty po identyfikatorze dostarczenia. Pełny format dostarczenia i harmonogram ponowień opisuje strona Webhooki.
Saldo, zużycie i historia
$balance = $client->getBalance(); // available / held / total, kwoty w USD jako tekst
$usage = $client->getUsage('2026-09-01', '2026-09-08'); // rozliczone wydatki w przedziale [from, to)
foreach ($client->iterTasks(state: 'succeeded') as $summary) {
echo $summary['taskId'], "\n"; // wszystkie strony, filtry powtarzane za ciebie
}held to pieniądze zablokowane przez zadania, które jeszcze się nie rozliczyły, więc nie są ani wydane, ani dostępne. Daty to dni kalendarzowe UTC w formacie YYYY-MM-DD, tworzące przedział półotwarty [from, to) obejmujący najwyżej 92 dni. Wszystkie trzy wywołania widzą wyłącznie klucz API, którym wywołujesz: bratnie klucze ani generacje z konsoli się w nich nie mieszczą.
getUsage() służy do uzgadniania rachunków, nie do śledzenia postępu. Niesie ze sobą budżet zapytań obowiązujący dla całego konta, wspólny dla wszystkich kluczy, a ten ogranicznik przy problemach domyka się zamiast otwierać — odpytywanie go potrafi odciąć całe konto od jego własnych raportów. Za pojedynczym zadaniem podążaj przez getTask().
listTasks() zwraca jedną stronę jako {items, hasMore, nextCursor}. Stronicowanie ręczne oznacza powtarzanie wszystkich filtrów bez zmian i przesuwanie wyłącznie kursora, a także zatrzymanie się, gdy hasMore ma wartość false albo nextCursor jest pusty — sprawdzanie samego hasMore zamienia usterkę po stronie serwera w nieskończoną pętlę płatnych wywołań, która wygląda jak zawieszenie. iterTasks() robi to wszystko za ciebie.
Błędy
Niepowodzenia rzucają SpicyApiError z polami $businessCode, $requestId i $retryAfterSeconds. Rozgałęziaj logikę po kodzie aplikacyjnym, nigdy po komunikacie — komunikaty są tłumaczone, kody nie.
Status HTTP 503 dzielą między siebie trzy różne kody aplikacyjne, więc sam status nie powie ci, co zrobić:
| Kod | Co to znaczy | Co zrobić |
|---|---|---|
40003 | przesłane bajty nie zgadzają się ze swoim pozwoleniem na wysyłkę | zacznij od nowa, od świeżego pozwolenia |
40004 | żadne wdrożenie nie obsługuje tej kombinacji parametrów | zmień parametr wskazany w komunikacie |
40201 | za niskie saldo | doładuj konto |
409 | ten klucz idempotentności został użyty do innego żądania | wyślij pod tym kluczem pierwotne żądanie albo zmienione pod nowym kluczem |
40901 | cena zmieniła się, zanim powstało zadanie | wyceń ponownie, zachowując ten sam klucz idempotentności |
503 | składnik, od którego zależymy, jest chwilowo niedostępny | odczekaj tyle, ile mówi Retry-After |
50301 | nie ma teraz działającego wdrożenia ani ceny | odśwież katalog |
50302 | generacja synchroniczna nie powiodła się podczas przetwarzania i została zwrócona | ponów z nowym kluczem idempotentności |
$error->guidance() zwraca tę samą wskazówkę w czasie działania programu. Wszystkie kody wymienia strona Błędy.
Dwie rzeczy, które oszczędzą ci pieniędzy
Miej jeden klucz idempotentności na jedno zgłoszenie i używaj go przy każdym ponownym wysłaniu — utracona odpowiedź nie dowodzi, że zadanie nie powstało. Zobacz Idempotentność.
Za udane zadanie płacisz, nawet jeśli wynik cię rozczaruje. quote() niczego nie blokuje i niczego nie tworzy.
Czego ten pakiet nie robi
- Modeli tekstowych. Mówią formatami OpenAI, Anthropic i Gemini; uznani klienci PHP dla tych formatów działają z
https://api.spicyapi.ai/v1od ręki. Zobacz Tekst i streaming. - Kodu po stronie przeglądarki. Klucz należy do twojego serwera, nigdy do czegokolwiek, co wysyłasz odwiedzającemu.
- Wyboru modelu ani wypełniania jego pól. Pakiet podaje ci katalog i schemat każdego modelu; o tym, co wysłać, decydujesz ty.
- Anulowania zadania. Przyjęte zadanie wykonuje się do końca.
Kod źródłowy
Pakiet jest na licencji MIT i powstaje otwarcie pod adresem github.com/spicyapi-ai/spicy-php. Jego README to najkrótsza kompletna wycieczka po kliencie, a w katalogu examples/ leżą gotowe do uruchomienia skrypty; ta strona dokłada do tego pojęcia, które go otaczają.
Co dalej
Katalog modeli i schematy
Jak czytać inputSchema modelu i dobierać prawidłowe dane wejściowe
Zadania asynchroniczne
Stany zadań, odpytywanie i znaczenie każdego pola
Wyceny i zgodność protokołów
Poznaj dokładną cenę żądania, zanim za nie zapłacisz
Webhooki
Format dostarczeń, harmonogram ponowień i weryfikacja podpisu
Błędy
Wszystkie kody błędów i to, które z nich warto ponawiać
SDK dla Javy
Ten sam proces w Javie, z zapieczętowaną taksonomią błędów
SDK dla Go
Oficjalne SDK SpicyAPI dla Go (github.com/spicyapi-ai/spicy-go): instalacja, wycena i pierwsza generacja, wysyłanie plików z dysku, przeglądanie historii zadań i obsługa wszystkich kodów błędów.
SDK dla Javy
Oficjalne SDK SpicyAPI dla Javy (ai.spicyapi spicyapi-java, Java 17+): instalacja, wycena i pierwsza generacja, wysyłanie plików z dysku, weryfikacja callbacków i wyczerpujący switch po zapieczętowanej taksonomii błędów.

