Contratto Spicy Schema
Struttura condivisa delle richieste, campi canonici, schema dei moduli, ciclo asincrono, errori, archiviazione dei risultati e compatibilità.
Spicy Schema è il contratto pubblico per ogni nuovo modello multimediale. Aggiungere un modello cambia il suo model, l'inputSchema e il prezzo al cliente; autenticazione, attività, risultati, errori e download restano gli stessi.
Questa è una pagina di riferimento. Alla maggior parte delle integrazioni basta Catalogo dei modelli e schemi. Continua se stai costruendo da inputSchema un modulo, un validatore o un generatore di codice e vuoi sapere esattamente su cosa puoi contare.
Soltanto il catalogo aggiornato dimostra che un modello sia utilizzabile
Questa pagina definisce la struttura del contratto; non afferma che qualche modello sia disponibile. Prima di un'attività a pagamento, leggi la risposta autenticata di GET /api/v1/models e richiedi sia enabled: true sia available: true. Le voci pianificate o disabilitate non possono essere chiamate.
Confine pubblico
Un ID pubblico di modello identifica una capacità stabile nella forma <publisher>/<model>/<task>. Il publisher è il creatore del modello: l'autore o l'organizzazione di ricerca che lo ha sviluppato. La modifica di immagini usa sempre il suffisso edit e gli identificativi pubblicati in precedenza restano accettati. Copia sempre un ID reale dal catalogo aggiornato; MODEL_ID_FROM_CATALOG in questa pagina è un segnaposto.
Risposte pubbliche, webhook, errori e download usano soltanto identificativi, codici di errore e URL propri di SpicyAPI. Non contengono mai dettagli interni di elaborazione, risposte grezze, errori grezzi o dati aziendali interni. I risultati vengono copiati nello storage di SpicyAPI prima di essere restituiti.
Struttura unificata di creazione
{
"model": "MODEL_ID_FROM_CATALOG",
"input": {
"prompt": "slow camera push-in",
"image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3",
"duration_seconds": 8,
"resolution": "1080p",
"generate_audio": true
},
"callBackUrl": "https://your-app.example.com/hooks/spicy"
}| Campo | Regola |
|---|---|
model | Valore esatto, attualmente utilizzabile, del catalogo autenticato aggiornato |
input | Deve soddisfare l'inputSchema corrente della stessa voce; i campi sconosciuti vengono rifiutati |
callBackUrl | Indirizzo pubblico HTTPS facoltativo che riceve l'attività conclusa; usa esattamente queste maiuscole e minuscole. Consulta Webhook |
L'input sopra è illustrativo: soltanto l'inputSchema del modello definisce quali di questi campi siano accettati.
Campi canonici
Lo stesso concetto usa un unico nome snake_case in tutti i nuovi endpoint. Questa tabella elenca i campi comuni, non tutti i campi; l'inputSchema del modello è sempre l'elenco completo.
| Concetto | Campo | Tipo |
|---|---|---|
| Prompt positivo | prompt | stringa |
| Prompt negativo | negative_prompt | stringa |
| Immagine principale / finale | image_url / last_image_url | riferimento a un'immagine (vedi sotto) |
| Più immagini di input | image_urls | array di riferimenti a immagini |
| Maschera di modifica | mask_url | riferimento a un'immagine |
| Video / audio principale | video_url / audio_url | URL HTTPS pubblico oppure URI spicy:// confermato |
| Media di riferimento | reference_image_urls / reference_video_urls / reference_audio_urls | array di riferimenti |
| Durata dell'output | duration_seconds | numero oppure intero |
| Risoluzione / rapporto | resolution / aspect_ratio | enumerazione documentata |
| Dimensione esatta dell'output | size (un preset), oppure width / height | enumerazione documentata / intero |
| Frequenza dei fotogrammi | fps | intero |
| Audio nativo | generate_audio | booleano |
| Seed casuale | seed | intero |
| Pesi degli adattatori | loras, oppure high_noise_loras / low_noise_loras quando un endpoint espone separatamente le sue fasi | array di oggetti |
| Numero di output | num_outputs | intero positivo |
| Codifica | output_format | enumerazione documentata |
| Conversazione chat | messages | array |
| Lunghezza dell'output / campionamento | max_tokens / temperature | intero / numero |
Un riferimento a un'immagine è un URL HTTPS pubblico, un URI spicy:// confermato da un caricamento oppure un piccolo URI data:image/…;base64,…. Video e audio non possono essere inviati inline. Consulta Media.
Una voce dei pesi degli adattatori identifica un insieme di pesi e quanto intensamente applicarlo. Il nome del campo è fisso, la struttura della voce no: ciò che un endpoint accetta per un file di pesi, un URL oppure una chiave di una libreria integrata, è specificato dal sottoschema items di quell'endpoint, quindi leggilo lì invece di presumere una forma. Lo stesso vale per il numero di voci consentite e per i sottocampi obbligatori.
Un campo specifico del modello esiste soltanto quando rappresenta una capacità reale non già coperta da un campo canonico e prende il nome di quella capacità. Un endpoint precedente può conservare nomi di campi precedenti nel proprio inputSchema aggiornato; i nuovi endpoint non li copiano.
inputSchema e annotazioni UI
Ogni modello usa JSON Schema 2020-12 in inputSchema. Lo stesso schema guida validazione sul server, moduli del Playground, esempi e preventivi. L'SDK TypeScript ufficiale tipizza staticamente le strutture comuni delle richieste e delle risposte; l'input di ciascun modello resta Record<string, unknown> e deve essere validato rispetto allo schema aggiornato, senza presumere di avere campi generati per ogni modello.
Questo sito non conserva una tabella di parametri per modello. I parametri hanno esattamente una fonte: l'inputSchema restituito da GET /api/v1/models?includeSchema=1, che è anche ciò che mostra il Playground. Una copia statica perde aderenza quando i modelli cambiano e niente può rilevare quella divergenza. Per costruire la tua tabella dallo schema, consulta Catalogo dei modelli e schemi.
Ogni schema che ricevi:
- ha una radice
objecte rifiuta i campi sconosciuti (additionalProperties: false); - dichiara
required, tipi, enumerazioni, intervalli, lunghezze, limiti degli array, formati URI, valori predefiniti e condizioni verificate; - assegna a ogni proprietà una
descriptioninglese non vuota; - omette campi e valori predefiniti non verificati, anziché indovinarli;
- esprime le condizioni tramite
anyOf/allOfalla radice (sotto), mai soltanto attraverso la visibilità UI; - non contiene interruttori che cambiano soltanto l'elaborazione interna né interruttori per filtrare i contenuti.
Annotazioni di presentazione: x-ui
I metadati di presentazione non sono un secondo schema di validazione. Sono tutti nell'oggetto x-ui della proprietà stessa, le cui chiavi sono snake_case e appartengono a un insieme chiuso:
| Chiave | Significato |
|---|---|
widget | controllo da mostrare; valori sotto |
order | **l'**ordine dei campi, prima i valori più alti, univoco all'interno di un endpoint |
label / placeholder | sostituzione dell'etichetta predefinita; testo segnaposto dell'input |
rows | numero di righe dell'area di testo |
step / unit | passo numerico e suffisso dell'unità (s, px) |
accept / max_size_mb | filtro MIME e limite di dimensione per file dei controlli di caricamento |
advanced | appartiene a una sezione avanzata comprimibile |
primary | input principale; fissato in alto e mai compresso |
affects_price | cambiare questo valore richiede un nuovo preventivo |
visible_when | espressione di visibilità condizionale |
enum_labels | corrispondenza fra valore di enumerazione ed etichetta visualizzata |
x-ui.widget è uno dei tredici valori: textarea, text, upload, multi-upload, select, radio, slider, number, switch, json, object-list, chat-messages, hidden. Un widget è sempre coerente con la struttura dei dati, quindi un renderer può scegliere direttamente in base a esso: select e radio includono sempre un enum; slider include sempre sia minimum sia maximum (mai soltanto exclusiveMinimum / exclusiveMaximum); switch è sempre un boolean; multi-upload è un array con items.type: string; object-list è un array con items.type: object e items.properties, con ogni sottocampo dotato dei propri type e description; chat-messages è un array; hidden significa che il campo viene comunque inviato ma non ha un controllo.
Per qualsiasi campo array, i suoi minItems / maxItems e il sottoschema items contengono vincoli mai menzionati dall'elenco required alla radice, che il server applica esattamente come il resto dello schema. In un object-list, items è a sua volta uno schema di oggetto completo: i propri required, il proprio additionalProperties: false e il proprio tipo, intervallo e default per ogni sottocampo. I valori predefiniti si applicano anche all'interno di quelle voci: un sottocampo omesso viene compilato con il suo default prima della validazione, quindi un sottocampo obbligatorio con un valore predefinito è di fatto facoltativo. Uno senza valore predefinito viene rifiutato se manca, così come un sottocampo sconosciuto o un valore fuori dal suo intervallo.
Un 400 dovuto a un valore dentro un array indica la voce esatta, cioè campo, indice a base zero e sottocampo, anziché la richiesta nel suo complesso. Passa quell'indicazione a chi deve correggerla: con varie voci in elaborazione, sapere quale sia fuori intervallo fa la differenza fra una correzione di una riga e una ricerca per esclusione.
I client devono ignorare le chiavi di presentazione sconosciute: aggiungere una chiave x-ui è una modifica retrocompatibile.
{
"type": "object",
"required": ["prompt", "duration_seconds"],
"additionalProperties": false,
"properties": {
"prompt": {
"type": "string",
"minLength": 1,
"description": "Describes the scene and its motion.",
"x-ui": { "widget": "textarea", "order": 100, "primary": true, "rows": 4 }
},
"duration_seconds": {
"type": "integer",
"enum": [5, 8, 10],
"description": "Output duration in seconds.",
"x-ui": { "widget": "radio", "order": 90, "unit": "s", "affects_price": true }
}
},
"x-pricing": { "variantFields": ["duration_seconds"], "billingMode": "variant_matrix" }
}Ogni description è prosa inglese e può essere mostrata integralmente come testo di aiuto del campo.
x-ui.affects_price: true indica alla UI di aggiornare un preventivo dopo la modifica del campo. Non è una formula di prezzo e non sostituisce mai il pricing del catalogo o quantityField. Il x-pricing alla radice è la rappresentazione sul server dello stesso fatto: variantFields elenca i campi che selezionano una fascia di prezzo ed è sempre un sottoinsieme dei campi affects_price: true, mentre billingMode dice come viene misurato l'utilizzo dell'endpoint. Entrambi sono indicazioni; l'importo autorevole è quello restituito da catalogo, preventivo e attività. Il modo in cui le fasce compaiono in pricing è descritto in Leggere i prezzi.
Campi condizionali
Le condizioni assumono esattamente due forme, entrambe alla radice:
{
"anyOf": [{ "required": ["image_url"] }, { "required": ["image_urls"] }],
"allOf": [
{ "if": { "required": ["last_image_url"] }, "then": { "required": ["image_url"] } },
{ "if": { "properties": { "resolution": { "const": "4k" } } }, "then": { "required": ["seed"] } }
]
}Ogni ramo anyOf contiene soltanto required e significa «fornisci almeno uno di questi». Ogni ramo allOf è un if → then: if viene attivato da required oppure properties.<field>.const, then dichiara soltanto required e significa «se fornisci A devi fornire B».
oneOf, not, dependentSchemas e dependentRequired non compaiono mai nell'inputSchema di un modello: esprimono il vincolo ma non possono essere rappresentati in un modulo, quindi l'utente lo scoprirebbe soltanto come un 400 inspiegabile dopo l'invio. Implementare le due forme sopra copre ogni endpoint condizionale.
Ciclo di vita asincrono
queued -> running -> succeeded
-> failed
-> expiredcreateTask restituisce un ID di attività Spicy. Interroga recordInfo oppure ricevi un webhook Spicy firmato. queued e running non sono stati finali; gli altri sono finali. Le registrazioni storiche canceled restano leggibili per compatibilità, ma le nuove attività non hanno un'azione di annullamento. Attività asincrone è la fonte autorevole sugli stati.
Uno stato interno non finale sconosciuto del modello viene mappato a running fino a uno stato finale noto o alla scadenza assoluta della piattaforma. Un invio non idempotente con una conferma incerta non viene ripetuto alla cieca, evitando generazioni e addebiti duplicati.
Risposta ed errori unificati
Ogni API JSON nativa (/api/v1) usa la stessa struttura esterna; gli endpoint di compatibilità /v1 e /v1beta usano i formati dei rispettivi protocolli:
{
"code": 200,
"msg": "success",
"data": {},
"request_id": "req_01k3m8x9q2z4v7n5p6r8s0t1w2"
}data è assente in caso di errore sincrono. Basa la logica su code, mai sul msg modificabile; usa request_id per l'assistenza. Un errore dopo la creazione dell'attività usa data.state: "failed" e un errorCode stabile. errorMessage è leggibile dalle persone: quando il servizio del modello ha riportato un motivo specifico, contiene quel motivo in inglese con nomi interni, indirizzi e dettagli dell'account rimossi; altrimenti è un messaggio della piattaforma nella tua lingua degli errori. Basa la logica su errorCode, mai su errorMessage.
Risultati e download
Un'attività riuscita elenca i propri file in output.assets[]. Ogni risorsa pronta include già un link di download:
{
"assets": [
{
"key": "tasks/2026/08/31/job_01k3m8x9q2z4v7n5p6r8s0t1w3/asset_01.mp4",
"url": "https://example.r2.cloudflarestorage.com/results/asset_01.mp4?X-Amz-Signature=SIGNATURE_FROM_RESPONSE",
"expiresAt": "2026-08-31T10:20:00Z",
"mime": "video/mp4",
"durationSeconds": 8,
"bytes": 1234567
}
]
}Scarica direttamente url, senza chiave API. Normalmente dura 20 minuti; leggi nuovamente l'attività per ottenerne uno nuovo finché il risultato è conservato (al massimo 14 giorni). Mentre un file viene ancora archiviato, la risorsa ha pending: true e nessun url; se l'archiviazione è fallita definitivamente, ha unavailable: true. key identifica il file per l'endpoint facoltativo download-url; non ti serve per scaricare. Tutti i link puntano allo storage di SpicyAPI.
Fatturazione al cliente
pricing, startingPrice e quantityField del catalogo e estimatedCost / cost dell'attività descrivono soltanto i prezzi al cliente. Gli importi sono stringhe decimali in USD. I dati aziendali interni sono fuori dal contratto pubblico e non compaiono mai in cataloghi, attività, webhook o log esportati.
Compatibilità e deprecazione
Modifiche che dovresti tollerare senza interrompere il funzionamento: un nuovo campo facoltativo, un nuovo campo di risposta che puoi ignorare oppure un'indicazione x-ui sconosciuta.
Un nuovo campo obbligatorio, un valore di enumerazione rimosso, un cambiamento di significato o tipo, un limite più restrittivo o un ID pubblico di modello modificato comportano una nuova versione del modello oppure una finestra di deprecazione annunciata. Gli ID pubblicati restano immutabili; le migrazioni usano un alias di compatibilità o un reindirizzamento esplicito.
Memorizza in cache il catalogo autenticato come descritto in Memorizzare il catalogo in cache. Non mantenere mai uno snapshot permanente dello schema né ripiegare su una pagina statica quando il catalogo aggiornato non contiene una voce utilizzabile.
Limiti di frequenza
Come funzionano i limiti separati di lettura e scrittura, quali richieste conteggiano, gli altri limiti e perché la concorrenza è diversa.
Impegno dell'attività e nuovo tentativo
Perché un'attività di generazione accettata non può essere annullata e come riprovare in sicurezza le attività fallite o scadute.

