spicyapiDocumentazione
SDK
Contenuto principale

SDK Python

L’SDK Python ufficiale di SpicyAPI (spicyapi) — installalo, chiedi un preventivo, esegui la tua prima generazione, carica un file locale, verifica i webhook e consulta ogni codice di errore.

spicyapi è l’SDK Python ufficiale di SpicyAPI. Mette la generazione di immagini, video e audio dietro un unico oggetto client: allega la tua chiave API, trasforma la struttura della risposta in normali dizionari, attende la fine di un’attività con un backoff ragionevole, carica i file locali con una sola chiamata e verifica le firme dei webhook a tempo costante.

Richiede Python 3.11 o successivo e non ha dipendenze a runtime. È una scelta deliberata: questo pacchetto entra in un albero di dipendenze che è già tuo, e ogni vincolo che aggiunge è un’occasione in più di conflitto.

È lo strumento giusto?

Vuoi…Usa
Chiamare SpicyAPI dal tuo codice PythonQuesto SDK
Chiamarlo da Node.js o TypeScriptL’SDK TypeScript
Chiamarlo da Go, PHP o JavaL’SDK Go, PHP o Java
Generare contenuti da un terminale, senza scrivere codiceLa CLI
Far chiamare SpicyAPI al posto tuo da un assistente IAIl server MCP e l’Agent Skill
Usare un modello di chat o di testoLa libreria ufficiale openai, anthropic o google-genai puntata su SpicyAPI: vedi Testo e streaming

Installalo

pip install spicyapi

Poi metti la chiave nell’ambiente, così non comparirà mai nel tuo codice né nel file della cronologia della shell:

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

Il tuo primo risultato

Chiedi il prezzo, decidi, crea l’attività, aspetta, leggi i file. Il preventivo è gratuito e non accantona nulla.

import os, uuid
from spicyapi import SpicyClient, output_assets

client = SpicyClient()  # legge SPICY_API_KEY dall'ambiente

model = client.get_model("MODEL_ID_FROM_CATALOG")
quote = client.quote_task(model=model["model"], input_data={"prompt": "a lantern in fog"})
print(quote["estimatedCost"], quote["maxCharge"])   # decidi prima di spendere

task = client.create_task(
    model=model["model"],
    input_data={"prompt": "a lantern in fog"},
    idempotency_key=str(uuid.uuid4()),
    quote_id=quote["quoteId"],
    expected_cost=quote["estimatedCost"],
)
final = client.wait_for_terminal(task["taskId"])
for asset in output_assets(final):                  # funzione a livello di modulo, non un metodo
    print(asset["url"])

MODEL_ID_FROM_CATALOG è un segnaposto. Prendi un ID reale dal catalogo autenticato — client.list_models(), cioè GET /api/v1/models — e mai a memoria o da una pagina vecchia: i modelli vengono aggiunti, sospesi e ritirati. Costruisci input_data a partire dall’inputSchema di quel modello, che list_models(include_schema=True) restituisce; ogni modello accetta campi diversi.

Gli importi arrivano come stringhe decimali in dollari USA, mai come numeri a virgola mobile, perché i float binari non riescono a contenere esattamente la maggior parte degli importi decimali. Confrontali e sommali con decimal.Decimal. In questa API non esistono crediti né punti.

wait_for_terminal ritorna a qualsiasi stato terminale. Uno stato terminale non è uno stato riuscito: controlla final["state"] prima di leggere l’output.

Alcuni endpoint rispondono con del testo invece che con dei file. Leggi prima output_text(final) quando il modello produce una trascrizione o una didascalia; un client che si limita a scorrere l’elenco dei file dichiara che un’attività perfettamente riuscita non ha prodotto nulla.

Parti da un file locale

Da immagine a video, sostituzione del soggetto e modifica delle immagini hanno tutte bisogno che il tuo materiale arrivi prima dalla nostra parte. upload_file esegue il caricamento in tre passaggi — ticket, PUT allo storage, commit — con una sola chiamata e restituisce un URI spicy://. È quell’URI che va nell’input.

uploaded = client.upload_file("/path/to/reference.png")
task = client.create_task(
    model="MODEL_ID_FROM_CATALOG",
    input_data={"image": uploaded["uri"], "prompt": "slow dolly in"},
    idempotency_key=str(uuid.uuid4()),
)

Un URL HTTPS raggiungibile pubblicamente può entrare direttamente nell’input e non richiede alcun caricamento. Le immagini sono accettate fino a 10 MiB, audio e video fino a 90 MiB; per il resto vedi Media.

Webhook

verify_webhook è una funzione a livello di modulo, così un gestore di richieste può usarla senza costruire un client. Confronta a tempo costante e controlla il timestamp solo dopo che la firma è risultata valida.

from spicyapi import verify_webhook

delivery = verify_webhook(
    raw_body=request.body,                      # i byte esatti, prima di qualsiasi parsing
    signature=request.headers["X-Webhook-Signature"],
    timestamp=request.headers["X-Webhook-Timestamp"],
    payload_version=request.headers["X-Webhook-Payload-Version"],
    secret=os.environ["SPICY_WEBHOOK_SECRET"],
)

Verifica i byte grezzi. Un json.loads seguito da json.dumps li modifica, e la firma non corrisponderà mai più. Le consegne vengono ritentate, quindi deduplica sull’ID della consegna. Il formato completo delle consegne e il calendario dei nuovi tentativi sono in Webhook.

Errori

Ogni fallimento solleva SpicyApiError, che porta con sé status, code, request_id e retry_after_seconds. Ramifica sul code, mai sul testo del messaggio: i messaggi vengono tradotti, i codici no.

L’HTTP 503 è condiviso da tre codici applicativi diversi, quindi leggere solo lo stato HTTP non basta per decidere che cosa fare:

codiceChe cosa significaChe cosa fare
40003i byte caricati non corrispondono al loro ticketricomincia da un ticket nuovo
40004nessuna istanza disponibile serve quella combinazione di parametricambia il parametro indicato nel messaggio
40201saldo insufficienteaggiungi fondi
40901il prezzo è cambiato prima che l’attività venisse creatachiedi di nuovo il preventivo, mantenendo la stessa chiave di idempotenza
503una dipendenza è momentaneamente non disponibileaspetta il tempo indicato da Retry-After
50301al momento il modello non ha né un’istanza utilizzabile né un prezzoaggiorna il catalogo, senza martellare
50302una generazione sincrona è fallita a monte ed è stata rimborsatariprova con una nuova chiave di idempotenza

err.recovery restituisce la stessa indicazione a runtime. Cita il request_id quando contatti l’assistenza. Tutti i codici sono elencati in Errori.

Due cose che ti faranno risparmiare

Tieni una sola chiave di idempotenza per ogni invio. Riusala a ogni reinvio di quell’invio, anche dopo un timeout o una connessione caduta. Una risposta persa non dimostra che l’attività non sia stata creata: una chiave nuova trasforma un esito sconosciuto in una seconda attività a pagamento. Vedi Idempotenza.

Un’attività che riesce viene addebitata, anche se il risultato delude. Chiedi prima un preventivo quando il prezzo conta: quote_task non accantona nulla e non crea nulla.

Che cosa questo pacchetto non fa

  • I modelli di testo. Parlano i formati OpenAI, Anthropic e Gemini, quindi le librerie ufficiali openai, anthropic e google-genai funzionano già: puntale su https://api.spicyapi.ai/v1 con la stessa chiave. Vedi Testo e streaming.
  • Le app per browser, mobile e desktop. Non spedire mai questa chiave dentro un’applicazione: una chiave compilata dentro un client è una chiave pubblica. Chiama dal tuo server.
  • Scegliere un modello o compilarne i campi. Ti consegna il catalogo e lo schema di ogni modello; che cosa inviare lo decidi tu.
  • Annullare un’attività. Una volta accettata, un’attività arriva fino in fondo. Fermare il tuo programma interrompe soltanto la tua attesa.

Codice sorgente

Il pacchetto ha licenza MIT ed è sviluppato in modo aperto su github.com/spicyapi-ai/spicy-python. Il suo README è il giro più breve e completo del client; questa pagina aggiunge i concetti che ci stanno intorno.

Prossimi passi

In questa pagina