Conversazioni e messaggi
Avvia chat, invia messaggi di follow-up, ricevi le risposte in streaming su WebSocket, confronta modelli, approva le chiamate agli strumenti MCP e condividi conversazioni tramite l'API REST.
Una conversazione è un thread di chat: la stessa cosa che il tuo team vede in Chat History nell’app. La avvii con un messaggio, il modello risponde e tu continui con altri messaggi di follow-up. Ogni richiesta descritta qui viene eseguita come l’utente proprietario della chiave API, con gli stessi accessi, le stesse quote e le stesse regole del workspace che quell’utente ha nel browser.
Tutti i percorsi sono relativi a https://api.stickyprompts.com/api/v1. I corpi delle richieste sono in JSON. I file si caricano prima tramite gli endpoint dei file e poi si richiamano tramite il loro ID.
Come funziona la chat
- Avvia la conversazione con
POST /conversation(attende la risposta completa) o conPOST /conversation/stream(risponde subito; la risposta del modello arriva sul WebSocket). Entrambi creano la conversazione e inviano il primo messaggio in un’unica chiamata. - Continua con
POST /conversation/:idoPOST /conversation/:id/stream. - Cambia modello, stile o livello di ragionamento per i turni successivi con
PATCH /conversation/:id/model. I corpi dei messaggi di follow-up non accettano un modello: la conversazione ricorda le impostazioni del “prossimo messaggio”. - Leggi la cronologia con
GET /conversation/:id(paginata, dal più recente) ed elenca le conversazioni conGET /conversation. - Segui l’avanzamento in tempo reale con il WebSocket
GET /conversation/:id/ws, oppure interroga periodicamenteGET /conversation/:ide leggi lostatusdel messaggio dell’IA.
Identificatori. La maggior parte degli endpoint accetta come :id sia l’ID numerico della conversazione sia lo slug di 8 caratteri. Gli endpoint di condivisione, l’eliminazione, l’approvazione e gli stream WebSocket e SSE accettano solo l’ID numerico; ognuno di questi casi è segnalato più avanti.
L’oggetto Message
Viene restituito dagli endpoint di invio senza streaming, all’interno di GET /conversation/:id e come data degli eventi WebSocket message.
{
"ID": 90412,
"CreatedAt": "2026-09-28T09:14:03.512Z",
"UpdatedAt": "2026-09-28T09:14:09.871Z",
"DeletedAt": null,
"conversation_context_id": 5120,
"ai_model_id": 12,
"ai_model": { "ID": 12, "name": "Example Model", "stream_support": true, "...": "..." },
"agent_id": null,
"is_auto_model": false,
"text": "Here are three subject lines for the Northwind Q4 newsletter: ...",
"raw_text": "Here are three subject lines for the Northwind Q4 newsletter: ...",
"parts": [
{ "id": "p1", "type": "text", "static": true, "text_part": { "text": "Here are three ...", "raw_text": "Here are three ..." } }
],
"thinking": null,
"isUser": false,
"error_text": null,
"error_id": null,
"error_code": null,
"mcp_approval_requests": null,
"ai_style": "prompty",
"status": "finished",
"citations": null,
"response_duration_ms": 6210,
"type": "normal",
"attachments": []
}
| Campo | Tipo | Significato |
|---|---|---|
conversation_context_id | uint o null | La conversazione a cui appartiene il messaggio. |
ai_model_id, ai_model | uint, oggetto | Il modello che ha prodotto il messaggio (IA) o che era selezionato per il messaggio (utente). |
agent_id, agent | uint, oggetto | L’agente che ha risposto, se presente. |
is_auto_model | bool | true quando il modello è stato scelto dalla selezione automatica. |
prompt_id | uint o null | Il prompt salvato usato per questo messaggio dell’utente. |
text | string | Il testo del messaggio. Nei messaggi dell’IA i marcatori delle citazioni sono già renderizzati. |
raw_text | string | Il testo dell’IA non elaborato (solo nei percorsi di lettura e di streaming). |
parts | array | Blocchi strutturati. type vale text, thinking, web_search, web_fetch, code_execution, image_generation o mcp_call, con l’oggetto *_part corrispondente. static è true quando non c’è nulla da espandere. |
thinking | string o null | Il testo del ragionamento, per i modelli di ragionamento. |
isUser | bool | true per i messaggi dell’utente, false per quelli dell’IA. |
status | string | thinking, generating o finished. |
error_text, error_id, error_code | string o null | Valorizzati quando la generazione non è riuscita. error_id è un riferimento di 10 caratteri da comunicare all’assistenza; error_code è un codice leggibile dalle macchine per alcune classi di errore, come i blocchi per dati sensibili e gli errori MCP. |
mcp_approval_requests | array | Approvazioni di strumenti MCP in attesa o già decise. Vedi Approvazione degli strumenti MCP. |
tools | array | Gli strumenti attivati per questo turno. |
citations | array | Citazioni dal web e dalle knowledge base: url, file_path, title, info (kb_id, file_id, intervalli di pagine e di righe), citation_index e altro. |
knowledge_base_ids, world_knowledge | uint[], bool | Le knowledge base consultate in questo turno e se il modello poteva andare oltre il loro contenuto. |
response_duration_ms | int o null | Il tempo di generazione. |
type | string | normal o sub_conversation (il contenitore di un confronto tra modelli). |
attachments | array | File allegati e trascrizioni, ciascuno con una chiave iniziale "type": "file" o "type": "transcription". È sempre un array. |
Stato. thinking significa che la riga del messaggio dell’IA esiste ma non è ancora stato generato nulla; generating significa che l’output parziale sta arrivando in streaming; finished significa che la generazione è terminata. Anche un messaggio dell’IA non riuscito è finished, con error_text ed error_id valorizzati: controlla quindi questi campi, non solo status. I messaggi dell’utente sono sempre finished.
Crediti. Ogni campo credits_used è un decimale serializzato come stringa JSON, per esempio "0.4213".
Inviare messaggi
Corpo della richiesta
POST /conversation e POST /conversation/stream accettano tutti i campi seguenti. Gli endpoint di follow-up accettano solo i campi contrassegnati con «follow-up»; gli altri vengono ignorati senza alcun avviso. Il binder non rende obbligatorio nessun campo, ma invia sempre un message e un modello.
-
messagestring facoltativo - Il messaggio dell’utente. Menziona
@<agent-tag>per indirizzare il turno a uno dei tuoi agenti. Avvio e follow-up. -
attachmentsarray facoltativo - Elementi
{ "id": uint, "type": "file" | "transcription", "temp": bool }. File caricati o trascrizioni completate. Contemp: truel’allegato vale solo per questo turno e non viene registrato sul messaggio. Avvio e follow-up. -
knowledge_base_idsuint[] facoltativo - Le knowledge base da cui recuperare il contesto per questo turno. Avvio e follow-up.
-
knowledge_base_limit_node_idsuint[] facoltativo - Limita il recupero a queste cartelle o a questi file della knowledge base. Avvio e follow-up.
-
world_knowledgebool facoltativo predefinitofalse false: risponde solo in base alla knowledge base.true: la knowledge base resta la fonte principale, ma il modello può usare anche la ricerca web e le proprie conoscenze. Avvio e follow-up.-
flash_modebool facoltativo - Richiede il livello di servizio prioritario del provider. Ha effetto solo sui modelli che lo supportano. Avvio e follow-up.
-
toolsarray facoltativo - Elementi
{ "name", "use", "mcp_tool_id"? }. Vedi Strumenti. Avvio e follow-up. -
ai_model_iduint facoltativo - Il modello da usare, preso da
GET /ai_model. Viene ignorato se è impostatoauto_model_type. Solo all’avvio. -
auto_model_typestring facoltativo best,balancedocheapest. La selezione automatica sceglie il modello migliore per ogni messaggio e ha la precedenza suai_model_id. Solo all’avvio.-
ai_stylestring facoltativo predefinitoprompty - Lo stile di risposta: il valore
tonedi uno stile dell’IA. Solo all’avvio. -
reasoning_effortstring facoltativo - Il livello di ragionamento per i modelli di ragionamento. Un valore non supportato ricade sul valore predefinito del modello; per i modelli senza ragionamento viene salvato null. Solo all’avvio.
-
agent_iduint facoltativo - Avvia una chat con un agente: a ogni turno vengono usati il modello, il prompt di sistema, gli strumenti, i server MCP, le knowledge base e i file dell’agente. L’agente deve essere tuo. Solo all’avvio.
-
invited_agent_idsuint[] facoltativo - I tuoi agenti che si possono menzionare in questa conversazione (
@mentioned). Viene ignorato se è impostatoagent_id. Solo all’avvio. -
team_iduint facoltativo - Crea una conversazione di team (il team riceve l’accesso
chat_contribute). Vedi Quando risponde l’IA. Solo all’avvio. -
X-Project-IDinteger in header facoltativo - Solo all’avvio. Archivia la conversazione in questo progetto. Se il corpo non contiene un modello, viene usato il modello predefinito del progetto. A ogni turno i file del progetto vengono aggiunti al contesto. Il campo
project_iddel corpo esiste ma non viene letto: usa questo header.
Selezione del modello. Vince auto_model_type, poi ai_model_id, poi il modello predefinito del progetto (con X-Project-ID). Se nessuno dei tre si applica, la conversazione viene comunque creata, ma l’invio non riesce con 503 {"error":"no AI model is selected, try reselecting model"}: all’avvio invia quindi sempre un modello o un tipo di selezione automatica. Non esiste un ID di modello letterale "auto". Le chat con un agente e le menzioni @agent usano il modello dell’agente (stile prompty, nessun livello di ragionamento). Il modello deve essere consentito dalle regole di Accesso a modelli e provider e di Residenza dei dati del tuo workspace, altrimenti l’invio non riesce con 503.
Strumenti
Ogni voce ha la forma { "name": ..., "use": true | false }. Nomi disponibili: web_search, image_generation, video_generation, speech_generation, music_generation, remote_mcp.
- Uno strumento arriva al modello solo se il modello lo elenca tra le proprie capacità
tools. In caso contrario viene ignorato senza alcun avviso. remote_mcprichiede anche"mcp_tool_id": <id>, l’ID di uno dei server MCP remoti che hai configurato. Aggiungi una voce per ogni server.- Selezione automatica degli strumenti. Sui modelli che supportano gli strumenti, un piccolo classificatore può attivare
web_searcheimage_generation(e l’esecuzione di codice) in base al messaggio, anche se non li hai richiesti. Se invii una voce per uno strumento, anche{"name":"web_search","use":false}, il classificatore non lo aggiunge più. L’esecuzione di codice dipende solo dal classificatore.
POST /conversation
/api/v1/conversation Crea una conversazione, invia il primo messaggio e attende la risposta completa dell’IA, comprese eventuali chiamate agli strumenti. La risposta è il Message dell’IA ormai completato; l’ID della nuova conversazione è il suo conversation_context_id. Dopo il primo scambio la conversazione riceve un nome automatico. Accetta il corpo della richiesta descritto sopra, più l’header facoltativo X-Project-ID.
curl -X POST https://api.stickyprompts.com/api/v1/conversation \
-H "Authorization: Bearer $STICKY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Draft three subject lines for the Northwind Q4 newsletter.",
"ai_model_id": 12,
"ai_style": "prompty",
"tools": [{ "name": "web_search", "use": false }]
}'import os, requests
r = requests.post(
"https://api.stickyprompts.com/api/v1/conversation",
headers={"Authorization": f"Bearer {os.environ['STICKY_API_KEY']}"},
json={
"message": "Draft three subject lines for the Northwind Q4 newsletter.",
"ai_model_id": 12,
"ai_style": "prompty",
"tools": [{"name": "web_search", "use": False}],
},
timeout=300,
)
r.raise_for_status()
reply = r.json()
if reply.get("error_id"):
print("Failed:", reply["error_text"], reply["error_id"])
else:
print(reply["conversation_context_id"], reply["text"])const res = await fetch("https://api.stickyprompts.com/api/v1/conversation", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.STICKY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
message: "Draft three subject lines for the Northwind Q4 newsletter.",
ai_model_id: 12,
ai_style: "prompty",
tools: [{ name: "web_search", use: false }],
}),
});
const reply = await res.json();
console.log(reply.conversation_context_id, reply.error_id ?? reply.text);Risposta. 200 con il Message dell’IA (vedi l’oggetto Message). Quando l’IA non deve rispondere (una conversazione di team con più membri e nessuna menzione di @ai o di un agente), il corpo è invece 200 {"conversation_context_id": 5120}.
Errori
| Stato | Corpo | Quando |
|---|---|---|
400 | {"error": "..."} | JSON non valido. |
400 | {"error": "...", "error_code": "..."} | Bloccato dalle regole sui dati sensibili del tuo workspace, oppure errore di un server MCP. Quando l’IA non risponde, un blocco per dati sensibili usa la chiave code al posto di error_code. |
400 | {"error": "Knowledge base not found"} | Knowledge base sconosciuta. |
429 | {"error": "Quota exceeded", "reason": "..."} | Verificato prima di creare qualsiasi cosa. reason vale credit_count, user_count, subscription, trial_expired o unknown. |
503 | {"error": "could not create conversation"} | Per esempio un agent_id che non è tuo o un team_id sconosciuto (un errore nella ricerca del team può emergere anche come 500). |
503 | {"error": "<message>"} | Qualsiasi altro errore: nessun modello selezionato, modello soggetto a restrizioni, errore del provider. |
Se il provider fallisce a generazione in corso, il messaggio dell’IA viene comunque salvato con error_text ed error_id, e POST /conversation/:id/retry può eseguirlo di nuovo.
POST /conversation/stream
/api/v1/conversation/stream Stessi header e stesso corpo di POST /conversation, ma risponde non appena il messaggio dell’utente è stato salvato. La generazione prosegue in background e la risposta arriva sul WebSocket oppure tramite polling.
{ "conversation_context_id": 5120 }
Gli errori rilevati prima che il messaggio dell’utente venga salvato (quota 429, agente non valido, nessun modello selezionato, modello soggetto a restrizioni, blocco per dati sensibili) vengono comunque restituiti in modo sincrono, con le stesse forme viste sopra. Gli errori successivi al 200 (selezione del modello o degli strumenti, recupero dalla knowledge base, errore del provider) vengono segnalati solo come evento WebSocket error_message e salvati su un messaggio dell’IA con error_text ed error_id.
Ricevere la risposta
- WebSocket (consigliato). Connettiti a
GET /conversation/{conversation_context_id}/ws. Gli eventi emessi prima della connessione vengono messi in buffer e riprodotti al primo client, quindi se ti connetti subito dopo il200non perdi nulla. - Polling. Chiama
GET /conversation/:id?page=1&size=2e leggi il messaggio dell’IA più recente (isUser: false, il primo dell’elenco, perché l’ordine va dal più recente). Il messaggio dell’IA viene creato constatus: "thinking"e salvato a ogni chunk, quindi vedraigeneratingcon untextsempre più lungo e poifinished. Fermati afinishede controllaerror_id. Subito dopo il200il messaggio dell’IA potrebbe non esistere ancora: se il messaggio più recente è ancora il tuo, la generazione non è iniziata.
Lo streaming avviene in tempo reale solo per i modelli con stream_support: true. Con gli altri modelli la risposta compare tutta insieme quando è completa.
POST /conversation/:id
/api/v1/conversation/:id Invia un messaggio di follow-up e attende la risposta dell’IA. Modello, stile e livello di ragionamento provengono dalle impostazioni next_message_* della conversazione; per cambiarli, usa prima PATCH /conversation/:id/model.
-
idstring in path obbligatorio - ID o slug della conversazione.
-
messagestring facoltativo - Il testo del messaggio di follow-up.
-
attachmentsarray facoltativo - Come nel corpo della richiesta.
-
knowledge_base_idsuint[] facoltativo - Le knowledge base per questo turno.
-
knowledge_base_limit_node_idsuint[] facoltativo - Limita il recupero a questi nodi.
-
world_knowledgebool facoltativo - Consente conoscenze che vanno oltre la knowledge base.
-
flash_modebool facoltativo - Livello di servizio prioritario, dove supportato.
-
toolsarray facoltativo - Gli strumenti per questo turno.
curl -X POST https://api.stickyprompts.com/api/v1/conversation/5120 \
-H "Authorization: Bearer $STICKY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "message": "Make the second one shorter." }'
Risposta. Come per POST /conversation: 200 con il Message dell’IA, oppure 200 {"conversation_context_id": ...} quando l’IA non risponde. Se la conversazione ha un confronto tra modelli attivo, il messaggio va in parallelo a ogni thread e la risposta è un array JSON di Message dell’IA, uno per thread.
Errori. Come per POST /conversation, più 404 {"error":"Conversation not found"}. Possono inviare messaggi solo il proprietario e gli utenti o i team con chat_contribute; chiunque altro riceve 503 {"error":"you are not allowed to send messages in this conversation"}.
POST /conversation/:id/stream
/api/v1/conversation/:id/stream Come POST /conversation/:id, ma restituisce subito 200 {"conversation_context_id": <id>}. Segui l’avanzamento sul WebSocket o tramite polling, come per POST /conversation/stream. Con un confronto tra modelli attivo, ogni thread trasmette in streaming sul WebSocket della conversazione padre.
-
idstring in path obbligatorio - ID o slug della conversazione.
Quando risponde l’IA
L’IA risponde a un messaggio quando vale almeno una di queste condizioni:
- un solo utente ha accesso in scrittura alla conversazione (il caso normale, che comprende ogni conversazione creata con una chiave API e senza
team_id); - il testo contiene
@ai(con distinzione tra maiuscole e minuscole); - è una chat con un agente;
- il testo menziona (
@mentions) il tag di un agente invitato nella conversazione.
In tutti gli altri casi il messaggio viene salvato come semplice messaggio dell’utente, visibile agli altri partecipanti, e l’endpoint restituisce 200 {"conversation_context_id": <id>} senza chiamare alcun modello, anche negli endpoint senza streaming.
Agenti in una conversazione
- Un
agent_idindicato alla creazione rende la conversazione una chat con un agente. Il suo modello non può essere cambiato in seguito. - In una conversazione con un solo utente,
@tagindirizza quel turno al tuo agente con quel tag, oppure a un agente condiviso con te (se il tag coincide, prevalgono i tuoi agenti). In una conversazione con più utenti si possono menzionare solo gli agenti invitati coninvited_agent_idso conPOST /conversation/:id/agents. - L’agente che risponde viene registrato sul messaggio dell’IA (
agent_id,agent).
Streaming
GET /conversation/:id/ws
/api/v1/conversation/:id/ws Un WebSocket che invia ogni aggiornamento della conversazione. Connettiti a wss://api.stickyprompts.com/api/v1/conversation/5120/ws e invia l’header Authorization: Bearer STICKY-API-... nella richiesta di upgrade. Gli oggetti WebSocket del browser non possono impostare header, quindi questo endpoint è pensato per i client lato server. Il server ignora tutto ciò che invii: legge solo per accorgersi della chiusura.
-
idinteger in path obbligatorio - L’ID numerico della conversazione. Con uno slug ti connetti a uno stream diverso e vuoto.
Ogni frame è un frame di testo JSON {"type": <string>, "data": <payload>}:
type | data | Quando |
|---|---|---|
message | Message (snapshot completo) | Un nuovo messaggio di un altro partecipante, e ogni aggiornamento di un messaggio dell’IA durante la generazione. text, parts e thinking contengono il contenuto accumulato finora, non un delta: sostituisci la tua copia in base a data.ID. status passa da thinking a generating e infine a finished. |
ai_message_end | nessuno (chiave assente) | La generazione è terminata, con o senza successo. Chiude il turno. |
error_message | Message con error_text, error_id, error_code facoltativo, status: "finished" | La generazione o la sua preparazione non è riuscita. Consideralo un evento finale: dopo gli errori di preparazione di solito segue un ai_message_end, ma non è garantito dopo gli errori del provider a generazione in corso. |
ai_model_change | { "ai_model_id", "ai_style", "auto_model_type", "reasoning_effort" } | Qualcuno ha chiamato PATCH /conversation/:id/model. |
run_data | Oggetto RunHistory | Solo per i turni avviati dall’esecuzione di un prompt salvato, insieme agli eventi message. Vedi Prompt ed esecuzioni. |
{"type":"message","data":{"ID":90412,"isUser":false,"status":"generating","text":"Here are","...":"..."}}
{"type":"message","data":{"ID":90412,"isUser":false,"status":"generating","text":"Here are three options","...":"..."}}
{"type":"message","data":{"ID":90412,"isUser":false,"status":"finished","text":"Here are three options for ...","response_duration_ms":6210,"...":"..."}}
{"type":"ai_message_end"}
- I messaggi che invii tu non vengono rimandati sulla tua connessione. La chiave agisce come il suo proprietario, quindi un client che la usa vede solo i messaggi dell’IA e quelli delle altre persone.
- Finché nessun client è connesso, gli eventi vengono messi in buffer, riprodotti alla connessione successiva e poi cancellati. Un client che si connette molto tempo dopo un turno può ricevere per primi gli eventi ormai superati di quel turno: ignora i messaggi il cui
IDhai già in stato finale. - Gli stream risiedono nella memoria del server API. Se ti connetti e non ricevi nulla per un turno che sai essere in corso, ripiega sul polling di
GET /conversation/:id.
# 1. Start the turn without waiting
curl -X POST https://api.stickyprompts.com/api/v1/conversation/stream \
-H "Authorization: Bearer $STICKY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "message": "Summarise last week for the Northwind team.", "auto_model_type": "balanced" }'
# -> {"conversation_context_id":5120}
# 2. cURL cannot hold a WebSocket open; poll the newest messages instead
curl "https://api.stickyprompts.com/api/v1/conversation/5120?page=1&size=2" \
-H "Authorization: Bearer $STICKY_API_KEY"import asyncio, json, os, requests, websockets
KEY = os.environ["STICKY_API_KEY"]
BASE = "https://api.stickyprompts.com/api/v1"
start = requests.post(
f"{BASE}/conversation/stream",
headers={"Authorization": f"Bearer {KEY}"},
json={"message": "Summarise last week for the Northwind team.", "auto_model_type": "balanced"},
).json()
cid = start["conversation_context_id"]
async def listen():
url = f"wss://api.stickyprompts.com/api/v1/conversation/{cid}/ws"
async with websockets.connect(url, additional_headers={"Authorization": f"Bearer {KEY}"}) as ws:
async for frame in ws:
event = json.loads(frame)
if event["type"] == "message" and not event["data"]["isUser"]:
print(event["data"]["status"], len(event["data"]["text"]))
elif event["type"] == "error_message":
print("Failed:", event["data"]["error_text"], event["data"]["error_id"])
break
elif event["type"] == "ai_message_end":
break
asyncio.run(listen())import WebSocket from "ws"; // Node: browsers cannot send the Authorization header
const KEY = process.env.STICKY_API_KEY;
const BASE = "https://api.stickyprompts.com/api/v1";
const { conversation_context_id: cid } = await fetch(`${BASE}/conversation/stream`, {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ message: "Summarise last week for the Northwind team.", auto_model_type: "balanced" }),
}).then((r) => r.json());
const ws = new WebSocket(`wss://api.stickyprompts.com/api/v1/conversation/${cid}/ws`, {
headers: { Authorization: `Bearer ${KEY}` },
});
ws.on("message", (raw) => {
const { type, data } = JSON.parse(raw);
if (type === "message" && !data.isUser) console.log(data.status, data.text.length);
if (type === "error_message") { console.error(data.error_text, data.error_id); ws.close(); }
if (type === "ai_message_end") ws.close();
});GET /conversation/:id/stream
/api/v1/conversation/:id/stream Un endpoint Server-Sent Events legacy. Usa invece il WebSocket o il polling. Nel codice attuale il percorso di invio delle conversazioni scrive solo sul WebSocket, quindi questo stream fa emergere solo eventi error_message e run_data per gli errori delle esecuzioni dei prompt; per il resto rimane aperto senza inviare il contenuto dei messaggi.
-
idinteger in path obbligatorio - ID numerico della conversazione.
Restituisce 404 {"error":"Stream not found"} quando il server non ha in memoria alcuno stream per la conversazione. Altrimenti risponde con Content-Type: text/event-stream e frame event:<name>\ndata:<json>\n\n, dove <name> è message, error_message (array di {run_id, error_id, error_text, model_name}), run_data (array di RunHistory) o close (data: Stream closed).
Leggere le conversazioni
GET /conversation/:id
/api/v1/conversation/:id Restituisce una conversazione con una pagina dei suoi messaggi, dal più recente. I metadati di paginazione si trovano negli header di risposta X-Total-Count (numero totale di messaggi), X-Page e X-Page-Size.
-
idstring in path obbligatorio - ID o slug della conversazione, oppure il suo slug di condivisione pubblica.
-
pageinteger in query facoltativo predefinito1 - Numero di pagina.
-
sizeinteger in query facoltativo predefinito10 - Messaggi per pagina.
Accesso. Il proprietario; gli utenti con chat_view o chat_contribute ottenuti tramite condivisione; oppure, quando :id è lo slug pubblico di una conversazione condivisa, chiunque sia ammesso dal tipo di condivisione (public: chiunque, internal: qualsiasi utente che ha effettuato l’accesso, workspace: i membri del workspace del proprietario).
{
"credits_used": "0.4213",
"conversation_context_id": 5120,
"conversation_context_name": "Q4 newsletter subject lines",
"conversation_context_slug": "aB3dE5gH",
"expensive_warning_threshold": 1000,
"public_slug": null,
"share_type": "",
"is_public": false,
"user_name": "John Smith",
"messages": [
{ "ID": 90412, "isUser": false, "status": "finished", "text": "Here are three options ...", "...": "..." },
{ "ID": 90411, "isUser": true, "status": "finished", "text": "Draft three subject lines ...", "...": "..." }
],
"next_message_ai_model_id": 12,
"next_message_ai_model_style": "prompty",
"next_message_auto_model_type": null,
"next_message_reasoning_effort": null,
"has_sub_conversations": false,
"unsupported_files": null,
"current_user_permission": "chat_contribute",
"owner_id": 77,
"user_count": 1,
"team_shares": null,
"agent_id": null,
"invited_agents": [],
"is_agent_chat": false
}
| Campo | Significato |
|---|---|
credits_used | I crediti dell’intera conversazione, compresi i thread di confronto (stringa decimale). |
messages | Questa pagina di messaggi, dal più recente. Nei messaggi dell’IA le citazioni sono renderizzate in text e l’originale si trova in raw_text. |
next_message_ai_model_id, next_message_ai_model | Il modello che userà il prossimo turno. In sua assenza vale il modello dell’ultimo messaggio dell’IA. |
next_message_ai_model_style | Lo stile del prossimo turno. Nota che la chiave è diversa da next_message_ai_style dell’oggetto conversazione. |
next_message_auto_model_type | best, balanced o cheapest quando è attiva la selezione automatica. |
forked_from_conversation_id, _slug, _name | Valorizzati nei fork. |
has_sub_conversations | Esiste un confronto tra modelli. |
unsupported_files | File allegati in precedenza che il prossimo modello non è in grado di leggere. |
current_user_permission | chat_contribute per il proprietario, altrimenti il tuo livello di accesso più alto: chat_view, chat_contribute o none. |
team_shares | {team_id, team, access_type} per ogni team con cui la conversazione è condivisa. |
Errori. 403 {"error":"You are not allowed to access this conversation"}, 404 {"error":"Conversation not found"}.
GET /conversation
/api/v1/conversation Elenca le tue conversazioni di chat, a partire da quelle con l’attività più recente. Compaiono solo le conversazioni di chat interattive con almeno un messaggio.
-
pageinteger in query facoltativo predefinito1 - Numero di pagina. I totali si trovano negli header
X-Total-Count,X-PageeX-Page-Size. -
sizeinteger in query facoltativo predefinito10 - Elementi per pagina.
-
searchstring in query facoltativo - Corrispondenza parziale sul testo di qualsiasi messaggio o sul nome della conversazione.
-
agent_iduint in query facoltativo - Elenca le chat di questo agente. Senza questo parametro, le chat con gli agenti sono escluse.
-
team_iduint in query facoltativo - Elenca le conversazioni condivise con questo team con
chat_contribute. Senza questo parametro ottieni le conversazioni di tua proprietà che non sono conversazioni di team. -
X-Project-IDinteger in header facoltativo - Solo le conversazioni di questo progetto.
Risposta. 200 con un array di oggetti conversazione (se è vuoto: []). Ognuno include user e project precaricati, message_count, credits_used e, in messages, solo l’ultimo messaggio (con attachments svuotato). Nota le chiavi in camelCase publicSlug, isPublic, userId, projectId, runId, isInteractive e forkedFromConversationId accanto a quelle in snake_case.
[
{
"ID": 5120, "CreatedAt": "2026-09-28T09:13:58Z", "UpdatedAt": "2026-09-28T09:14:10Z", "DeletedAt": null,
"slug": "aB3dE5gH", "publicSlug": null, "isPublic": false, "share_type": "",
"userId": 77, "user": { "ID": 77, "first_name": "John", "last_name": "Smith", "...": "..." },
"next_message_ai_model_id": 12, "next_message_ai_style": "prompty",
"next_message_auto_model_type": null, "next_message_reasoning_effort": null,
"projectId": null, "project": null, "agent_id": null,
"name": "Q4 newsletter subject lines", "source": "chat",
"messages": [ { "ID": 90412, "isUser": false, "text": "Here are three options ...", "...": "..." } ],
"isInteractive": true, "expensive_warning_threshold": 1000,
"forkedFromConversationId": null,
"message_count": 2, "credits_used": "0.4213"
}
]
GET /conversation/:id/used_prompts
/api/v1/conversation/:id/used_prompts Restituisce i prompt salvati distinti eseguiti in questa conversazione, compresi i thread di confronto: un array di { "id", "name", "slug", "ai_model_id", "user_id" }, oppure []. L’ordine non è definito.
-
idstring in path obbligatorio - ID o slug della conversazione.
Gestire le conversazioni
PATCH /conversation/:id
/api/v1/conversation/:id Rinomina una conversazione e la sposta in cima all’elenco. Solo per il proprietario.
-
idstring in path obbligatorio - ID o slug della conversazione.
-
namestring obbligatorio - Il nuovo nome. Se è vuoto o manca, restituisce
400.
Risposta. 200 con l’oggetto conversazione. Errori. 403 {"error":"You are not allowed to edit this conversation"}.
PATCH /conversation/:id/model
/api/v1/conversation/:id/model Imposta modello, stile e livello di ragionamento per i turni successivi. È consentito al proprietario e agli utenti con chat_contribute. Trasmette anche un evento WebSocket ai_model_change.
-
idstring in path obbligatorio - ID o slug della conversazione.
-
ai_model_iduint facoltativo - Il modello per i turni successivi.
400 {"error":"AI model not found"}se è sconosciuto. -
ai_stylestring facoltativo - Lo stile per i turni successivi.
-
auto_model_typestring facoltativo best,balanced,cheapesto null. Viene sempre scritto: se lo ometti o invii null, la selezione automatica si disattiva. Invialo a ogni chiamata per mantenerla attiva.-
reasoning_effortstring facoltativo - Normalizzato in base ai livelli supportati dal nuovo modello o da quello attuale.
Risposta. 200 {"message":"Model changed successfully"}. Errori. 400 {"error":"Cannot change model for agent conversations"}, 403 se non hai accesso.
POST /conversation/:id/fork
/api/v1/conversation/:id/fork Crea una nuova conversazione chiamata "Forked from <name>" con le copie di tutti i messaggi fino a message_id incluso. Vengono copiati allegati, strumenti e registrazioni delle approvazioni MCP, e restano invariate le impostazioni di modello, stile e ragionamento. Devi essere il proprietario della conversazione di origine, oppure questa deve essere condivisa; altrimenti ottieni 403.
-
idstring in path obbligatorio - ID o slug della conversazione di origine.
-
message_iduint obbligatorio - L’ultimo messaggio da copiare. Deve essere un messaggio
normaldi questa conversazione o di uno dei suoi thread di confronto (altrimenti404o400).
Risposta. 200 con una versione ridotta della risposta della conversazione: conversation_context_id, conversation_context_name, conversation_context_slug, public_slug, is_public, user_name, messages (qui dal più vecchio) e credits_used: "0". Le altre chiavi contengono il valore zero del rispettivo tipo.
DELETE /conversation/:id
/api/v1/conversation/:id Esegue un’eliminazione logica (soft delete) della conversazione e dei suoi messaggi e nasconde le relative esecuzioni dei prompt dalla cronologia delle esecuzioni. Solo per il proprietario.
-
idinteger in path obbligatorio - ID numerico della conversazione.
curl -X DELETE https://api.stickyprompts.com/api/v1/conversation/5120 \
-H "Authorization: Bearer $STICKY_API_KEY"
Risposta. 200 {"message":"Conversation deleted successfully"}. Errori. 404 {"error":"Conversation not found or you do not have permission to delete it"}.
POST /conversation/:id/retry
/api/v1/conversation/:id/retry Esegue di nuovo l’ultimo turno quando l’ultimo messaggio dell’IA si è concluso con un errore. Il messaggio non riuscito viene rigenerato sul posto (stesso ID) con il modello e lo stile attuali della conversazione, oppure con quelli dell’agente. Solo per il proprietario. Nessun corpo.
-
idstring in path obbligatorio - ID o slug della conversazione.
Risposta. 200 con:
- per un normale turno di chat, un Message. Sui modelli con
stream_support: truela chiamata risponde subito con il messaggio instatus: "thinking"e il contenuto arriva sul WebSocket o tramite polling; sugli altri modelli restituisce il messaggio completato; - per un turno nato da un prompt salvato, un array di oggetti RunHistory.
Errori. 400 {"error":"Last AI message does not have an error"}, 400 {"error":"No user message found in this conversation"}, 403, 500 {"error":"..."}.
POST /conversation/:id/snooze-expensive-warning
/api/v1/conversation/:id/snooze-expensive-warning Quando i credits_used di una conversazione superano il suo expensive_warning_threshold (predefinito: 1000), l’app web mostra un avviso sull’utilizzo. Questo endpoint raddoppia la soglia finché non supera l’utilizzo attuale. Solo per il proprietario.
-
idstring in path obbligatorio - ID o slug della conversazione.
Risposta. 200 con l’oggetto conversazione e il nuovo expensive_warning_threshold. Errori. 400 se l’utilizzo è ancora sotto la soglia.
POST /conversation/:id/agents
/api/v1/conversation/:id/agents Invita uno dei tuoi agenti nella conversazione, così da poterlo menzionare (@mentioned). Solo per il proprietario; non è consentito nelle chat con un agente (400).
-
idstring in path obbligatorio - ID o slug della conversazione.
-
agent_iduint obbligatorio - Un agente di tua proprietà.
Risposta. 200 {"message":"Agent invited successfully"}. Errori. 404 {"error":"Agent not found or not owned by user"}, 403.
DELETE /conversation/:id/agents/:agentId
/api/v1/conversation/:id/agents/:agentId Rimuove un agente invitato. Solo per il proprietario.
-
idstring in path obbligatorio - ID o slug della conversazione.
-
agentIdinteger in path obbligatorio - ID numerico dell’agente.
Risposta. 200 {"message":"Agent removed successfully"}. Errori. 400 {"error":"Invalid agent ID"}, 404.
Approvazione degli strumenti MCP
Questa sezione vale quando un turno usa un server MCP remoto (uno strumento remote_mcp o un agente con server MCP) la cui configurazione ha require_approval: true e il modello gira sul protocollo OpenAI Responses, l’unico percorso che genera richieste di approvazione. Le esecuzioni dei workflow approvano sempre in automatico.
- Il modello chiede di chiamare uno strumento MCP. La generazione si ferma e il messaggio dell’IA riceve in
mcp_approval_requestsuna voce per ogni chiamata richiesta. Nel percorso in streaming, al testo del messaggio viene aggiunto anche il testoApproval required for action: <name>, con l’etichetta del server e gli argomenti. - Ogni voce usa come chiavi i nomi dei campi Go (senza tag JSON).
Approved: nullindica una richiesta in attesa;trueofalseindicano che la decisione è stata presa.
{
"ID": 311, "CreatedAt": "2026-09-28T09:20:01Z", "UpdatedAt": "2026-09-28T09:20:01Z", "DeletedAt": null,
"ApprovalRequestID": "mcpr_abc123",
"Approved": null,
"ServerLabel": "crm",
"Name": "create_contact",
"Arguments": "{\"email\":\"jane@northwind.example\"}",
"MCPToolID": 0,
"MessageID": 90415
}
- Decidi con
POST /conversation/:id/approve, usando l’IDnumerico della voce, nonApprovalRequestID. - Il server registra la decisione ed esegue un nuovo turno dell’IA che la ritrasmette al modello. La continuazione è un nuovo messaggio dell’IA.
POST /conversation/:id/approve
/api/v1/conversation/:id/approve Approva o rifiuta una chiamata in attesa a uno strumento MCP.
-
idinteger in path obbligatorio - ID numerico della conversazione.
-
approval_request_iduint obbligatorio - L’
IDdella voce inmcp_approval_requests. -
is_approvedbool obbligatorio trueper approvare,falseper rifiutare.-
use_streambool facoltativo true: risponde subito e la continuazione arriva sul WebSocket o tramite polling.false: attende che la continuazione sia completata.
Risposta. 200 con la stringa JSON "Successfully handled approval", non un oggetto. Il messaggio di continuazione non viene restituito: leggilo con GET /conversation/:id o dal WebSocket.
Errori. 404 {"error":"Conversation not found"}, 404 {"error":"MCP Approval request not found"}, 400 {"error":"Approval request already processed"}, 400 {"error":"No messages in conversation"}, 500. La continuazione usa il modello fisso impostato per il prossimo messaggio della conversazione; nelle conversazioni con selezione automatica del modello questa operazione non è supportata.
Confronto tra modelli
Una sub-conversation esegue lo stesso messaggio su due o più modelli fianco a fianco, con un “thread” per modello. Finché è attiva, i follow-up inviati alla conversazione padre vanno a tutti i thread. Quando la chiudi, scegli un thread vincitore, la cui cronologia prosegue nella conversazione padre. È il lato API di Confrontare i modelli.
POST /conversation/:id/sub-conversation
/api/v1/conversation/:id/sub-conversation Avvia un confronto e attende tutti i thread.
-
idstring in path obbligatorio - ID o slug della tua conversazione (solo per il proprietario). I valori letterali
nulloundefinedcreano prima una nuova conversazione vuota.
-
ai_model_idsuint[] obbligatorio - Almeno 2 ID di modello.
-
messagestring facoltativo - Il messaggio inviato a ogni modello.
-
prompt_instance_iduint facoltativo - In alternativa a
message, esegue in ogni thread un’istanza di prompt salvata. -
attachmentsarray facoltativo - Usato solo con
prompt_instance_id. -
flash_modebool facoltativo - Usato solo con
prompt_instance_id. -
reasoning_effortstring facoltativo - Usato solo con
prompt_instance_id.
Lo stile è quello della conversazione, altrimenti il tuo stile preferito, altrimenti prompty.
Risposta. 200 con il Message contenitore (type: "sub_conversation"). Il suo sub_conversation contiene parent_conversation_context_id, threads, selected_thread_id e is_active: true. Ogni thread ha ai_model_id, ai_model, thread_conversation_context_id, thread_conversation_context (con messages), unsupported_files e credits_used.
Errori. 400 con meno di 2 modelli, 400 {"error":"AI model not found: <id>"}, 400 {"error":"An active sub-conversation already exists. Close it before creating a new one."}.
POST /conversation/:id/sub-conversation/stream
/api/v1/conversation/:id/sub-conversation/stream La variante in streaming: stessi parametri di percorso e stesso corpo, ma risponde non appena esistono i messaggi dell’utente. Le risposte dei thread arrivano poi in streaming sul WebSocket della conversazione padre, e nella risposta i messages di ogni thread contengono solo il messaggio dell’utente.
POST /sub-conversation/:id/close
/api/v1/sub-conversation/:id/close Chiude un confronto attivo in una conversazione di tua proprietà.
-
idinteger in path obbligatorio - ID numerico della sub-conversation (
sub_conversation_idosub_conversation.ID).
-
ai_model_iduint obbligatorio - Diventa il modello del prossimo messaggio della conversazione padre. Deve essere maggiore di 0.
-
ai_stylestring facoltativo - Diventa lo stile della conversazione padre.
-
thread_iduint facoltativo - Il thread vincitore.
0significa nessuno.
Risposta. 204 No Content. Errori. 404 se non esiste o non è attivo.
POST /sub-conversation/:id/select-thread
/api/v1/sub-conversation/:id/select-thread Cambia il thread i cui messaggi valgono come cronologia della conversazione. La sub-conversation deve essere chiusa; solo per il proprietario.
-
idinteger in path obbligatorio - ID numerico della sub-conversation.
-
thread_iduint obbligatorio - Maggiore di 0.
Risposta. 204 No Content.
Condivisione
Tutti e quattro gli endpoint di condivisione accettano l’ID numerico della conversazione e sono riservati al proprietario (altrimenti 404 {"error":"Conversation not found"}).
POST /conversation/:id/share
/api/v1/conversation/:id/share Condivide la conversazione tramite link. Se non esiste ancora, genera uno slug pubblico di 32 caratteri e imposta isPublic: true. Leggi la conversazione condivisa con GET /conversation/{public_slug}.
-
idinteger in path obbligatorio - ID numerico della conversazione.
-
share_typestring obbligatorio workspace(i membri del tuo workspace),internal(qualsiasi utente di StickyPrompts che ha effettuato l’accesso e ha il link) opublic(chiunque abbia il link).
Risposta. 200 {"message":"Conversation shared successfully","publicSlug":"<32 chars>"}. Errori. 400 {"error":"Invalid share type"}.
POST /conversation/:id/revoke-share
/api/v1/conversation/:id/revoke-share Imposta isPublic: false. Lo slug viene mantenuto. Nessun corpo.
-
idinteger in path obbligatorio - ID numerico della conversazione.
Risposta. 200 {"message":"Conversation share successfully revoked"}.
POST /conversation/:id/regenrate-share-slug
/api/v1/conversation/:id/regenrate-share-slug Sostituisce lo slug pubblico, così i vecchi link smettono di funzionare. Nel percorso si scrive regenrate, esattamente come mostrato. Nessun corpo.
-
idinteger in path obbligatorio - ID numerico della conversazione.
Risposta. 200 {"slug":"<new 32 chars>"}.
POST /conversation/:id/share-with-teams
/api/v1/conversation/:id/share-with-teams Condivide la conversazione in sola lettura con i tuoi team. L’elenco rappresenta lo stato completo desiderato per i tuoi team: ogni team di cui fai parte che non compare nell’elenco perde la condivisione, tranne i team che hanno già chat_contribute (come il team per cui è stata creata una conversazione di team). Garantisce inoltre che esista uno slug pubblico.
-
idinteger in path obbligatorio - ID numerico della conversazione.
-
sharesarray obbligatorio - Elementi
{ "team_id": uint, "access_type": "chat_view" | "none" }. Qui si può concedere solochat_view;chat_contributeviene rifiutato con400.
Risposta. 200 {"message":"Conversation shared successfully with teams","publicSlug":"<32 chars>"}. Errori. 403 {"error":"You are not a member of team <name>"}, 404 per i team sconosciuti.
Messaggi
POST /message/:id/export
/api/v1/message/:id/export Esporta un singolo messaggio in un file DOCX o PDF, come link di download oppure direttamente in un’integrazione di archiviazione collegata, per esempio Google Drive. Devi essere il proprietario della conversazione o avere almeno chat_view su di essa.
-
idinteger in path obbligatorio - ID numerico del messaggio.
-
formatstring obbligatorio docxopdf.-
targetstring facoltativo - Vuoto o
local: genera un file scaricabile. In alternativa, l’identificatore di un provider di archiviazione collegato, per esempiogoogle_drive. -
folder_idstring facoltativo - La cartella di destinazione nel provider. Obbligatorio per le destinazioni non locali.
-
namestring facoltativo - Il nome del file per le destinazioni su un provider (l’estensione viene aggiunta automaticamente). Per impostazione predefinita è il titolo della conversazione.
Risposta. 200 con esattamente una delle due forme seguenti:
{ "path": "https://<storage host>/<bucket>/<userId>/<random>.pdf" }
{ "entry": { "id": "...", "name": "Q4 subject lines.docx", "kind": "file", "mime_type": "...", "web_url": "...", "parent_id": "...", "...": "..." } }
Errori. 400 {"error":"invalid format"}, 400 {"error":"invalid folder_id"}, 400 {"error":"unknown export target"}, 403 {"error":"you are not allowed to export this message"} oppure una cartella di destinazione non scrivibile, 404 messaggio non trovato o integrazione non collegata, 409 {"error":"reconnect_required"}, 501 il provider non supporta il caricamento, 500.
Pagine correlate
- Prompt ed esecuzioni - esegui i prompt salvati; ogni esecuzione crea una conversazione.
- Errori, paginazione e quote - forme degli errori, motivi del
429e header di paginazione. - Riferimento degli strumenti -
send_message,get_conversation,list_conversations,delete_conversation.