spicyapiDokumentacja
Budowanie z API
Treść główna

Katalog modeli i schematy

Korzystaj z uwierzytelnionego katalogu na żywo, aby wybierać dostępne modele, odczytywać ich ceny i budować żądania według aktualnego JSON Schema.

createTask.model przyjmuje dokładną wartość model zwróconą w uwierzytelnionej odpowiedzi GET /api/v1/models. Jego input definiuje aktualne inputSchema tej samej pozycji. Ta odpowiedź otrzymana podczas działania aplikacji jest jedynym źródłem prawdy o identyfikatorze dostępnym do wywołania.

Nie kopiuj identyfikatora ze statycznej strony

Migawki z momentu premiery, strony rodzin modeli i katalogi twórców modeli pomagają odkrywać ofertę. Mogą zawierać pozycje planowane, wyłączone lub przemianowane i nigdy nie mogą być źródłem zastępczym, gdy katalog na żywo jest pusty. Przed płatną operacją pobierz uwierzytelniony katalog i wymagaj zarówno enabled: true, jak i available: true.

W przykładach na tej stronie MODEL_ID_FROM_CATALOG jest symbolem zastępczym, a nie prawdziwym modelem: zastąp go wartością model z własnego katalogu na żywo. Odczyt katalogu jest bezpłatny.

Wybierz model i jego zwalidowane dane wejściowe

Schematy żądań różnią się między modelami, więc bezpieczny sposób uruchomienia wybiera razem dostępny model i jeden z jego przykładów zwalidowanych przez serwer:

const response = await fetch(
  'https://api.spicyapi.ai/api/v1/models?includeSchema=1&includeExamples=1',
  { headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` } },
);
const envelope = await response.json();
if (!response.ok || envelope.code !== 200) throw new Error(envelope.msg);

const selected = envelope.data.items.find(
  (item) => item.enabled && item.available && item.examples?.length,
);
if (!selected) throw new Error('No callable model with a validated example');

const createTaskBody = {
  model: selected.model,
  input: selected.examples[0].input,
};

Każdy przykład to kompletne input, które serwer już sprawdził względem aktualnego schematu, więc można wysłać je bez zmian.

Odczytuj katalog programowo

GET /api/v1/models
GET /api/v1/models/{model}
curl "https://api.spicyapi.ai/api/v1/models?modality=video" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Lista nie ma paginacji: jedna odpowiedź zawiera wszystkie modele widoczne dla twojego klucza i pasujące do filtrów. Wszystkie parametry są opcjonalne.

ParametrZnaczenie
modalityimage, video, audio lub text
providerTwórca modelu, dopasowywany dokładnie z uwzględnieniem wielkości liter, na przykład ByteDance. Skopiuj go z provider danej pozycji
taskJedno zadanie, na przykład text-to-image, edit (edycja obrazów), image-to-video, text-to-video, reference-to-video, speech-to-text, video-analyze, video-edit, video-extend, character-animation lub chat. Aktualny zestaw odczytaj z tasks w katalogu. Edycja obrazów ma dwa akceptowane zapisy: modele są publikowane jako .../edit, ale tasks klasyfikuje je jako image-to-image, a filtr przyjmuje oba
searchTekst dopasowywany bez uwzględniania wielkości liter w dowolnym miejscu identyfikatora lub nazwy wyświetlanej modelu, do 128 znaków
includeSchematrue lub 1 dodaje inputSchema każdej pozycji
includeExamplestrue lub 1 dodaje examples każdej pozycji, zwalidowane względem aktualnego schematu

Endpoint pojedynczego modelu, GET /api/v1/models/{model}, zawsze zawiera inputSchema i examples; includeSchema i includeExamples mają znaczenie tylko dla listy. Ukośniki w identyfikatorze mogą pozostać bez zmian; koduj je procentowo tylko wtedy, gdy klient HTTP traktuje parametr ścieżki jako pojedynczy segment. Model, który nie istnieje lub nie jest obecnie oferowany, zwraca 404.

Skrócona odpowiedź listy:

{
  "code": 200,
  "msg": "success",
  "data": {
    "total": 1,
    "items": [
      {
        "model": "MODEL_ID_FROM_CATALOG",
        "family": "…",
        "displayName": "…",
        "provider": "…",
        "modality": "video",
        "tasks": ["image-to-video"],
        "async": true,
        "enabled": true,
        "available": true,
        "availability": "available",
        "taskTimeoutSeconds": 1200,
        "maxOutputDurationSeconds": 10,
        "quantityField": "duration_seconds",
        "pricing": [
          { "variant": "generate_audio=false;resolution=720p", "unit": "per_second", "price": "0.05", "currency": "USD" },
          { "variant": "generate_audio=true;resolution=720p", "unit": "per_second", "price": "0.08", "currency": "USD" }
        ],
        "startingPrice": { "variant": "generate_audio=false;resolution=720p", "unit": "per_second", "price": "0.05", "currency": "USD" },
        "badges": ["audio_output"],
        "relatedModels": [],
        "version": "v1",
        "updatedAt": "2026-09-16T16:47:57Z"
      }
    ]
  },
  "request_id": "req_01k3m8x9q2z4v7n5p6r8s0t1w2"
}

Powyższe ceny są przykładowe. inputSchema i examples pojawiają się w pozycjach listy tylko wtedy, gdy o nie poprosisz.

Pola, z których powinien korzystać klient

PolePrzeznaczenie
modelDokładna wartość przesyłana jako createTask.model, w postaci publisher/model/task
familyStabilny identyfikator rodziny produktu do grupowania powiązanych endpointów
displayNameCzytelna dla człowieka nazwa tego endpointu
providerTwórca modelu, na przykład laboratorium, które go zbudowało
modality / tasksRodzaj mediów, pod którym endpoint jest grupowany w katalogu, oraz wykonywane zadanie. modality steruje przeglądaniem i filtrem modality; nie gwarantuje rodzaju pliku wynikowego — endpoint speech-to-text jest grupowany pod audio, a odpowiada tekstem. Zobacz Struktura wyniku
toolkitRodzina narzędzi, do której należy endpoint, obecnie tylko subject-swap. Pole jest nieobecne, gdy model nie należy do zestawu narzędzi, więc sprawdzaj wartość, a nie sam klucz. Podobnie jak badges jest klasyfikacją i nigdy nie wpływa na przyjęcie żądania, cenę ani walidację. Zobacz Podmiana obiektu
asynctrue: utwórz zadanie i odbierz wynik przez odpytywanie lub webhook. false: odpowiedź wraca bezpośrednio w odpowiedzi na żądanie
inputSchemaJSON Schema 2020-12 używany do generowania formularzy i walidacji żądań
examplesDane wejściowe zwalidowane względem aktualnego schematu; na liście zwracane tylko na żądanie
enabledCzy pozycję można teraz wywołać. Katalog zawiera też pozycje opublikowane, ale jeszcze nieudostępnione, oraz pozycje wstrzymane przez platformę; dla nich zwracane jest false. Sprawdzaj je razem z available przed wysłaniem zadania
availableCzy model można teraz wywołać. false oznacza, że wywołanie się nie powiedzie, na przykład z powodu braku aktualnej ceny
availabilityDeklarowany etap: planned, available, preview (pola i wyniki mogą się jeszcze zmieniać) lub maintenance (przejściowe problemy, przewidywany powrót)
pricing / startingPriceTwoje ceny; zobacz Odczytywanie cen
quantityFieldPole wejściowe, którego wartość stanowi rozliczaną ilość, zwykle duration_seconds dla wideo. Pusta wartość oznacza, że każde wywołanie liczy się jako jedna jednostka. Zawsze odczytuj je z katalogu
taskTimeoutSecondsTermin wykonania jednego zadania ustalony przez platformę. To nie długość mediów
maxOutputDurationSecondsNajdłuższy wynik możliwy do wygenerowania przez model, pobierany z maximum jego właściwości duration_seconds; pole jest pomijane, gdy nie zadeklarowano maksimum
badgesOznaczenia możliwości i licencji, takie jak commercial_use lub no_watermark. Ignoruj nierozpoznane wartości
relatedModelsRęcznie wybrane alternatywy lub kolejne kroki, jako identyfikatory modeli dostępnych do wywołania
version / updatedAtŚledzenie zmian: porównaj je, aby ustalić, czy kolejny odczyt przyniósł zmianę

mature i policyTier to oznaczenia informacyjne. Nie uczestniczą w decyzji o przyjęciu żądania.

Odczytywanie cen

Każda pozycja w pricing oznacza jeden poziom ceny:

PoleZnaczenie
unitper_image, per_second (wynikowych mediów), per_request lub per_1k_tokens
priceTwoja cena jednostkowa w dolarach amerykańskich jako ciąg dziesiętny. Uwzględnia już stawki konta, które mogą różnić się między kontami
variantUstawienia wybierające ten poziom ceny. Puste, gdy model ma jedną cenę; sama wartość (na przykład 720p), gdy poziom wybiera jedno pole; pary field=value połączone ; i posortowane według nazwy pola (na przykład generate_audio=false;resolution=480p), gdy wybiera go kilka pól
currencyZawsze USD
regularPrice, offerLabel, offerPercent, offerEndsAtObecne tylko podczas oferty dla klienta: cena przed ofertą, nazwa oferty, jej procent i termin zakończenia

startingPrice to najtańsza pozycja, a nie cena twoich ustawień. Pola wybierające poziom ceny są wymienione w inputSchema["x-pricing"].variantFields, jeśli to pole istnieje; w przeciwnym razie są to pola oznaczone x-ui.affects_price: true (z wyjątkiem quantityField). Pominięte pole jest liczone według jego schematowego default.

  • Modele multimedialne: koszt to price × quantity, gdzie ilość jest wartością quantityField w twoich danych wejściowych (lub jedną jednostką, jeśli quantityField jest puste). Niektóre endpointy następnie doliczają osobną opłatę za każde dodatkowe wejście, najczęściej za każdy obraz referencyjny. Traktuj ją jako rzeczywistą część rachunku, a nie szczegół zaokrąglenia: w endpoincie edycji przyjmującym tablicę obrazów referencyjnych wypełnienie tablicy może zwielokrotnić kwotę, choć unit, quantity, variant i cena price poziomu pozostają dokładnie takie jak dla jednego obrazu — powyższy rachunek zaniża więc kwotę bez widocznego sygnału. Maszynowo rozpoznasz to po polu oznaczonym x-ui.affects_price: true, które nie jest ani quantityField, ani polem wymienionym w x-pricing.variantFields: zmienia kwotę bez wybierania poziomu ceny. Dla takiego endpointu traktuj pricing jako dolną granicę i pobieraj kwotę z wyceny.
  • Modele tekstowe (per_1k_tokens): jedna liczba nie opisuje całej opłaty. price jest wyłącznie stawką za tokeny wyjściowe, na 1 000 tokenów. Tokeny wejściowe i wejściowe z pamięci podręcznej mają własne, zwykle niższe stawki i są rozliczane według zmierzonego użycia każdego wywołania. Nie mnoż price przez łączną liczbę tokenów. Ceny za milion tokenów wejściowych, wejściowych z pamięci podręcznej i wyjściowych są podane na stronie każdego modelu oraz w price.perMillionTokens publicznego katalogu.

Aby poznać kwotę jednego dokładnego żądania natywnego API przed płatnością, użyj POST /api/v1/jobs/quote. Ostateczne opłaty są w rekordzie zadania (cost przy settled: true) i w Rozliczeniach.

Buforowanie katalogu

  • Odpowiedź katalogu można przechowywać w pamięci podręcznej przez najwyżej 60 sekund (Cache-Control: private, max-age=60). Przechowuj ją wyłącznie w prywatnej pamięci dla danego konta: ceny są przypisane do konta, więc nigdy nie umieszczaj jej za współdzieloną lub publiczną pamięcią CDN.
  • Ponadto nie odczytuj katalogu ponownie przed każdym zadaniem. Odczyty katalogu korzystają z osobnego limitu odczytów konta i nie zużywają limitu wysyłania zadań. Pobieranie katalogu przed każdym wywołaniem nadal marnuje dostępną liczbę odczytów; zobacz Limity żądań.
  • Odświeżaj go okresowo (na przykład co kilka minut), po błędzie walidacji 400 oraz gdy wysłanie zadania do danego modelu zostanie odrzucone.
  • Zachowaj version i updatedAt użytego rekordu, aby móc stwierdzić, czy późniejszy odczyt coś zmienił.
  • Nigdy nie dostarczaj schematu wpisanego na stałe do kodu ani nie korzystaj ze statycznej strony jako zamiennika, gdy katalog na żywo nie ma pozycji dostępnej do wywołania.

Wspólne zasady schematu i Playground

inputSchema używa JSON Schema 2020-12. Standardowe słowa kluczowe sterują walidacją serwera; obiekt x-ui na poziomie właściwości opisuje jedynie kolejność w Playground, prezentację i wskazówki odświeżania wyceny. Klient musi ignorować nieznane rozszerzenia prezentacji, które nigdy nie zastępują required, wartości enum, granic ani gałęzi warunkowych. Zobacz pełny Kontrakt Spicy Schema.

Wyrenderuj własną tabelę parametrów każdego modelu

Ta strona nie zawiera tabel parametrów poszczególnych modeli. Nie wynika to z zaniedbania: modele i pola zmieniają się co tydzień, każda statyczna kopia staje się nieaktualna, a skutkiem odczytania starego parametru może być 400 lub błędna cena. Parametry mają dokładnie jedno źródło — inputSchema zwracane przez katalog. Playground renderuje ten sam dokument, a SDK waliduje dane względem niego.

Jak przełożyć części schematu na tabelę

W schemacieW twojej tabeli parametrów
klucz propertiesnazwa parametru. Nazwy pól są ujednolicone między modelami: jedno znaczenie, jedna nazwa wszędzie
obecność w requiredwymagany lub opcjonalny
anyOf / allOfwymagany warunkowo. anyOf = podaj co najmniej jedno z tych pól; w allOf reguła if → then = jeśli podasz A, musisz podać B
typetyp
descriptiontekst objaśnienia. Jest po angielsku i można go wyświetlić bez zmian; nie musisz pisać własnego
enumakceptowane wartości. Jeśli istnieje x-ui.enum_labels, użyj go do zamiany wartości na czytelne etykiety
minimum / maximumakceptowany zakres; x-ui.step to krok, a x-ui.unit przyrostek jednostki (s, px)
minItems / maxItemsdla tablicy: liczba akceptowanych wpisów. Wiersz bez tego nie mówi użytkownikowi nic o limicie, który napotka
itemsdla tablicy: struktura jednego wpisu. Gdy items.type to object, ten podschemat jest samodzielnym, pełnym schematem obiektu: odczytaj jego required, additionalProperties oraz type, description, zakres i default każdego podpola i przedstaw je jako zagnieżdżoną tabelę zamiast pola swobodnego tekstu
defaultwartość domyślna stosowana po pominięciu pola
x-ui.orderklucz sortowania, od największej wartości. Nie sortuj według kolejności kluczy w properties — kolejność kluczy obiektu JSON nie jest częścią kontraktu
x-ui.primaryprzypnij na górze jako główne pole wejściowe
x-ui.advancedmożna zwinąć do sekcji zaawansowanej
x-ui.affects_priceoznacz jako wpływające na cenę; zmiana wartości uzasadnia nową wycenę
x-ui.widgetkontrolka do wyrenderowania w edytowalnym formularzu (trzynaście wartości, zobacz Spicy Schema)

Gałęzie warunkowe występują tylko w korzeniu inputSchema, w dwóch postaciach: anyOf, gdzie każda gałąź wymienia tylko pola required („podaj co najmniej jedno z tych pól”), oraz allOf, gdzie każda gałąź ma postać if → then („jeśli podasz A, musisz podać B”). Nie wyprowadzaj ich z rodziny modelu i nie oczekuj oneOf, not ani dependentSchemas. Nowe endpointy używają standardowych pól Spicy Schema; starsze — własnego schematu na żywo.

Pobieranie schematu

const modelId = 'MODEL_ID_FROM_CATALOG'; // the exact `model` value from GET /api/v1/models
const res = await fetch(`https://api.spicyapi.ai/api/v1/models/${modelId}`, {
  headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` },
});
const { data } = await res.json();
const schema = data.inputSchema;

const rows = Object.entries(schema.properties)
  .sort(([, a], [, b]) => (b['x-ui']?.order ?? 0) - (a['x-ui']?.order ?? 0))
  .map(([name, prop]) => ({
    name,
    required: (schema.required ?? []).includes(name),
    type: prop.type,
    description: prop.description,
    values: prop.enum
      ? prop.enum.map((v) => prop['x-ui']?.enum_labels?.[v] ?? v)
      : prop.minimum !== undefined || prop.maximum !== undefined
        ? [`${prop.minimum ?? ''}–${prop.maximum ?? ''}${prop['x-ui']?.unit ?? ''}`]
        : [],
    default: prop.default,
    affectsPrice: prop['x-ui']?.affects_price === true,
    advanced: prop['x-ui']?.advanced === true,
  }));

Ten szkic celowo kończy się na wartościach skalarnych: dla tablicy pozostawia values puste, ponieważ tablica opisuje akceptowane dane w items, minItems i maxItems, a nie w enum lub zakresie. Rozbuduj go przed wydaniem — wiersz, który przedstawia parametr tablicowy jedynie jako array, bez struktury wpisu i limitu długości, nie pozwala użytkownikowi ustalić, co ma wpisać.

Rekord pojedynczego modelu zwraca też examples: każdy jest kompletnym wejściem już zwalidowanym po stronie serwera względem aktualnego schematu, więc sprawdza się zarówno jako minimalny działający przykład w dokumentacji, jak i jako treść żądania gotowa do wysłania bez zmian. To bezpieczniejsze niż ręczne tworzenie przykładu, ponieważ ręczny przykład staje się nieaktualny po zmianie schematu, a examples nie.

Ten sam kod obsługuje dowolny model po zmianie modelId i nie traci ważności po dodaniu nowych modeli. Aby wygenerować tabelę całego katalogu, przejdź po items z GET /api/v1/models?includeSchema=1 i przechowuj ją w pamięci podręcznej zgodnie z Buforowaniem katalogu.

Objaśnienia dłuższe niż description

description to jedno zdanie o długości odpowiedniej do etykiety formularza. Gdy parametr wymaga szerszego wyjaśnienia, publiczny katalog udostępnia dodatkową notatkę dla każdego parametru:

curl "https://api.spicyapi.ai/console/v1/catalog/models/MODEL_ID_FROM_CATALOG?locale=en"

Rekord pojedynczego modelu zwraca paramNotes, obiekt z kluczami będącymi nazwami parametrów, dostępny w dowolnym z dziesięciu języków dokumentacji przez locale. To miejsce na informacje, które nie mieszczą się w etykiecie — względem czego rzeczywiście mierzona jest wartość, jakie ustawienie zauważalnie spowalnia wywołanie i jakie dane wejściowe są przyjmowane przez schemat, ale nadal dają rozczarowujący wynik. Dla parametru wskazującego samodzielnie hostowany plik zwykle tylko tam opisano, czy go pobieramy, kiedy to robimy i co się stanie, gdy okaże się bezużyteczny.

Są dwie granice: paramNotes występuje w publicznym katalogu, który nie wymaga klucza, a nie w uwierzytelnionym GET /api/v1/models, więc odczytuj je osobno i buforuj obok schematu. Ponadto jest tekstowym objaśnieniem, nigdy regułą — inputSchema pozostaje jedynym źródłem decydującym o przyjęciu żądania.

Na tej stronie