Questa è una traduzione automatica del documento originale in inglese. In caso di discrepanze tra la presente traduzione e la versione originale in inglese, prevarrà la versione inglese. Leggi la versione originale in inglese


API Pubblica

Caiioo include un'API REST che ti permette di controllare tutto programmaticamente: eseguire agenti, gestire strumenti, pianificare task e altro ancora. L'API risiede sullo stesso server locale che alimenta l'app desktop e il bridge del browser.

URL di base: http://localhost:3847/v1

Autenticazione: Due modi per autenticarsi, entrambi regolati dall'interruttore API nelle impostazioni:

Per consumatori esterni (script, integrazioni, curl): Imposta un token di accesso API in Impostazioni > Accesso API, quindi usalo come Bearer token:

curl -H \"Authorization: Bearer IL_TUO_TOKEN_API\" http://localhost:3847/v1/providers

Per l'app locale (automatico): L'app desktop Caiioo, le estensioni del browser e le app mobili si autenticano automaticamente tramite l'intestazione di autenticazione relay esistente (x-relay-auth; le intestazioni HTTP non fanno distinzione tra maiuscole e minuscole). Nessuna configurazione manuale necessaria — l'app gestisce tutto dietro le quinte. Le richieste relay-auth saltano l'interruttore Abilita API Pubblica poiché sono già attendibili; solo le richieste con bearer-token sono regolate dall'interruttore.

Configurazione:

  1. Apri Impostazioni Caiioo > Accesso API
  2. Attiva Abilita API Pubblica
  3. Imposta un token di accesso API (qualsiasi stringa a tua scelta — trattala come una password)
  4. Usa quel token in tutte le richieste API

L'API è disponibile su localhost e tramite il relay privato. Controlla GET /v1/auth/info (nessuna autenticazione richiesta) per lo stato attuale e le istruzioni di configurazione.

Limiti di frequenza: ogni richiesta /v1/* è limitata per IP client — 100 richieste GET al minuto per la lettura e 30 richieste di scrittura al minuto (POST / PATCH / DELETE) combinate. Le richieste oltre il limite ricevono 429. Le consegne dei webhook (POST /v1/webhooks/:id) non sono autenticate tramite bearer e non sono soggette a questi limiti.

Profili

Un singolo dispositivo può ospitare più profili utente (ad es. personale + lavoro). L'API consente agli script esterni di ispezionare i profili disponibili e cambiare quello attivo prima di eseguire altre operazioni. La creazione, l'aggiornamento e l'eliminazione dei profili non sono deliberatamente esposti tramite l'API pubblica — questi flussi appartengono all'interfaccia utente di onboarding dell'app.

Elenco profili:

GET /v1/profiles

Restituisce { profiles: [...] } con una voce per ogni profilo non eliminato. Ogni voce include id, name, email, avatarUrl, tier, accessibleModes, license, organization, preferences, onboardingComplete, createdAt, lastAccessedAt. I campi contenenti token (serviceCredentials, oauthConnections) e i dati interni di sincronizzazione (vectorClock, lastModifiedBy) vengono rimossi. Usa /v1/connectors per ispezionare le connessioni OAuth.

Ottieni il profilo attivo:

GET /v1/profiles/active

Restituisce { profile } per il profilo attualmente in uso da questo server. Tutte le risorse /v1/* relative a un profilo (thread, allegati, impostazioni, skill) operano su questo.

Cambia il profilo attivo:

PUT /v1/profiles/active
Content-Type: application/json

{ "profileId": "user-uuid-dalla-lista" }

Restituisce { profile } per il nuovo profilo attivo. Restituisce 404 se l'ID non corrisponde a un profilo noto.

Providers & Models

Scopri quali provider LLM sono configurati e quali modelli sono disponibili.

Elenco dei provider:

GET /v1/providers

Restituisce ogni tipo di provider supportato. Attualmente: anthropic, openai, google, openrouter, ollama, poe, mlx, perplexity, baseten, cloudflare. Ogni voce include type, displayName, icon, requiresApiKey, hasApiKey e un oggetto capabilities con i flag indicati di seguito.

Flag di capacità Significato
supportsVision Il provider può accettare input di immagini
supportsPdfFile Il provider può accettare nativamente blocchi di contenuto di file PDF grezzi
supportsToolCalling Il provider supporta la chiamata di funzioni/strumenti
supportsStreaming Il provider trasmette i token in modo incrementale
supportsExtendedThinking Il provider espone un budget di ragionamento/pensiero
supportsPromptCaching Il provider supporta le direttive di prompt-cache
nativeReasoningBlocks Il provider emette il pensiero come blocchi di messaggi nativi (rispetto al testo)
requiresThoughtSignature Il provider richiede che i token di pensiero firmati vengano restituiti in eco

I flag di capacità rispecchiano il campo readonly capabilities di ogni classe provider (vedere src/shared/providers/*-provider.ts) e sono validati da un test sentinella di deriva — chiama questo endpoint a runtime invece di codificare la matrice in modo fisso.

Note per i provider BYOK:

  • perplexity espone un elenco curato di modelli Sonar (Perplexity non ha un endpoint /models pubblico).
  • cloudflare (AI Gateway) è BYOK + multi-vendor; l'elenco dei modelli è determinato dalla configurazione del tuo gateway e viene restituito come un array vuoto da /v1/providers/cloudflare/models. Utilizza il catalogo del tuo gateway.

Elenco dei modelli per un provider:

GET /v1/providers/openrouter/models

Restituisce il catalogo dei modelli per quel provider. Ogni modello include id, displayName e contextLength dove disponibile. Restituisce 503 quando il provider manca di una API key o il suo catalogo a monte non è raggiungibile.

Catalogo unico per tutti i provider:

GET /v1/models

Unisce i modelli di ogni provider configurato in un unico elenco. I provider senza API key vengono saltati e inclusi nei warnings.

Agenti

Gli agenti sono il cuore di caiioo. Ogni agente è una Modalità — una personalità configurata con il proprio prompt di sistema, strumenti, variabili e skill.

Elenca tutti gli agenti:

GET /v1/agents

Restituisce gli agenti integrati (Shopping, Workplace, Generale) e tutti gli agenti personalizzati creati. Ognuno è contrassegnato con source: \"builtin\" o source: \"custom\".

Crea un agente personalizzato:

POST /v1/agents
Content-Type: application/json

{
  \"id\": \"mio-agente-ricerca\",
  \"branding\": {
    \"name\": \"Agente di Ricerca\",
    \"description\": \"Cerca nel web e riassume i risultati\"
  },
  \"defaultSettings\": {
    \"systemPrompt\": \"Sei un assistente di ricerca. Cita sempre le fonti.\",
    \"enabledTools\": { \"web_browsing\": true, \"search_tools\": true }
  },
  \"settingLevels\": {}
}

Restituisce 201 con l'agente creato. Un vector clock viene allegato automaticamente per la sincronizzazione.

Aggiorna un agente:

PATCH /v1/agents/mio-agente-ricerca
Content-Type: application/json

{ \"branding\": { \"name\": \"Agente di Ricerca\", \"description\": \"Descrizione aggiornata\" } }

Unisce la patch all'agente esistente e incrementa il vector clock. Gli agenti integrati restituiscono 403 — sono in sola lettura.

Elimina un agente:

DELETE /v1/agents/mio-agente-ricerca

Eliminazione logica tramite tombstone (si sincronizza tra i dispositivi). Restituisce 204.

Esecuzione degli Agenti

Questo è l'evento principale — invocare un agente per elaborare un messaggio.

Corpo della richiesta — campi supportati

Campo Obbligatorio Descrizione
agentId ID della modalità integrata (es. general) o ID di un agente personalizzato
input.message Testo del messaggio dell'utente
input.attachments no Array di ID degli allegati (già caricati tramite /v1/attachments) da allegare a questo turno
input.variables no Sovrascritture delle variabili per singola esecuzione unite nel risolutore di variabili dell'agente
input.tabContext no Stringa a formato libero iniettata come contesto della pagina (utilizzata dal bridge del browser)
input.messageId no ID messaggio fornito dal client — utile per la deduplicazione in caso di riprovo
threadId no Thread esistente da continuare. Se omesso, viene creato e restituito un nuovo thread
mode no "sync" o "async". Il valore predefinito è "async"

Modalità Sincrona

Attendi la risposta completa:

POST /v1/runs
Content-Type: application/json

{
  "agentId": "general",
  "input": { "message": "Che tempo fa a Parigi oggi?" },
  "mode": "sync"
}

Restituisce 200 con { content, usage, status: "completed" } dopo che l'agente ha terminato. Se l'agente riscontra un errore, restituisce 500 con { error, status: "error" }. Le esecuzioni sincrone vanno in timeout dopo 5 minuti con status: "error" se non viene ricevuto alcun evento terminale — usa la modalità async + SSE per qualsiasi operazione che potrebbe richiedere più tempo.

Modalità Asincrona

Invia e dimentica — utile per attività a lunga durata:

POST /v1/runs
Content-Type: application/json

{
  "agentId": "my-research-agent",
  "input": { "message": "Scrivi un'analisi di 2000 parole sulle tendenze delle energie rinnovabili" },
  "mode": "async"
}

Restituisce immediatamente 202 con { runId, threadId, status: "running" }.

Polling per lo stato:

GET /v1/runs/{runId}

Restituisce { run: { runId, threadId, agentId, status, createdAt, content?, usage?, error? } }. Lo stato è uno tra running, completed, error, o cancelled.

Streaming degli eventi in tempo reale (SSE):

GET /v1/runs/{runId}/events

Restituisce un text/event-stream con ogni evento dell'agente man mano che accade: GENERATION_STARTED, STREAMING_CONTENT, chiamate a strumenti (tool calls), attività dei sub-agenti e l'evento terminale (GENERATION_COMPLETE, GENERATION_ERROR, o GENERATION_CANCELLED).

Dopo l'evento terminale, il server emette un frame SSE finale con event: terminal e un payload di dati vuoto come sentinella esplicita di fine flusso, quindi chiude la connessione. I client dovrebbero considerare la ricezione di quel frame (o la chiusura della connessione) come il segnale per interrompere la lettura.

Se ti iscrivi dopo che l'esecuzione è già terminata, il server riproduce un frame di tipo RUN_SNAPSHOT contenente il record finale completo, seguito dalla sentinella event: terminal, quindi chiude.

Annullare un'esecuzione:

POST /v1/runs/{runId}/cancel

Restituisce { run: { ..., status: "cancelled" } }.

Threads

I Threads sono conversazioni. Ogni esecuzione di un agente avviene all'interno di un thread e i thread persistono tra le sessioni. L'API consente di elencare, leggere, creare e gestire i thread a livello di programmazione.

Elenca tutti i thread (solo metadati):

GET /v1/threads

Restituisce { threads: [...] } per il profilo corrente con i messages rimossi (utilizza l'endpoint di dettaglio quando ne hai bisogno). Ogni altro campo viene preservato — id, title, createdAt, updatedAt, modeId, archived, statistiche di utilizzo, oltre a subAgentHistories, anonymizerSnapshot, threadToolApprovals, threadVariables, threadToolOverrides, messagingBinding, scheduledTaskId quando impostati. (Il payload più ricco è un'esclusiva dell'API — il broadcast della barra laterale via WebSocket utilizza una rimozione più stringente per rimanere entro i limiti di trasporto.)

Ottieni un thread con i messaggi completi:

GET /v1/threads/{id}

Restituisce il thread completo includendo il suo array messages — ogni messaggio dell'utente, risposta dell'assistente, chiamata a strumenti (tool call) e risultato degli strumenti (tool result).

Ottieni solo i messaggi:

GET /v1/threads/{id}/messages

Restituisce solo l'array messages — più leggero rispetto all'oggetto thread completo quando hai bisogno solo della conversazione.

Crea un thread:

POST /v1/threads
Content-Type: application/json

{ "title": "Research project", "modeId": "general" }

Restituisce 201 con { thread }. Il nuovo thread appare immediatamente nella barra laterale (tramite broadcast WebSocket). L'API non cambia mai il thread attivo dell'app al momento della creazione — chiama separatamente PUT /v1/threads/active se desideri farlo.

Aggiorna un thread:

PATCH /v1/threads/{id}
Content-Type: application/json

{ "title": "Renamed project", "archived": true }

Campi aggiornabili: title, modeId, archived, lastUsedModel. Le modifiche vengono trasmesse alla barra laterale in tempo reale.

Elimina un thread:

DELETE /v1/threads/{id}

Esegue una cancellazione logica (soft-delete) del thread (tombstone per la sincronizzazione). Restituisce 204. I thread eliminati vengono spostati nel cestino e possono essere recuperati finché il cestino non viene svuotato.

Thread attivo:

GET /v1/threads/active            # Restituisce { threadId }
PUT /v1/threads/active            # Body: { "threadId": "..." }

Gestione del cestino:

GET /v1/threads/trash/count       # Restituisce { count }
POST /v1/threads/trash/empty      # Restituisce { deletedCount, protectedCount }

I thread protetti (conservati tramite l'opzione di conservazione dei dati) sono esclusi dallo svuotamento del cestino.

Continuare una conversazione tramite l'API: Per inviare un messaggio di follow-up a un thread esistente, usa POST /v1/runs con l'ID del thread:

POST /v1/runs
Content-Type: application/json

{
  "agentId": "general",
  "threadId": "existing-thread-id",
  "input": { "message": "Follow up on that last point" },
  "mode": "sync"
}

L'agente visualizza l'intera cronologia della conversazione dal thread.

Allegati

Gli allegati sono file collegati ai thread — screenshot, PDF, documenti, immagini caricate, artefatti generati. L'API ti consente di elencarli, caricarli, scaricarli e gestirli.

Elenca tutti gli allegati (solo metadati):

GET /v1/attachments

Restituisce i metadati degli allegati per il profilo corrente. I campi pesanti (dataUrl, extractedContent, extractedImages) vengono rimossi — usa gli endpoint di dettaglio o contenuto per quelli.

Elenca allegati per un thread specifico:

GET /v1/threads/{threadId}/attachments

Ottieni metadati dell'allegato:

GET /v1/attachments/{id}

Restituisce i metadati completi inclusi extractedContent (testo OCR, markdown analizzato), contentType, fileName, size e un flag hasContent. Il binario grezzo NON è incluso — usa l'endpoint /content per quello.

Scarica il binario dell'allegato:

GET /v1/attachments/{id}/content

Restituisce il file grezzo con le intestazioni Content-Type e Content-Disposition corrette. Indirizzalo su un file:

curl -o output.pdf \
  -H "Authorization: Bearer $API_TOKEN" \
  http://localhost:3847/v1/attachments/{id}/content

Carica un allegato:

POST /v1/attachments
Content-Type: application/json

{
  "threadId": "id-thread",
  "type": "user_upload",
  "contentType": "application/pdf",
  "fileName": "report.pdf",
  "description": "Report trimestrale",
  "dataUrl": "data:application/pdf;base64,JVBERi0xLjQ..."
}

Il dataUrl è un URL di dati codificato in base64. Restituisce 201 con l'ID del nuovo allegato. L'allegato è collegato al thread specificato.

Aggiorna i metadati dell'allegato:

PATCH /v1/attachments/{id}
Content-Type: application/json

{ "description": "Descrizione aggiornata", "fileName": "nuovo-nome.pdf" }

Elimina un allegato:

DELETE /v1/attachments/{id}

Eliminazione logica tramite tombstone. Restituisce 204.

Server MCP

Gestisci le tue connessioni ai server MCP (Model Context Protocol) — i server che forniscono agli agenti l'accesso a strumenti esterni e fonti di dati.

Elenca i server configurati:

GET /v1/mcp-servers

Restituisce tutte le configurazioni dei server MCP per il profilo corrente. I campi sensibili (authToken, env, credentialId) vengono rimossi dalla risposta.

Ottieni la configurazione di un server:

GET /v1/mcp-servers/{id}

Aggiungi un nuovo server MCP:

POST /v1/mcp-servers
Content-Type: application/json

{
  "id": "my-server",
  "name": "My MCP Server",
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"],
  "serverType": "local"
}

Per i server HTTP remoti, usa "url" invece di "command":

{
  "id": "remote-server",
  "name": "Remote API",
  "url": "https://my-mcp-server.example.com/sse",
  "serverType": "remote"
}

Campi opzionali accettati in POST: command, args, env, url, description, transportType, authType, authToken, authHeader, headers, specType, specPath, timeoutMs, credentialId, oauthConnectionId, approval. I campi gestiti dal server (customOAuth, hubPackageId, profileId, connectorId, teamPublished, teamOrgId, vectorClock, ...) non possono essere impostati tramite API.

Aggiorna un server:

PATCH /v1/mcp-servers/{id}
Content-Type: application/json

{ "name": "Renamed Server", "args": ["-y", "@mcp/server-v2"] }

I campi modificabili tramite patch rispecchiano la allowlist del metodo POST (inclusi credentialId e oauthConnectionId — utile per ruotare una connessione OAuth senza dover eliminare e ricreare). I campi gestiti dal server rimangono in sola lettura.

Abilita/disabilita un server:

POST /v1/mcp-servers/{id}/toggle
Content-Type: application/json

{ "enabled": false }

Elimina un server:

DELETE /v1/mcp-servers/{id}

Gestione dei Processi

Per i server MCP locali (stdio), è possibile gestire direttamente il processo del server.

Elenca i processi in esecuzione:

GET /v1/mcp-servers/processes

Restituisce i processi del server in esecuzione con pid, startedAt e lo stato running.

Avvia un server:

POST /v1/mcp-servers/{id}/start

Legge command/args/env dalla configurazione del server e avvia il processo. Restituisce lo stato del processo.

Ferma un server:

POST /v1/mcp-servers/{id}/stop

Arresta correttamente il processo del server (SIGTERM con fallback a SIGKILL).

Chiama direttamente un metodo JSON-RPC:

POST /v1/mcp-servers/{id}/call
Content-Type: application/json

{ "method": "tools/list", "params": {} }

Invia una richiesta JSON-RPC 2.0 grezza al server e restituisce il risultato. Utile per il debugging o per chiamare metodi non esposti tramite l'API degli strumenti.

Strumenti e Toolkit

Sfoglia e invoca gli strumenti utilizzati dagli agenti: navigazione web, ricerca, calendario, Gmail, Slate e altro ancora.

Elenca i toolkit (raggruppati):

GET /v1/toolkits

Restituisce gli strumenti integrati raggruppati per categoria (Produttività, Ricerca, Utility, ecc.) e tutti i server MCP connessi come toolkit separati, ciascuno con l'elenco delle proprie azioni.

Elenca tutti gli strumenti (elenco piatto):

GET /v1/tools
GET /v1/tools?source=embedded   # Solo strumenti integrati
GET /v1/tools?source=mcp        # Solo strumenti del server MCP

Ottieni i dettagli dello strumento con lo schema di input:

GET /v1/tools/calculator

Restituisce { tool: { name, displayName, description, source, category, inputSchema, actions?, requiredTier?, requiredRuntimes?, riskTier?, riskExplanation?, requiresApproval? } }.

Campo Significato
inputSchema Schema JSON per l'input dello strumento — da validare prima dell'invocazione
actions Sotto-azioni opzionali (es. Slate read/write); ognuna ha id, displayName, description, requiredTier opzionale
requiredTier Livello utente minimo (free se omesso). L'invocazione tramite API pubblica rifiuta qualsiasi livello superiore a free
requiredRuntimes Piattaforme in cui questo strumento è disponibile (macos, ios, ecc.); omettere ⇒ ovunque
riskTier Rischio di consenso: low (predefinito), medium, high
riskExplanation Motivo leggibile dall'utente per cui il riskTier è elevato
requiresApproval true quando lo strumento richiede l'approvazione dell'utente per ogni chiamata — l'invocazione tramite API pubblica li rifiuta

Invoca uno strumento direttamente:

POST /v1/tools/calculator/invoke
Content-Type: application/json

{ "input": { "expression": "sqrt(144) + 3^2" }, "threadId": "optional-thread-id" }

Restituisce { result }. L'input viene validato rispetto allo schema dello strumento — un input non valido restituisce 422 con i dettagli. Passa un threadId opzionale se lo strumento necessita di un contesto limitato al thread (es. ricerca di allegati).

Gating — cosa rifiuta l'API pubblica:

  • Strumenti limitati per livello (metadata.requiredTier !== 'free') → 403. Il ciclo dell'agente controlla il livello rispetto alla sessione dell'utente; l'API pubblica non ha un contesto di livello trasportato, quindi la politica conservativa è il rifiuto. Utilizza invece POST /v1/runs con un agente che abbia il livello corretto.
  • Strumenti che richiedono approvazione (metadata.approval.requiresApproval === true) → 403. Non c'è un essere umano nel ciclo a cui chiedere. Invoca tramite POST /v1/runs (che mostra la richiesta all'utente) o imposta la modalità di approvazione dello strumento su approve_all nell'app per bypassare.
  • Strumenti MCP remoti501 con indicazione di utilizzare /v1/runs (richiedono il trasporto del sottoprocesso dell'agente).

Strumenti di visione e che utilizzano immagini: carica prima tramite POST /v1/attachments, quindi passa l'ID dell'allegato restituito all'interno di input (es. { "input": { "attachment_id": "att_abc", "prompt": "Cosa c'è in questa immagine?" } }). Lo strumento legge il binario dallo storage tramite threadId; non passare i byte inline.

Connettori

Gestisci le integrazioni OAuth — Google, Microsoft, GitHub, Notion, Slack e altro.

Sfoglia le integrazioni disponibili:

GET /v1/connectors/catalog

Restituisce tutti i provider OAuth registrati con il loro nome, categoria e scope predefiniti.

Elenca i tuoi account connessi:

GET /v1/connectors

Restituisce le connessioni attive per il profilo corrente. I token non vengono mai esposti — solo i metadati (provider, email, stato, scope, timestamp).

Ottieni una singola connessione:

GET /v1/connectors/{id}

Restituisce i metadati per una connessione. I token non vengono mai esposti.

Verifica lo stato della connessione:

POST /v1/connectors/{id}/test

Restituisce { health: { status, isTokenExpired, canRefresh } }.

Rimuovi una connessione:

DELETE /v1/connectors/{id}

La creazione di nuove connessioni richiede il flusso OAuth interattivo tramite l'interfaccia dell'app o le rotte /auth/*.

Trigger

Pianifica l'esecuzione automatica degli agenti — briefing quotidiani, report settimanali, monitoraggio a intervalli.

Ogni trigger ha un discriminatore kind: schedule (predefinito — si attiva in base all'orario), webhook (si attiva quando un servizio esterno invia un POST al percorso del webhook) o messaging (si attiva da un adattatore di messaggistica connesso — es. messaggi Slack/Discord in entrata che corrispondono a un filtro di canale).

Elenca i trigger:

GET /v1/triggers

Restituisce { triggers: [...] }.

Ottieni un singolo trigger:

GET /v1/triggers/{id}

Crea un trigger pianificato:

POST /v1/triggers
Content-Type: application/json

{
  \"name\": \"Briefing Mattutino\",
  \"prompt\": \"Riassumi le mie email non lette e il calendario di oggi\",
  \"modeId\": \"general\",
  \"schedule\": { \"type\": \"daily\", \"time\": \"08:00\" }
}

Tipi di pianificazione supportati:

  • { \"type\": \"interval\", \"minutes\": 60 } — ogni N minuti (min 15, max 1440)
  • { \"type\": \"daily\", \"time\": \"09:00\" } — giornaliero a un orario specifico
  • { \"type\": \"weekly\", \"day\": \"mon\", \"time\": \"09:00\" } — settimanale
  • { \"type\": \"weekdays\", \"time\": \"08:30\" } — dal lunedì al venerdì
  • { \"type\": \"daysOfWeek\", \"days\": [\"mon\", \"wed\", \"fri\"], \"time\": \"10:00\" } — giorni specifici
  • { \"type\": \"monthly\", \"dayOfMonth\": 1, \"time\": \"09:00\" } — mensile
  • { \"type\": \"manual\" } — solo se attivato tramite API

Attiva un trigger manualmente:

POST /v1/triggers/{id}/fire

Restituisce 202 con un threadId per l'esecuzione risultante.

Aggiorna o elimina:

PATCH /v1/triggers/{id}
DELETE /v1/triggers/{id}

Webhook

I trigger webhook consentono a servizi esterni (CI/CD, monitoraggio, form builder) di attivare l'esecuzione di un agente tramite HTTP.

Crea un trigger webhook:

POST /v1/triggers
Content-Type: application/json

{
  \"name\": \"Deploy hook\",
  \"prompt\": \"È avvenuto un deploy: {{webhook.body}}\",
  \"modeId\": \"general\",
  \"kind\": \"webhook\"
}

Restituisce 201 con un webhookSecret e webhookPath. Conserva il segreto — ti servirà per firmare i payload.

Invia un webhook:

# Calcola HMAC-SHA256 del corpo della richiesta raw
SIGNATURE=$(echo -n '{\"repo\":\"my-app\",\"branch\":\"main\"}' | openssl dgst -sha256 -hmac \"$WEBHOOK_SECRET\" | awk '{print $2}')

POST /v1/webhooks/{triggerId}
Content-Type: application/json
X-Webhook-Signature: $SIGNATURE

{\"repo\": \"my-app\", \"branch\": \"main\"}

L'endpoint del webhook NON richiede l'autenticazione bearer — utilizza invece la verifica HMAC. Restituisce 202 con il threadId dell'esecuzione avviata. Il segnaposto {{webhook.body}} nel prompt del trigger viene sostituito con il corpo della richiesta raw.

Trigger di messaggistica

I trigger di messaggistica si attivano quando un adattatore di messaggistica connesso (es. un'integrazione Slack o Discord installata tramite l'Hub della Community) riceve un messaggio in entrata che corrisponde al filtro del trigger. Crea con kind: \"messaging\":

POST /v1/triggers
Content-Type: application/json

{
  \"name\": \"Risponditore menzioni\",
  \"prompt\": \"Rispondi in modo utile a: {{message.text}}\",
  \"modeId\": \"general\",
  \"kind\": \"messaging\",
  \"messagingAdapterId\": \"slack-team-acme\",
  \"messagingChannelFilter\": \"#support\"
}

L'adattatore è responsabile dell'invio degli eventi corrispondenti al trigger; messagingChannelFilter è specifico per l'adattatore.

Funzioni Personalizzate

Crea i tuoi strumenti che gli agenti possono chiamare. Le funzioni sono scritte in JavaScript o Python ed eseguite in una sandbox.

Elenca funzioni:

GET /v1/functions

Crea una funzione:

POST /v1/functions
Content-Type: application/json

{
  "name": "calcola_bmi",
  "description": "Calcola l'Indice di Massa Corporea da altezza e peso",
  "language": "javascript",
  "source": "return { bmi: (input.weightKg / (input.heightM * input.heightM)).toFixed(1) };",
  "inputSchema": {
    "type": "object",
    "properties": {
      "weightKg": { "type": "number" },
      "heightM": { "type": "number" }
    },
    "required": ["weightKg", "heightM"]
  }
}

Le funzioni JavaScript ricevono input e devono restituire un risultato. Le funzioni Python impostano una variabile result:

# Esempio Python
result = {"bmi": round(input["weightKg"] / (input["heightM"] ** 2), 1)}

Esegui una funzione direttamente:

POST /v1/functions/{id}/execute
Content-Type: application/json

{ "input": { "weightKg": 75, "heightM": 1.80 } }

Sicurezza: JavaScript viene eseguito nella sandbox vm di Node (nessun accesso al filesystem o alla rete, timeout di 10s). Python viene eseguito come sottoprocesso con un timeout di 30s. Entrambi validano l'input prima dell'esecuzione.

Aggiorna o elimina:

PATCH /v1/functions/{id}
DELETE /v1/functions/{id}

Skill

Le Skill sono prompt salvati a cui gli agenti possono fare riferimento e che possono avviare rapidamente dalla visualizzazione di conversazione vuota. Le skill installate tramite Hub (gestite tramite installazione di pacchetti) NON sono incluse qui — solo le skill create dall'utente sono elencate e modificabili.

Elenco skill:

GET /v1/skills

Restituisce { skills: [...] } delle skill create dall'utente per il profilo attivo. Le skill eliminate (tombstoned), quelle sovrapposte dall'hub e le skill ombra di sincronizzazione vengono filtrate.

Ottieni una skill:

GET /v1/skills/{id}

Crea una skill:

POST /v1/skills
Content-Type: application/json

{
  "prompt": "Riassumi la pagina in 3 punti elenco.",
  "tags": ["utility", "summarize"],
  "isFavorite": true,
  "modes": ["general"],
  "displayName": "Riassunto Rapido",
  "description": "TL;DR in tre punti della pagina attiva"
}

Solo prompt è richiesto. modes (opzionale) limita la skill a specifici ID agente; omettere per tutte le modalità. Restituisce 201 con la nuova skill (inclusi id, createdAt, updatedAt assegnati dal server).

Aggiorna una skill:

PATCH /v1/skills/{id}
Content-Type: application/json

{ "prompt": "Prompt aggiornato", "isFavorite": false }

Campi modificabili: prompt, tags, modes, displayName, description, isFavorite. I tentativi di modificare una skill sovrapposta dall'hub restituiscono 404.

Elimina una skill:

DELETE /v1/skills/{id}

Eliminazione logica tramite tombstone. Restituisce 204. Le skill sovrapposte dall'hub restituiscono 404 — disinstalla invece il pacchetto sorgente.

Workflow

Orchestra più agenti in un DAG (grafo aciclico diretto): esegui i passaggi in parallelo quando possibile e inserisci gli output dei passaggi precedenti in quelli successivi.

Validare il grafo di un workflow:

POST /v1/workflows/validate
Content-Type: application/json

{
  "graph": {
    "nodes": [
      { "id": "research", "agentId": "general", "prompt": "Ricerca le tendenze delle energie rinnovabili" },
      { "id": "analyze", "agentId": "general", "prompt": "Ricerca i prezzi della concorrenza" },
      { "id": "report", "agentId": "general", "prompt": "Scrivi un report combinando: {{outputs.research}} e {{outputs.analyze}}", "dependsOn": ["research", "analyze"] }
    ]
  }
}

Restituisce { valid: true/false, errors: [...] }. Controlla la presenza di cicli, ID duplicati e riferimenti a dipendenze mancanti.

Eseguire un workflow:

POST /v1/workflows/execute
Content-Type: application/json

{
  "graph": {
    "nodes": [
      { "id": "research", "agentId": "general", "prompt": "Ricerca le tendenze delle energie rinnovabili" },
      { "id": "summarize", "agentId": "general", "prompt": "Riassumi: {{outputs.research}}", "dependsOn": ["research"] }
    ]
  }
}

Restituisce { status: "completed", outputs: { research: "...", summarize: "..." }, nodeResults: {...} }.

I nodi indipendenti (senza dipendenze condivise) vengono eseguiti in parallelo. Il segnaposto {{outputs.nodeId}} nel prompt di un nodo viene sostituito con l'output del contenuto del nodo a monte specificato. Ogni nodo è un'esecuzione completa dell'agente, quindi può utilizzare strumenti, navigare sul web e accedere a tutte le funzionalità dell'agente di destinazione.

Basi di Conoscenza

Organizza i documenti in raccolte ricercabili a cui gli agenti possono fare riferimento.

Elenca basi di conoscenza:

GET /v1/knowledge/bases

Crea una base di conoscenza:

POST /v1/knowledge/bases
Content-Type: application/json

{ "name": "Documenti di Ricerca" }

Restituisce 201 con l'ID della nuova base.

Carica un documento in una base di conoscenza:

POST /v1/knowledge/bases/{id}/documents
Content-Type: application/json

{
  "fileName": "ricerca.pdf",
  "contentType": "application/pdf",
  "dataUrl": "data:application/pdf;base64,JVBERi0xLjQ...",
  "description": "Tendenze energie rinnovabili 2026"
}

Il campo dataUrl è un URL di dati codificato in base64. Restituisce 201 con i metadati del documento.

Elenca documenti in una base di conoscenza:

GET /v1/knowledge/bases/{id}/documents

Cerca all'interno di una base di conoscenza:

POST /v1/knowledge/bases/{id}/search
Content-Type: application/json

{ "query": "energia rinnovabile" }

Restituisce i documenti corrispondenti in base al nome del file e alla descrizione. La ricerca semantica (vettoriale) sarà disponibile in una versione futura.

Elimina un documento o una base di conoscenza:

DELETE /v1/knowledge/bases/{id}/documents/{docId}
DELETE /v1/knowledge/bases/{id}

Esportazione e Importazione Agenti

Condividi gli agenti come pacchetti portatili — tra dispositivi, team o il Community Hub.

Esporta un agente:

POST /v1/agents/{id}/export

Restituisce un pacchetto JSON contenente la definizione dell'agente, i requisiti degli strumenti (derivati dagli strumenti abilitati), i requisiti dei connettori (quali fornitori OAuth sono necessari) e i template dei trigger. I metadati di sincronizzazione vengono rimossi — il pacchetto è un progetto pulito e autonomo.

Importa un agente:

POST /v1/agents/import
Content-Type: application/json

{
  \"package\": {
    \"$schema\": \"caiioo.agent.package/v1\",
    \"agent\": {
      \"id\": \"agente-ricerca-condiviso\",
      \"branding\": { \"name\": \"Agente di Ricerca\", \"description\": \"Dal team\" },
      \"defaultSettings\": { \"systemPrompt\": \"Fai ricerche su vari argomenti.\" },
      \"settingLevels\": {}
    },
    \"toolRequirements\": [
      { \"toolId\": \"web_browsing\", \"enabled\": true },
      { \"toolId\": \"search_tools\", \"enabled\": true }
    ]
  }
}

Restituisce 201 con l'agente installato. Le collisioni di ID con agenti integrati o esistenti restituiscono 409.

Gestione degli Errori

L'API utilizza codici di stato HTTP standard:

Codice Significato
200 Successo
201 Creato
202 Accettato (operazione asincrona avviata)
204 Eliminato (nessun contenuto)
400 Richiesta errata — controlla il campo error per i dettagli
401 Non autorizzato — segreto di sessione mancante o non valido
403 Proibito — ad es. tentativo di modificare un agente predefinito
404 Non trovato
409 Conflitto — ad es. l'ID dell'agente esiste già
422 Errore di validazione — l'input non corrisponde allo schema dello strumento
429 Limite di frequenza superato — vedi i budget di rate-limit nella sezione Autenticazione
500 Errore del server — controlla il campo error
501 Non implementato — la funzionalità esiste ma non è disponibile in questo modo
503 Servizio non disponibile — archiviazione o provider non pronti

Tutte le risposte di errore includono { "error": "messaggio leggibile dall'utente" }.

Esempio di Avvio Rapido

Ecco un workflow completo: crea un agente, eseguilo e trasmetti i risultati in streaming.

# 1. Crea un agente personalizzato
curl -X POST http://localhost:3847/v1/agents \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "riassuntore-rapido",
    "branding": { "name": "Riassuntore Rapido" },
    "defaultSettings": {
      "systemPrompt": "Riassumi qualsiasi input in modo conciso in 3 punti elenco.",
      "enabledTools": { "web_browsing": true }
    },
    "settingLevels": {}
  }'

# 2. Eseguilo in modo asincrono
RUN=$(curl -s -X POST http://localhost:3847/v1/runs \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "agentId": "riassuntore-rapido", "input": { "message": "Riassumi https://it.wikipedia.org/wiki/Intelligenza_artificiale" }, "mode": "async" }')

RUN_ID=$(echo $RUN | jq -r '.runId')

# 3. Streaming degli eventi
curl -N http://localhost:3847/v1/runs/$RUN_ID/events \
  -H "Authorization: Bearer $API_TOKEN"

# 4. Esporta l'agente per la condivisione
curl -X POST http://localhost:3847/v1/agents/riassuntore-rapido/export \
  -H "Authorization: Bearer $API_TOKEN"

This guide is maintained by the Caiioo team using Slate, our built-in editor.