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 consente di controllare tutto a livello programmatico: eseguire agenti, gestire strumenti, pianificare attività 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 token Bearer:

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). Nessuna configurazione manuale necessaria: l'app gestisce tutto dietro le quinte.

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.

Fornitori e Modelli

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

Elenco fornitori:

GET /v1/providers

Restituisce tutti i tipi di fornitori configurati (Anthropic, OpenAI, Google, OpenRouter, Ollama, Poe, MLX, Baseten e altri man mano che vengono aggiunti) con i flag delle funzionalità (supportsVision, supportsToolCalling, supportsStreaming, ecc.) e se è configurata una chiave API.

Elenco modelli per un fornitore:

GET /v1/providers/anthropic/models

Restituisce il catalogo dei modelli per quel fornitore. Ogni modello include id, displayName e contextLength dove disponibile.

Catalogo completo tra tutti i fornitori:

GET /v1/models

Unisce i modelli di ogni fornitore configurato in un unico elenco. I fornitori senza chiavi API vengono saltati ed elencati in 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: invoca un agente per elaborare un messaggio.

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" } al termine del lavoro dell'agente. Se l'agente riscontra un errore, restituisce 500 con { error, status: "error" }.

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" }.

Controlla lo stato (polling):

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 in tempo reale: GENERATION_STARTED, STREAMING_CONTENT, chiamate a strumenti, attività dei sotto-agenti e l'evento terminale (GENERATION_COMPLETE, GENERATION_ERROR, o GENERATION_CANCELLED). Lo stream termina dopo l'evento finale.

Annulla un'esecuzione:

POST /v1/runs/{runId}/cancel

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

Threads

I Threads sono conversazioni. Ogni esecuzione di un agent avviene all'interno di un thread, e i thread persistono tra le sessioni. L'API consente di elencare, leggere, creare e gestire i thread in modo programmatico.

Elenca tutti i thread (solo metadati):

GET /v1/threads

Restituisce i thread per il profilo corrente con i messaggi rimossi per ottimizzare le prestazioni. Ogni thread include id, title, createdAt, updatedAt, modeId, archived e le statistiche di utilizzo.

Ottieni un thread con i messaggi completi:

GET /v1/threads/{id}

Restituisce il thread completo incluso il suo array messages — ogni messaggio dell'utente, risposta dell'assistant, tool call e tool result.

Ottieni solo i messaggi:

GET /v1/threads/{id}/messages

Restituisce solo l'array messages — più leggero dell'oggetto thread completo quando serve solo la conversazione.

Crea un thread:

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

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

Restituisce 201 con il nuovo thread. Per impostazione predefinita, l'API NON cambia il thread attivo dell'app — passa "setActive": true nel corpo della richiesta se desideri questo comportamento. Il nuovo thread appare immediatamente nella barra laterale (tramite broadcast WebSocket).

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 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 data retention) sono esclusi dallo svuotamento del cestino.

Continuare una conversazione tramite 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'agent 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.

MCP Servers

Gestisci le connessioni ai tuoi 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 MCP server 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 MCP server:

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"
}

Aggiorna un server:

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

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

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 MCP server locali (stdio), puoi gestire il processo del server direttamente.

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.

Arresta 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 toolkit (raggruppati):

GET /v1/toolkits

Restituisce gli strumenti integrati raggruppati per categoria (Produttività, Ricerca, Utilità, ecc.) e tutti i server MCP connessi come toolkit separati, ciascuno con le proprie azioni elencate.

Elenca tutti gli strumenti (elenco piatto):

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

Ottieni dettagli dello strumento con schema di input:

GET /v1/tools/calculator

Restituisce il JSON Schema dello strumento per i suoi parametri di input, in modo da poterli validare prima dell'invocazione.

Invoca uno strumento direttamente:

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

{ "input": { "expression": "sqrt(144) + 3^2" } }

Restituisce { result }. L'input viene validato rispetto allo schema dello strumento — un input non valido restituisce 422 con i dettagli. Gli strumenti MCP remoti restituiscono 501 con l'indicazione di usare /v1/runs (richiedono il trasporto del sottoprocesso dell'agente).

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 ambiti 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, ambiti, timestamp).

Controlla 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 utente dell'app o le rotte /auth/*.

Trigger

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

Elenca trigger:

GET /v1/triggers

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" } — ogni giorno a un'ora specifica
  • { "type": "weekly", "day": "mon", "time": "09:00" } — ogni settimana
  • { "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" } — ogni mese
  • { "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 grezzo della richiesta
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 inviata. Il segnaposto {{webhook.body}} nel prompt del trigger viene sostituito con il corpo grezzo della richiesta.

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}

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
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.