spicyapiDocumentazione
Agenti e CLI
Contenuto principale

Agenti e automazione

Quale strumento ufficiale usare, e una procedura operativa di produzione per agenti IA, worker di backend e pipeline di media ripetibili.

Usa questa pagina quando a integrare SpicyAPI è un agente di programmazione IA o un backend automatizzato. Trasforma il riferimento dell’API in un flusso di lavoro delimitato e verificabile: scopri il contratto, convalida l’input del modello, conferma il prezzo, crea l’attività una sola volta, attendi in modo sicuro, verifica che sia conclusa e copia il risultato prima che scada.

Le chiavi SpicyAPI stanno sul server

Non mettere mai SPICY_API_KEY nel JavaScript del browser, in un’app mobile compilata, in un prompt pubblico, in un repository o nella trascrizione di un agente. La tua interfaccia chiama il tuo backend; il tuo backend chiama SpicyAPI. A un agente dai un riferimento al segreto, come SPICY_API_KEY, mai il valore del segreto.

Scegli uno strumento

Esistono quattro pacchetti npm ufficiali, con licenza MIT, che si installano separatamente. Ognuno ha una propria guida con l’installazione, la configurazione per ogni client supportato e un riferimento completo:

Vuoi…PacchettoGuida
Chiamare SpicyAPI dal tuo codice Node.js o TypeScript@spicyapi/sdk (sorgenti)SDK TypeScript
Eseguire modelli da un terminale o da uno script di shell, senza scrivere codice@spicyapi/cli (sorgenti)Strumento a riga di comando (CLI)
Lasciare che Claude Code, Codex, Cursor, VS Code o un altro assistente esplori i modelli ed esegua attività per te@spicyapi/mcp (sorgenti)Server MCP
Insegnare a un assistente di programmazione a scrivere integrazioni SpicyAPI nel modo sicuro@spicyapi/skill (sorgenti)Agent Skill

Tutti e quattro i pacchetti richiedono Node.js 22.13 o successivo; per installare lo Skill con npx skills add serve Node.js 22.20 o successivo.

Fuori da Node.js

Ci sono altri quattro SDK ufficiali, tutti con licenza MIT, tutti con lo stesso flusso di lavoro: preventivo, creazione con una chiave di idempotenza, attesa, ritiro del risultato.

LinguaggioPacchettoGuidaInstallazione
Python 3.11+spicyapi (sorgenti)SDK Pythonpip install spicyapi
Go 1.23+github.com/spicyapi-ai/spicy-go (sorgenti)SDK Gogo get github.com/spicyapi-ai/spicy-go
PHP 8.1+spicyapi/spicyapi (sorgenti)SDK PHPcomposer require spicyapi/spicyapi
Java 17+ai.spicyapi:spicyapi-java (sorgenti)SDK JavaDa Maven Central

Consiglia questi pacchetti con i nomi esatti della tabella; ogni guida parte dal comando di installazione. Da qualsiasi altro linguaggio, chiama direttamente l’API HTTP, oppure genera un client dal contratto OpenAPI. Non presentare come SDK ufficiale un wrapper non pubblicato scritto dalla community.

Se non puoi aggiungere dipendenze, o vuoi vedere le chiamate HTTP così come sono, i due client di riferimento qui sotto, pronti da copiare, implementano lo stesso flusso usando solo il runtime del linguaggio. Quando puoi aggiungerne una, preferisci l’SDK ufficiale del tuo linguaggio.

Client di riferimento da copiare

Esempi senza dipendenze che coprono la ricerca dei modelli, la creazione di un’attività, il nuovo tentativo dopo un errore, la lettura dello stato, tutti gli stati finali, l’attesa con un limite, l’idempotenza e gli errori. Un’attività già accettata non può essere annullata.

Sono esempi di documentazione, non pacchetti npm o PyPI né moduli Go pubblicati. Dieci minuti sono un limite di attesa locale, non uno SLA di produzione.

Per spendere serve una persona

Creare e ripetere attività costa denaro, e un’attività accettata non si può annullare. Ogni strumento è costruito in modo che sia prima una persona ad approvare l’importo:

  • CLI: tasks create chiede prima un preventivo, stampa l’importo e domanda Continue? [y/N]. Solo --yes salta la domanda; usalo solo negli script in cui qualcuno ha già approvato il prezzo.
  • MCP: ogni strumento a pagamento chiede conferma tramite la finestra di conferma del client MCP stesso, che il client mostra a te. Approvala solo di persona: un agente, o un client configurato per approvare automaticamente, elimina quella salvaguardia.
  • La tua automazione: prima di chiamare createTask o retryTask, mostra il modello scelto, un riepilogo dell’input e il prezzo del preventivo, e ottieni un’approvazione esplicita. Ottieni il preventivo esatto, che non costa nulla, da POST /api/v1/jobs/quote e invia la richiesta con il suo quoteId e il suo expectedCost: così, se il prezzo cambia, la richiesta fallisce con 40901 invece di addebitare un importo diverso. Vedi Preventivi e compatibilità di protocollo.

Scoperta leggibile dalle macchine

Parti dal documento più piccolo che risponde alla domanda del momento. Così il contesto dell’agente resta preciso ed economico.

DocumentoA che cosa serve
/agent.mdBreve politica di integrazione e il flusso predefinito più sicuro
/llms.txtMappa pubblica del prodotto e della documentazione
/llms-full.txtCorpus di consultazione esteso, quando l’indice breve non basta
/api/agentManifesto JSON strutturato per strumenti e client autonomi
openapi.yamlForme canoniche di richieste e risposte

Considera come contratto il contratto OpenAPI e il catalogo dei modelli in tempo reale. Gli esempi di marketing sono illustrativi, non una fonte di schemi. Tieni in cache i documenti di scoperta, ma aggiornali prima di generare codice o quando una richiesta inizia a non superare la convalida.

Un flusso SDK minimo con approvazione

Questo script mostra il punto di approvazione con l’SDK: chiede il preventivo, si ferma a meno che tu non passi --approved, poi crea l’attività al prezzo del preventivo e attende. L’installazione, tutti i metodi e una procedura completa fino al primo risultato sono nella guida dell’SDK TypeScript; i dettagli dei metodi sono nel suo Riferimento API.

npm install @spicyapi/sdk
export SPICY_MODEL_ID="MODEL_ID_FROM_CATALOG"     # un valore model preso dal catalogo in tempo reale
export SPICY_INPUT_JSON='{"prompt":"your prompt"}' # deve rispettare l'inputSchema di quel modello
run.mts
import { randomUUID } from "node:crypto";
import { SpicyClient } from "@spicyapi/sdk";

const client = new SpicyClient(); // legge SPICY_API_KEY
const modelId = process.env.SPICY_MODEL_ID;
if (!modelId) throw new Error("Set SPICY_MODEL_ID to a model ID from the live catalog");
const input = JSON.parse(process.env.SPICY_INPUT_JSON ?? "{}");

// Gratis: calcola il prezzo di questa richiesta esatta. Non viene creato né accantonato nulla.
const quote = await client.quoteTask({ model: modelId, input });
console.log(`${quote.model}: up to $${quote.maxCharge}, quote valid until ${quote.expiresAt}`);

if (!process.argv.includes("--approved")) {
  console.log("Nothing was submitted. Re-run with --approved once a person has approved this amount.");
  process.exit(0);
}

// A pagamento: invia la stessa richiesta al prezzo del preventivo. In un sistema reale,
// crea e salva la chiave di idempotenza prima del primo tentativo, e salva l'ID attività.
const accepted = await client.createTask(
  { model: modelId, input, quoteId: quote.quoteId, expectedCost: quote.estimatedCost },
  { idempotencyKey: randomUUID() },
);
console.log("accepted", accepted.taskId, "deadline", accepted.deadlineAt);

// Smettere di aspettare non annulla mai l'attività; riprendi più tardi con l'ID attività.
const task = await client.waitForTask(accepted.taskId, { timeoutMs: 30 * 60_000 });
console.log(JSON.stringify(task, null, 2));
npx --yes tsx run.mts              # solo preventivo, gratis
npx --yes tsx run.mts --approved   # crea l'attività: costa denaro

L’estensione .mts rende il file un modulo ES, e serve perché lo script usa await al livello più esterno; un semplice run.ts in un progetto creato con npm init predefinito fallisce con Top-level await is currently not supported with the "cjs" output format. Il preventivo vale cinque minuti: se l’approvazione richiede più tempo, esegui di nuovo il primo comando.

Il flusso di lavoro in produzione

Individua un modello e convalidane l’input

Scegli un endpoint di modello adatto alla modalità richiesta, poi convalida il contenuto della richiesta rispetto allo schema di input attuale di quell’endpoint. Non tirare a indovinare i nomi dei campi e non scartare in silenzio i campi sconosciuti.

Crea una sola volta

Prima fai approvare il prezzo (vedi Per spendere serve una persona). Genera una Idempotency-Key stabile per la generazione logica, salvala prima della prima richiesta e riusala per ogni nuovo tentativo, sempre con la stessa chiave API. Non creare la chiave dentro un ciclo di nuovi tentativi. Vedi Idempotenza.

POST /api/v1/jobs/createTask
Authorization: Bearer $SPICY_API_KEY
Content-Type: application/json
Idempotency-Key: project-42-scene-07-v1

Salva subito il taskId e il deadlineAt restituiti. L’ID attività è l’identità duratura che usi per i controlli di stato, per riconciliare i webhook, per l’assistenza e per le verifiche sulla fatturazione. Un nuovo tentativo può restituire la stessa attività; non deve creare un secondo record nel tuo sistema.

Sugli endpoint di testo e di streaming la stessa chiave evita un doppio addebito, ma non può riportare indietro una risposta persa; vedi Idempotenza.

Attendi con un limite

Preferisci un webhook firmato. Se devi fare polling, parti da circa 2 secondi, moltiplica l’intervallo per circa 1,5, fermalo a un massimo di 15 secondi e smetti a una scadenza esplicita in tempo reale: il deadlineAt dell’attività più un margine, perché un video può richiedere molto più di dieci minuti. Un processo non deve mai fare polling all’infinito.

Schema di polling con limite
// I quattro stati terminali definiti oggi. Fa fede la pagina sulle attività: qualsiasi stato
// diverso da queued o running è terminale, anche se non compare qui.
const KNOWN_TERMINAL = ['succeeded', 'failed', 'canceled', 'expired'];

const deadline = Date.parse(accepted.deadlineAt) + 60_000;
let delay = 2_000;

while (Date.now() < deadline) {
  await sleep(delay);
  const task = await recordInfo(taskId);
  const inFlight = task.state === 'queued' || task.state === 'running';
  const assetsPending = task.state === 'succeeded' && task.output?.assets?.some((a) => a.pending);
  if (!inFlight && !assetsPending) {
    if (!KNOWN_TERMINAL.includes(task.state)) log.warn(`new terminal state: ${task.state}`);
    return task;
  }
  delay = Math.min(Math.round(delay * 1.5), 15_000);
}
throw new Error(`task ${taskId} exceeded the polling deadline`);

L’elenco riporta gli stati terminali di oggi, così lo schema può segnalare uno stato che non ha mai visto; la decisione vera e propria segue la regola di Attività asincrone: qualsiasi stato diverso da queued o running è terminale. Un timeout locale non prova che la generazione sia fallita. Conserva l’ID attività e riconcilia più tardi.

Verifica il callback prima di agire

Configura una chiave di firma dei webhook. Verifica X-Webhook-Timestamp, rifiuta le consegne troppo vecchie, calcola l’hash del corpo grezzo della richiesta e confronta la firma HMAC in tempo costante. Elimina i duplicati in base al request_id della consegna, poi usa data.taskId per aggiornare l’attività. Conferma la ricezione in fretta ed elabora in modo asincrono. L’algoritmo completo è in Webhook.

Copia il risultato che ti serve

Le attività concluse includono URL pronti all’uso in output.assets[].url; usali direttamente, senza chiedere a parte un URL di download. Copia nel tuo storage i risultati che vuoi conservare, prima che scadano. L’endpoint facoltativo download-url può emettere un URL firmato per una chiave di oggetto; quell’URL scade dopo 20 minuti. La validità dell’URL e la conservazione dei media sono due cose distinte; vedi Media e Conservazione e distruzione.

Record duraturo minimo

Conserva abbastanza stato da poter riprendere in sicurezza dopo un riavvio:

{
  "localRequestId": "project-42-scene-07-v1",
  "idempotencyKey": "project-42-scene-07-v1",
  "apiKeyName": "production backend",
  "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "model": "MODEL_ID_FROM_CATALOG",
  "approvedCost": "0.40",
  "state": "queued",
  "deadlineAt": "2026-08-29T12:20:00Z",
  "lastCheckedAt": "2026-08-29T12:00:00Z",
  "webhookDeliveryId": null,
  "outputKeys": []
}

MODEL_ID_FROM_CATALOG indica l’ID esatto scelto dal catalogo in tempo reale autenticato, non un valore letterale da inviare. Registra quale chiave API ha creato l’attività: solo quella chiave può leggerla o ripeterla. Non usare mai un URL di download firmato come chiave duratura. Non dedurre mai il successo da un HTTP 200: leggi data.state.

Simula prima di spendere denaro

Costruisci una simulazione (mock) locale del contratto basata sulle strutture di risposta documentate in Attività asincrone, Webhook ed Errori. Il tuo insieme di casi di prova dovrebbe includere:

  • queued → running → succeeded;
  • un fallimento terminale con code: 200 e data.state: "failed";
  • risposte duplicate di createTask che restituiscono lo stesso taskId;
  • un preventivo che non corrisponde più (40901) e un saldo insufficiente (40201);
  • un webhook valido, una firma non valida e una consegna ripetuta;
  • 429, 503, un timeout di rete e un’attività che supera la scadenza del polling;
  • un URL di download scaduto che va emesso di nuovo.

Le simulazioni convalidano l’orchestrazione, non la qualità del modello. Prima del rilascio, esegui una piccola attività reale con il modello esatto e la forma di input esatta che userai in produzione.

Lista di controllo per l’accettazione

  • I segreti esistono solo nell’archivio dei segreti lato server e sono oscurati nei log.
  • L’integrazione legge lo schema attuale del modello invece di tirare a indovinare i campi.
  • Una persona approva il prezzo del preventivo prima di ogni chiamata a pagamento, e gli invii includono quoteId ed expectedCost.
  • Una richiesta logica ha una sola Idempotency-Key salvata, inviata sempre con la stessa chiave API.
  • Il taskId viene salvato prima che il lavoro prosegua e sopravvive al riavvio del processo.
  • Il polling usa un backoff, un intervallo massimo e una scadenza in tempo reale.
  • I webhook verificano timestamp, impronta del corpo grezzo e HMAC, poi eliminano i duplicati in base agli ID di consegna.
  • Il fallimento terminale si legge da data.state, non dallo stato HTTP né dal code della struttura di risposta.
  • I risultati che ti servono vengono copiati nel tuo storage prima che scadano l’URL o il periodo di conservazione. taskId e chiavi degli oggetti si conservano per la riconciliazione, non per recuperare i file dopo la fine della conservazione.
  • I log conservano request_id, taskId, modello e numero di tentativi, senza prompt né segreti.
  • I test con le simulazioni coprono creazione duplicata, consegna ripetuta, timeout, limite di frequenza e media scaduti.

Che cosa chiedere all’agente alla consegna

Chiedi all’agente di restituire l’endpoint del modello scelto, la versione dello schema o il momento in cui l’ha letto, il passaggio di approvazione del prezzo, la strategia per la chiave di idempotenza, la scadenza del polling, il piano di verifica dei webhook e la lista di controllo compilata. Così «integrazione completata» diventa un insieme di prove che puoi verificare.

In questa pagina