Passa al contenuto principale

Endpoint: Agenti, Chat e Conversazioni

Riferimento degli endpoint per la gestione degli agenti conversazionali, l'invio di messaggi (con risposta completa o in streaming), le conversazioni, la traduzione di testi, i connettori MCP associabili agli agenti, le valutazioni e i template di prompt riutilizzabili.

Tutte le richieste usano l'URL base https://ai.askme.it/api/v2 e le intestazioni descritte in Autenticazione (X-Api-Key, e facoltativamente X-Source-App e X-External-Id). Gli elenchi seguono la paginazione offset/limit descritta nella Panoramica. Accanto a ogni endpoint è indicato, dove rilevante, il permesso che gli scope della chiave devono coprire.

1. Agenti​

POST /agents​

Crea un nuovo agente nell'organizzazione. Permesso: agents.create.

Attributi della richiesta

CampoInTipoObbligatorioPredefinitoDescrizione
namebodystring (1–255)Sì—Nome dell'agente.
descriptionbodystringNo—Descrizione libera.
model_providerbodystringNoopenaiFornitore del modello: openai, anthropic, google, mistral, aruba, ollama, local.
model_namebodystring (max 100)Nogpt-4o-miniModello da usare, tra quelli abilitati per l'organizzazione (l'elenco si legge con GET /ai/models).
system_promptbodystringNo—Istruzioni di sistema dell'agente. Può contenere variabili {{nome_variabile}}, valorizzate con template_vars in POST /chat.
temperaturebodyfloat (0.0–2.0)No0.7Temperatura di campionamento.
max_tokensbodyint (1–128000)No2048Numero massimo di token della risposta.
reasoning_effortbodystringNo—Solo per i modelli con ragionamento: minimal, low, medium, high.
rag_configbodyobjectNo—Basi di conoscenza consultate dall'agente (vedere sotto).
handoff_configbodyobjectNo—Regole di passaggio all'operatore: enabled e l'elenco conditions. Si consiglia di configurarle dalla console e di riusare l'oggetto restituito da GET /agents/{agent_id}.
tools_configbodyobjectNo—Impostazioni degli strumenti, per esempio require_tool_approval: true per chiedere un'approvazione prima di ogni chiamata a uno strumento.
output_schemabodyobject (JSON Schema)No—Schema JSON a cui la risposta del modello deve attenersi (output strutturato).
mcp_server_idsbodyint[]No—Connettori MCP da associare. Omesso o []: nessuna associazione. Ogni id deve appartenere all'organizzazione.
parent_idbodyintNo—Agente genitore: le istruzioni effettive sono la concatenazione lungo la catena (massimo 10 livelli).
iconbodyobjectNo—Icona dell'agente: {"kind": "material", "value": "support_agent"} (nome di un'icona Material in minuscolo) oppure {"kind": "image", "value": "https://..."} (indirizzo http(s) o percorso che inizia con /). Omesso: icona predefinita.
is_temporarybodyboolNofalseSe true, l'agente non compare negli elenchi standard.

Il campo rag_config

CampoTipoDescrizione
enabledboolAttiva la consultazione delle basi di conoscenza.
knowledge_base_idsint[]Identificativi delle basi di conoscenza consultate dall'agente.
rewrite_instructionsstring (max 1000)Indicazioni facoltative per riformulare le domande nel dominio dell'agente prima della ricerca (per esempio la terminologia di settore).

Il flusso di recupero (riformulazione della domanda, ricerca ibrida, riordino e filtro di pertinenza) è lo stesso per tutti gli agenti ed è regolato dalla piattaforma. Chiavi diverse da quelle elencate, inviate da versioni precedenti o da client esterni, vengono ignorate senza errore.

Esempio di richiesta

curl -X POST "https://ai.askme.it/api/v2/agents" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Content-Type: application/json" \
-d '{
"name": "Assistente sito",
"description": "Risponde sui servizi dell'\''azienda usando il sito pubblico e le FAQ.",
"model_provider": "openai",
"model_name": "gpt-5-mini",
"system_prompt": "Sei l'\''assistente virtuale del sito. Rispondi in italiano, con registro formale, solo sulla base delle informazioni disponibili.",
"temperature": 0.35,
"max_tokens": 1024,
"reasoning_effort": "minimal",
"rag_config": { "enabled": true, "knowledge_base_ids": [10, 11, 12] },
"icon": { "kind": "material", "value": "support_agent" }
}'

Esempio di risposta (201 Created)

{
"id": 54,
"tenant_id": "5b0e2f7a-2c41-4d0e-9a6b-1c9e8f3d4a21",
"name": "Assistente sito",
"description": "Risponde sui servizi dell'azienda usando il sito pubblico e le FAQ.",
"model_provider": "openai",
"model_name": "gpt-5-mini",
"system_prompt": "Sei l'assistente virtuale del sito. Rispondi in italiano, con registro formale, solo sulla base delle informazioni disponibili.",
"temperature": 0.35,
"max_tokens": 1024,
"tools_config": null,
"rag_config": { "enabled": true, "knowledge_base_ids": [10, 11, 12] },
"handoff_config": null,
"reasoning_effort": "minimal",
"mcp_server_ids": [],
"parent_id": null,
"is_temporary": false,
"output_schema": null,
"icon": { "kind": "material", "value": "support_agent" },
"status": "draft",
"version": 1,
"created_by": "apikey:28",
"created_at": "2026-09-24T17:09:03.035266Z",
"updated_at": "2026-09-24T17:09:03.035266Z"
}

Un agente creato tramite API è in stato draft: risponde già alle richieste POST /chat che lo indicano con agent_id, ma compare in GET /chat/agents e nella chat della console solo dopo l'attivazione, che si esegue impostando "status": "active" con PUT /agents/{agent_id}. Il campo created_by vale apikey:<id> per le risorse create con una chiave.

Esempio di handoff_config restituito per un agente con passaggio all'operatore attivo:

{
"enabled": true,
"conditions": [
{ "id": "scope", "type": "scope", "enabled": true, "timing": "immediate", "description": "Domanda fuori ambito" },
{ "id": "human_handoff", "type": "intent", "enabled": true, "timing": "immediate", "min_confidence": 0.5, "description": "Richiesta esplicita di un operatore umano" }
]
}

Errori specifici

CodiceSignificato
400mcp_server_ids contiene connettori che non appartengono all'organizzazione, oppure la configurazione non è valida.
422Validazione non superata (per esempio model_provider fuori elenco, icon non valida, temperature fuori intervallo).

GET /agents​

Elenca gli agenti dell'organizzazione. Permesso: agents.read.

Attributi della richiesta

CampoInTipoObbligatorioPredefinitoDescrizione
offsetqueryint (≥0)No0Offset di paginazione.
limitqueryint (1–100)No50Numero massimo di elementi.
searchquerystringNo—Ricerca testuale su nome e descrizione.
statusquerystringNo—Stato: draft, active, paused, archived.
model_namequerystringNo—Modello esatto.
parent_idqueryintNo—Solo gli agenti figli dell'agente indicato.
mcp_server_idqueryintNo—Solo gli agenti che usano il connettore MCP indicato.
knowledge_base_idqueryintNo—Solo gli agenti che consultano la base di conoscenza indicata.
include_temporaryqueryboolNofalseInclude gli agenti temporanei (per esempio quelli creati dall'analisi PDF per conversare con un documento).
sort_byquerystringNo—Campo di ordinamento (name, created_at, updated_at).
orderquerystringNo—asc o desc.

Esempio di richiesta

curl -G "https://ai.askme.it/api/v2/agents" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
--data-urlencode "limit=20" \
--data-urlencode "status=active"

La risposta (200 OK) ha la forma { "items": [...], "total": 3, "offset": 0, "limit": 20 }, con ogni elemento nello stesso formato di POST /agents.


GET /agents/{agent_id}​

Restituisce un agente. Permesso: agents.read. Risposta nello stesso formato di POST /agents; 404 se l'agente non esiste o appartiene a un'altra organizzazione.

PUT /agents/{agent_id}​

Aggiorna l'agente. Permesso: agents.update. Tutti i campi sono facoltativi e vengono modificati solo quelli inviati; ogni modifica incrementa version e salva un'istantanea della configurazione. Oltre ai campi di POST /agents:

CampoInTipoDescrizione
statusbodystringdraft, active, paused, archived.
mcp_server_idsbodyint[] | nullnull o omesso: associazioni invariate; []: rimuove tutte le associazioni; [n, m]: sostituisce le associazioni con quelle indicate.
curl -X PUT "https://ai.askme.it/api/v2/agents/54" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "status": "active", "temperature": 0.3 }'

DELETE /agents/{agent_id}​

Elimina l'agente e libera la quota agents. Permesso: agents.delete. Risposta 204 No Content.

POST /agents/{agent_id}/duplicate​

Crea una copia indipendente dell'agente, in stato draft. Permesso: agents.create. Risponde 201 con il nuovo agente; la copia consuma la quota agents come una nuova creazione.

GET /agents/{agent_id}/versions​

Elenca le versioni salvate della configurazione (version_number, config_snapshot, changelog, created_at, created_by). Paginazione offset/limit (massimo 200).

POST /agents/{agent_id}/rollback/{version_number}​

Riporta la configurazione a una versione precedente e registra una nuova versione con changelog "Rollback to version N". Permesso: agents.update. Risponde 404 se la versione non esiste.

GET /agents/{agent_id}/usage-sources​

Indica chi usa l'agente: le chiavi API e le applicazioni che hanno avviato conversazioni con esso.

{
"items": [
{ "kind": "product", "id": 1, "label": "api_direct", "detail": "4 conversazioni" }
],
"total": 1
}

kind vale api_key oppure product.

Connettori MCP di un agente​

Oltre al campo mcp_server_ids di POST e PUT /agents, sono disponibili endpoint dedicati (permesso agents.update per le modifiche):

  • POST /agents/{agent_id}/mcp-servers: corpo { "mcp_server_id": 12 }. Risponde 201, oppure 409 se il connettore è già associato.
  • GET /agents/{agent_id}/mcp-servers: connettori associati, con il dettaglio.
  • DELETE /agents/{agent_id}/mcp-servers/{mcp_server_id}: rimuove l'associazione (204, oppure 404).

2. Chat​

POST /chat​

Invia un messaggio a un agente e restituisce la risposta, completa oppure in streaming. È l'endpoint principale per le integrazioni conversazionali.

  • Modalità agente: si indica agent_id. Modello, istruzioni, basi di conoscenza e connettori derivano dalla configurazione dell'agente.
  • Modalità diretta: si omette agent_id e si forniscono model e system_prompt. La chiamata va direttamente al modello, senza basi di conoscenza.

Attributi della richiesta

CampoInTipoObbligatorioPredefinitoDescrizione
messagebodystring (1–32000)Sì—Testo del messaggio dell'utente.
agent_idbodyintNo*—Agente. *Se omesso sono obbligatori model e system_prompt.
conversation_idbodyintNo—Conversazione esistente da proseguire. Se assente (e senza external_conversation_id) viene creata una nuova conversazione.
external_conversation_idbodystringNo—Identificativo della conversazione nel sistema chiamante. La prima richiesta crea la conversazione con questo identificativo; le richieste successive con lo stesso valore e lo stesso agente la proseguono. Consente di non memorizzare il conversation_id.
streambodyboolNofalseSe true la risposta è uno stream SSE.
include_sourcesbodyboolNotrueInclude le fonti usate (rag_sources).
supports_citationsbodyboolNofalseChiede al modello di citare le fonti nella risposta con riferimenti numerati [N]; ogni fonte citata riporta il numero in citation_index. Richiede include_sources.
include_thinkingbodyboolNofalsePer i modelli con ragionamento, restituisce anche il ragionamento (thinking_content e, in streaming, eventi thinking).
template_varsbodyobject (string→string)No—Valori delle variabili {{nome}} presenti nelle istruzioni dell'agente.
filesbodyarrayNo—Allegati: [{ "filename", "content_type", "data" }], con data in base64.
temperaturebodyfloatNo(dell'agente)Temperatura per questo messaggio.
max_tokensbodyintNo(dell'agente)Limite di token per questo messaggio.
modelbodystringNo*—Solo in modalità diretta.
system_promptbodystringNo*—Solo in modalità diretta.
response_formatbodystringNomarkdownFormato del testo della risposta: markdown o html.
llm_response_formatbodyobjectNo—Schema JSON per un output strutturato valido solo per questo messaggio.
classification_intentsbodyarrayNo—Categorie di intento personalizzate per la classificazione del messaggio: [{ "name", "description" }].
force_handoffbodyboolNofalseRichiede il passaggio all'operatore.
skip_handoffbodyboolNofalseNon valuta il passaggio all'operatore per questo messaggio.
skip_scope_checkbodyboolNofalseNon valuta se la domanda è fuori ambito per questo messaggio.
metadatabodyobjectNo—Metadati liberi, riportati nel record di consumo.
mcp_authbodyobject (string→string)No—Credenziali dell'utente per i connettori MCP che le richiedono, indicizzate per connettore.
tool_approvalbodyobjectNo—Risposta a una richiesta di approvazione di uno strumento: { "approved": true, "pending_message_id": 5932 } (vedere Approvazione degli strumenti).

L'attribuzione dei consumi si imposta con le intestazioni X-Source-App e X-External-Id (si veda Autenticazione); i campi source_app ed external_id del corpo non sostituiscono le intestazioni. Con una chiave API le fonti nascoste delle basi di conoscenza non vengono mai restituite.

Esempio di richiesta (cURL)

curl -X POST "https://ai.askme.it/api/v2/chat" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "X-External-Id: ticket-9281" \
-H "Content-Type: application/json" \
-d '{
"agent_id": 54,
"message": "Di cosa si occupa Lascaux?",
"external_conversation_id": "ticket-9281",
"stream": false
}'

Esempio di richiesta (Python, httpx)

import os

import httpx

client = httpx.Client(
base_url=os.environ["ASKMEAI_HOST"] + "/api/v2",
headers={
"X-Api-Key": os.environ["ASKMEAI_API_KEY"],
"X-Source-App": os.environ.get("ASKMEAI_SOURCE_APP", "api_direct"),
},
timeout=60.0,
)

resp = client.post("/chat", json={
"agent_id": 54,
"message": "Di cosa si occupa Lascaux?",
"external_conversation_id": "ticket-9281",
"stream": False,
})
resp.raise_for_status()
data = resp.json()
print(data["content"])
for source in data.get("rag_sources") or []:
print("-", source["metadata"].get("document_title") or source["title"])

Esempio di risposta (200 OK)

{
"message_id": 5921,
"conversation_id": 2758,
"external_conversation_id": "ticket-9281",
"content": "Lascaux è un'impresa che offre servizi informatici orientati alla trasformazione digitale delle aziende. [...]",
"thinking_content": null,
"content_format": "markdown",
"role": "assistant",
"model_used": "gpt-5-mini-2025-08-07",
"tokens_input": 2415,
"tokens_output": 243,
"latency_ms": 7333,
"rag_sources": [
{
"document_id": "100",
"knowledge_base_id": 10,
"chunk_id": "15",
"title": null,
"content_preview": "Mettiti in contatto: troveremo insieme le risposte che cerchi [...]",
"relevance_score": 0.029828,
"metadata": {
"source_url": "https://www.lascaux.it/contatti",
"source_type": "text",
"document_title": "Contatti - Lascaux",
"source_priority": 2
},
"is_visible": true,
"passages": [
{ "chunk_id": "15", "content_preview": "Mettiti in contatto: [...]", "relevance_score": 0.029828 },
{ "chunk_id": "14", "content_preview": "Contatti. Telefono, la sede, scrivici [...]", "relevance_score": 0.029762 }
]
}
],
"confidence_score": 0.63,
"needs_review": false,
"handoff_requested": false,
"handoff_reason": null,
"handoff_trigger": null,
"intent": null,
"handoff_intent": null,
"sentiment": null,
"is_in_scope": null,
"classified_intent": null,
"intent_confidence": null,
"handoff_criterion": null,
"tool_calls_count": 0,
"tools_used": [],
"pending_tool_approval": false,
"pending_tool_calls": null,
"pending_message_id": null,
"created_at": "2026-09-24T17:10:58.072295Z"
}

Il testo della risposta è nel campo content, al primo livello dell'oggetto.

Campi delle fonti (rag_sources[])

CampoDescrizione
document_idIdentificativo del documento (stringa).
knowledge_base_idBase di conoscenza del documento.
chunk_idFrammento più pertinente del documento.
titleTitolo del documento, quando disponibile. Per le pagine web il titolo è in metadata.document_title.
content_previewEstratto del frammento più pertinente.
relevance_scorePunteggio di pertinenza del frammento, utile a ordinare le fonti tra loro; la scala dipende dalla configurazione del recupero e non va interpretata come una percentuale.
metadataMetadati del documento, per esempio source_url, document_title, source_type.
is_visibleSempre true per le richieste con chiave API.
citation_indexPresente solo con supports_citations: il numero [N] con cui la risposta cita la fonte.
passages[]Presente quando la risposta si basa su più frammenti dello stesso documento: chunk_id, content_preview, relevance_score di ciascun frammento, il più pertinente per primo.

Altri campi della risposta

CampoDescrizione
confidence_score, needs_reviewConfidenza della risposta (0–1) e indicazione che la risposta merita una revisione.
handoff_requested, handoff_reason, handoff_trigger, handoff_criterion, handoff_intentEsito della valutazione del passaggio all'operatore: se è richiesto, per quale motivo, quale condizione lo ha attivato e quale segnale di escalation è stato riconosciuto.
intent, classified_intent, intent_confidenceIntento del messaggio e relativa confidenza, valorizzati quando la classificazione è attiva (per esempio con classification_intents).
sentiment, is_in_scopeSentimento del messaggio e valutazione dell'ambito, quando calcolati.
tool_calls_count, tools_usedChiamate a strumenti eseguite nel turno.
pending_tool_approval, pending_tool_calls, pending_message_idPresenti quando il turno è sospeso in attesa di approvazione di uno strumento.

Risposta in streaming (SSE)​

Con "stream": true il servizio risponde con Content-Type: text/event-stream. Ogni evento è una riga data: seguita da un oggetto JSON con il campo type:

data: {"type": "...", ...}

Gli eventi riportano in genere tutti i campi del formato, valorizzati a null quando non pertinenti: il client distingue gli eventi dal campo type e legge solo i campi indicati nella tabella. Il testo arriva in porzioni brevi, anche di poche lettere, da concatenare.

TipoQuandoCampi principali
rag_thinkingSubito dopo l'avvio in modalità agente, e di nuovo quando inizia la ricerca nelle basi di conoscenza (può quindi arrivare più volte). È un segnale senza contenuto, utile a mostrare un indicatore di attesa—
sourcesFonti usate. Con supports_citations arriva a fine risposta e contiene solo le fonti citatesources[] (stesso formato di rag_sources)
thinkingPorzione del ragionamento del modello, solo con include_thinking: truecontent
contentPorzione del testo della risposta, da concatenare nell'ordine di arrivocontent
tool_callIl modello invoca uno strumentotool_name, tool_args
tool_approval_requiredLo strumento richiede un'approvazione; il turno si riprende con tool_approvalpending_tool_calls[], pending_message_id
input_requiredLo strumento chiede dati all'utente tramite un modulotool_name, input_requests, pending_message_id
confidencePunteggio di confidenza della rispostaconfidence_score, confidence_signals, needs_review
handoff_decisionEsito della valutazione del passaggio all'operatore, solo per gli agenti con passaggio all'operatore attivohandoff_requested, handoff_reason, handoff_trigger, handoff_intent, handoff_criterion
usageRiepilogo del turnousage.message_id, usage.conversation_id, usage.model_used, usage.tokens_input, usage.tokens_output, usage.latency_ms, e gli stessi indicatori di confidenza e passaggio all'operatore della risposta completa
doneFine dello stream—
errorErrore verificatosi dopo l'avvio dello streamerror (messaggio), code

Codici dell'evento error:

codeSignificato
quota_exceededQuota delle conversazioni del piano esaurita.
context_window_exceededIl messaggio, con la cronologia, supera la finestra di contesto del modello.
invalid_requestParametri non validi (per esempio un agente o una conversazione inesistenti).
missing_provider_api_keyIl fornitore del modello non è configurato per l'organizzazione; error riporta il nome del fornitore.
internal_errorErrore interno.
(assente)Errore del fornitore del modello durante la generazione; il messaggio è in error.

Dopo un evento error può seguire l'evento done. Poiché lo stato HTTP 200 è già stato inviato quando lo stream inizia, gli errori successivi arrivano solo come eventi.

Esempio di stream senza supports_citations (estratto, campi a null omessi per leggibilità; senza citazioni le fonti arrivano prima del testo):

data: {"type":"rag_thinking"}

data: {"type":"rag_thinking"}

data: {"type":"sources","sources":[{"document_id":"100","knowledge_base_id":10,"chunk_id":"15","title":null,"content_preview":"Mettiti in contatto: [...]","relevance_score":0.029828,"metadata":{"source_url":"https://www.lascaux.it/contatti"},"is_visible":true}]}

data: {"type":"content","content":"L"}

data: {"type":"content","content":"asc"}

data: {"type":"content","content":"aux è un'impresa"}

data: {"type":"confidence","confidence_score":0.63,"confidence_signals":{"length":1.0,"overlap":0.8,"coverage":1.0,"uncertainty":1.0},"needs_review":false}

data: {"type":"handoff_decision","handoff_requested":false}

data: {"type":"usage","usage":{"message_id":5921,"conversation_id":2758,"model_used":"gpt-5-mini-2025-08-07","tokens_input":2415,"tokens_output":243,"latency_ms":7333,"needs_review":false,"handoff_requested":false,"tool_calls_count":0,"tools_used":[]}}

data: {"type":"done"}

Esempio Python (httpx, lettura dello stream)

import json
import os

import httpx

with httpx.stream(
"POST",
os.environ["ASKMEAI_HOST"] + "/api/v2/chat",
headers={
"X-Api-Key": os.environ["ASKMEAI_API_KEY"],
"X-Source-App": "api_direct",
"Accept": "text/event-stream",
},
json={"agent_id": 54, "message": "Come posso contattare Lascaux?", "stream": True},
timeout=None,
) as resp:
resp.raise_for_status()
for raw in resp.iter_lines():
if not raw.startswith("data: "):
continue
event = json.loads(raw[len("data: "):])
kind = event["type"]
if kind == "content":
print(event["content"], end="", flush=True)
elif kind == "error":
print(f"\n[errore {event.get('code')}] {event.get('error')}")
elif kind == "usage":
print(f"\n[conversazione {event['usage']['conversation_id']}]")
elif kind == "done":
print()
break

Errori specifici

CodiceSignificato
400Parametri non validi, per esempio un agent_id o un conversation_id inesistenti o di un'altra organizzazione (detail: Invalid request parameters).
413Il messaggio supera la finestra di contesto del modello: detail.code vale context_window_exceeded e detail riporta model, context_window, estimated_input_tokens, max_output_tokens, total_needed.
422Validazione non superata, per esempio message vuoto o oltre 32000 caratteri, oppure modalità diretta senza model o system_prompt.
429Quota delle conversazioni del piano esaurita (all'avvio di una nuova conversazione), crediti AI esauriti oppure limite di frequenza della chiave (con Retry-After).
503Troppi stream contemporanei: ripetere la richiesta più tardi.

Approvazione degli strumenti​

Se l'agente è configurato per chiedere un'approvazione prima di usare uno strumento (tools_config.require_tool_approval, oppure un'impostazione del singolo strumento del connettore), il turno si sospende: la risposta completa riporta pending_tool_approval: true, pending_tool_calls[] (tool_call_id, tool_name, tool_args) e pending_message_id, mentre lo stream emette l'evento tool_approval_required. Per riprendere il turno si invia un nuovo POST /chat con lo stesso agente e la stessa conversazione e il campo tool_approval:

{
"agent_id": 55,
"conversation_id": 2790,
"message": "Approvato",
"tool_approval": { "approved": true, "pending_message_id": 5932 }
}

Con "approved": false lo strumento non viene eseguito e il modello risponde senza il suo risultato.


GET /chat/agents​

Elenca gli agenti attivi con cui si può avviare una conversazione, con le sole informazioni utili a sceglierli (mai istruzioni, modello o connettori). Permesso: chat.agents.list oppure agents.read.

{
"items": [
{
"id": 54,
"name": "Assistente sito",
"description": "Risponde sui servizi dell'azienda usando il sito pubblico e le FAQ.",
"icon": null,
"has_prompt_placeholders": false,
"prompt_placeholders": []
},
{
"id": 55,
"name": "Supporto interno",
"description": "Supporto ai reparti, con il contesto del reparto richiedente.",
"icon": { "kind": "material", "value": "support_agent" },
"has_prompt_placeholders": true,
"prompt_placeholders": ["reparto"]
}
]
}

prompt_placeholders elenca le variabili {{nome}} delle istruzioni, da valorizzare con template_vars in POST /chat.

POST /classify​

Classifica un messaggio (intento, sentimento, ambito) e valuta il passaggio all'operatore secondo la configurazione dell'agente, senza generare una risposta. Risponde 404 se l'agente non appartiene all'organizzazione.

CampoInTipoObbligatorioDescrizione
agent_idbodyintSìAgente di cui usare le regole.
messagebodystring (1–32000)SìMessaggio da classificare.
conversation_idbodyintNoConversazione di contesto.
external_conversation_idbodystringNoConversazione di contesto, tramite identificativo esterno.
classification_intentsbodyarrayNoCategorie di intento personalizzate: [{ "name", "description" }].
external_idbodystring (max 255)NoIdentificativo del sistema chiamante registrato sui costi della classificazione. L'intestazione X-External-Id ha la precedenza; se mancano entrambi vale external_conversation_id.

La risposta contiene intent (null se nessuna delle categorie personalizzate corrisponde), confidence, should_handoff, handoff_reason, handoff_trigger, handoff_intent, sentiment, sentiment_score, is_in_scope, complexity, complexity_score.

Le condizioni di passaggio all'operatore impostate su Dopo i tentativi contano le risposte del bot su tutta la conversazione indicata (vedere Handoff). Ogni classificazione conta come un'esecuzione agentic.

POST /decisions​

Risponde a domande tipizzate (sì o no, scelta fra opzioni, punteggio) su un testo, una conversazione o un oggetto, e restituisce per ogni domanda la probabilità delle opzioni. Usa il modello decisionale dell'organizzazione, cioè un modello del catalogo con la capacità Decisionale (vedere Modelli LLM). Disponibile dalla versione 2.3.17.

CampoInTipoObbligatorioDescrizione
statebodystring | object[] | objectSìLo stato da giudicare: un testo, una conversazione ([{ "role": "user" | "assistant", "content" }]) oppure un oggetto libero.
questionsbodyobjectSìDa 1 a 8 domande, indicizzate per nome. Ogni domanda ha type e instructions, più criteria secondo il tipo (vedere sotto).
modelbodystringNoModello decisionale da usare al posto di quello dell'organizzazione.
external_idbodystring (max 255)NoIdentificativo del sistema chiamante registrato sui costi. L'intestazione X-External-Id ha la precedenza.
typecriteriaRisposta
noul (sì o no)Facoltativo: { "true": "...", "false": "..." }noul: probabilità del sì (da 0 a 1)
choice (scelta)Obbligatorio: { "etichetta": "descrizione" | null }, almeno 2 vocichoice, confidence e probabilities per etichetta
score (punteggio)Obbligatorio: elenco delle descrizioni dei livelli, dal più basso, almeno 2score (indice del livello), confidence e probabilities per livello

Lo stato, le istruzioni e le descrizioni dei criteri passano sempre dalla protezione dei dati personali dell'organizzazione prima di arrivare al modello; le etichette delle domande choice restano invariate, perché le risposte sono indicizzate su di esse.

Esempio di richiesta

curl -X POST "https://ai.askme.it/api/v2/decisions" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-External-Id: ticket-4711" \
-H "Content-Type: application/json" \
-d '{
"state": [
{ "role": "user", "content": "Buongiorno, non riesco ad accedere al mio account." },
{ "role": "assistant", "content": "Può descrivere l'\''errore che vede?" },
{ "role": "user", "content": "Dice che la password è errata, ma è urgente." }
],
"questions": {
"urgent": { "type": "noul", "instructions": "Il messaggio è urgente?" },
"topic": {
"type": "choice",
"instructions": "Qual è l'\''argomento della richiesta?",
"criteria": { "accesso": "Problemi di login", "fatturazione": null }
},
"tone": {
"type": "score",
"instructions": "Valuta il tono dell'\''utente.",
"criteria": ["sereno", "neutro", "irritato"]
}
}
}'

Esempio di risposta

{
"model": "gpt-6-luna",
"answers": {
"urgent": { "type": "noul", "noul": 0.93 },
"topic": {
"type": "choice",
"choice": "accesso",
"confidence": 0.91,
"probabilities": { "accesso": 0.91, "fatturazione": 0.09 }
},
"tone": {
"type": "score",
"score": 1,
"confidence": 0.64,
"probabilities": { "sereno": 0.1, "neutro": 0.64, "irritato": 0.26 }
}
},
"latency_ms": 480,
"usage": { "input_tokens": 212 }
}

Ogni risposta riuscita conta come un'esecuzione agentic; le risposte con errore non consumano esecuzioni.

Errori specifici

CodiceSignificato
422Corpo non valido, più di 8 domande, oppure una domanda con più opzioni del massimo consentito (predefinito 20).
503Decisione non disponibile: {"code": "DECISION_UNAVAILABLE", "reason": "..."}. Fra i motivi: timeout, rate_limited, pii_unavailable (protezione dei dati personali non pronta), model_not_decision (il modello indicato non è decisionale), not_configured.

Classificazione con il modello decisionale​

Per un'organizzazione, l'intento e il segnale di passaggio all'operatore calcolati da POST /classify possono essere affidati al modello decisionale. L'impostazione, a cura del team Askme, prevede tre modalità: spenta (predefinita); in prova, in cui il modello decisionale viene interrogato e il confronto registrato nei costi, senza cambiare la risposta; automatica, in cui decide il modello decisionale quando la sua confidenza supera la soglia stabilita, altrimenti resta la classificazione attuale. In caso di errore del modello decisionale la classificazione torna sempre a quella attuale.


3. Conversazioni​

Una conversazione appartiene a chi l'ha avviata: le conversazioni avviate con una chiave API appartengono a quella chiave (user_id vale apikey:<id>). Per leggere le conversazioni di altri utenti o di altre chiavi serve il permesso conversations.read_all; per rinominarle, chiuderle o eliminarle serve conversations.delete. Senza il permesso la risposta è 404, come per una conversazione inesistente.

GET /conversations​

Elenca le conversazioni della chiave che effettua la richiesta.

CampoInTipoPredefinitoDescrizione
offsetqueryint0Paginazione.
limitqueryint (1–100)50Dimensione della pagina.
exclude_source_appquerystring—Esclude le conversazioni attribuite all'applicazione indicata.

Esempio di risposta (200 OK)

{
"items": [
{
"id": 2758,
"tenant_id": "5b0e2f7a-2c41-4d0e-9a6b-1c9e8f3d4a21",
"agent_id": 54,
"agent_name": "Assistente sito",
"user_id": "apikey:28",
"title": "Di cosa si occupa Lascaux?",
"status": "active",
"message_count": 2,
"metadata": null,
"external_id": "ticket-9281",
"source_app": "api_direct",
"agent_deleted": false,
"last_message_preview": "Di cosa si occupa Lascaux?",
"needs_review": false,
"handoff": false,
"insights": null,
"created_at": "2026-09-24T17:10:50.687393Z",
"updated_at": "2026-09-24T17:10:58.072295Z"
}
],
"total": 1,
"offset": 0,
"limit": 50
}

GET /conversations/monitoring​

Tutte le conversazioni dell'organizzazione. Permesso: conversations.read_all.

CampoInTipoDescrizione
offset, limitqueryintPaginazione (limit massimo 100).
statusquerystringactive, closed, archived.
agent_idqueryintAgente.
date_from, date_toquerydatetime ISO 8601Intervallo di date.
source_appquerystringSolo le conversazioni attribuite all'applicazione indicata.
exclude_source_appquerystringEsclude l'applicazione indicata.
needs_reviewqueryboolSolo le conversazioni con risposte da rivedere.
handoffqueryboolSolo le conversazioni con passaggio all'operatore.

GET /conversations/{conversation_id}​

Dettaglio della conversazione, senza messaggi, nello stesso formato degli elementi di GET /conversations.

GET /conversations/by-external-id/{external_id}​

Recupera la conversazione tramite l'identificativo inviato in external_conversation_id nel corpo di POST /chat. L'intestazione X-External-Id non entra in questa ricerca: serve solo all'attribuzione dei consumi.

CampoInTipoDescrizione
external_idpathstringIdentificativo esterno della conversazione.
agent_idqueryintFacoltativo: limita la ricerca a un agente, utile se lo stesso identificativo è stato usato con più agenti.
curl "https://ai.askme.it/api/v2/conversations/by-external-id/ticket-9281" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx"

Per proseguire la conversazione è sufficiente inviare un nuovo POST /chat con lo stesso external_conversation_id (oppure con il conversation_id restituito). Risponde 404 se nessuna conversazione visibile alla chiave corrisponde all'identificativo.

GET /conversations/{conversation_id}/messages​

Messaggi della conversazione, dal più vecchio.

CampoInTipoPredefinitoDescrizione
offsetqueryint0Paginazione.
limitqueryint (1–500)100Dimensione della pagina.

Esempio di risposta (200 OK, estratto)

{
"items": [
{
"id": 5920,
"conversation_id": 2758,
"role": "user",
"content": "Di cosa si occupa Lascaux?",
"tokens_input": null,
"tokens_output": null,
"model_used": null,
"latency_ms": null,
"metadata": null,
"created_at": "2026-09-24T17:10:50.723217Z"
},
{
"id": 5921,
"conversation_id": 2758,
"role": "assistant",
"content": "Lascaux è un'impresa che offre servizi informatici [...]",
"tokens_input": 2415,
"tokens_output": 243,
"model_used": "gpt-5-mini-2025-08-07",
"latency_ms": 7333,
"metadata": {
"rag_used": true,
"confidence": 0.631,
"needs_review": false,
"handoff_requested": false,
"tool_calls_count": 0,
"tools_used": [],
"sources": [
{
"document_id": "100",
"knowledge_base_id": 10,
"chunk_id": "15",
"title": "Contatti - Lascaux",
"relevance_score": 0.029828,
"is_visible": true,
"source_type": "text",
"source_url": "https://www.lascaux.it/contatti",
"snippet": "Mettiti in contatto: troveremo insieme le risposte che cerchi [...]",
"passages": [
{ "chunk_id": "15", "snippet": "Mettiti in contatto: [...]", "relevance_score": 0.029828 },
{ "chunk_id": "14", "snippet": "Contatti. Telefono, la sede, scrivici [...]", "relevance_score": 0.029762 }
]
}
]
},
"created_at": "2026-09-24T17:10:58.072295Z"
}
],
"total": 2,
"offset": 0,
"limit": 100
}

Nei messaggi salvati le fonti sono in metadata.sources, con title, source_type, source_url e un estratto in snippet; citation_index è presente se la risposta è stata generata con supports_citations. Con una chiave API le fonti nascoste non compaiono.

PATCH /conversations/{conversation_id}/messages/{message_id}​

Imposta o toglie il contrassegno di revisione su un messaggio. Corpo: { "needs_review": true }. Restituisce il messaggio aggiornato.

POST /conversations/{conversation_id}/messages/{message_id}/feedback​

Registra una valutazione su una risposta dell'assistente.

CampoInTipoObbligatorioDescrizione
ratingbodystringSìpositive o negative (altri valori: 400).
commentbodystringNoCommento.
{ "message_id": 5921, "rating": "positive", "comment": "Risposta chiara." }

POST /conversations/{conversation_id}/export​

Scarica la conversazione come allegato. Parametro format: json (predefinito) oppure csv.

  • JSON: { "conversation": {...}, "messages": [{ "id", "role", "content", "model_used", "confidence", "needs_review", "sources", "created_at" }], "exported_at": "..." }.
  • CSV: una riga per messaggio, con le colonne timestamp, role, content, model_used, confidence, needs_review.

PUT /conversations/{conversation_id}​

Aggiorna titolo o stato della conversazione (è accettato anche PATCH).

CampoInTipoDescrizione
titlebodystring (max 500)Nuovo titolo.
statusbodystringactive, closed o archived.

DELETE /conversations/{conversation_id}​

Elimina la conversazione e i suoi messaggi. Risposta 204 No Content.


4. Traduzione​

Traduzione di testi con il servizio di traduzione configurato per l'installazione. Gli endpoint richiedono che la funzionalità translation sia attiva per l'organizzazione (altrimenti 403 con FEATURE_FLAG_DISABLED) e il permesso translation.use. Le traduzioni consumano i crediti AI dell'organizzazione; i testi già tradotti vengono riutilizzati da una cache.

POST /translation/translate​

CampoInTipoObbligatorioDescrizione
textbodystring (1–32000)SìTesto da tradurre.
target_langbodystring (2–10)SìLingua di destinazione, codice ISO 639-1 (per esempio en, it, de).
source_langbodystring (2–10)NoLingua di origine. Se omessa viene rilevata automaticamente.
curl -X POST "https://ai.askme.it/api/v2/translation/translate" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Content-Type: application/json" \
-d '{
"text": "Le spedizioni standard partono entro 24 ore lavorative.",
"target_lang": "en"
}'

Esempio di risposta (200 OK)

{
"translated_text": "Standard shipments start within 24 working hours.",
"detected_source_lang": "IT",
"provider": "openai"
}

POST /translation/translate-batch​

Traduce più testi in una sola richiesta, nella stessa lingua di destinazione. Ogni elemento ha un id scelto dal chiamante, restituito insieme alla traduzione.

CampoInTipoObbligatorioDescrizione
itemsbodyarraySì[{ "id": string (1–200), "text": string (1–32000) }], almeno un elemento.
target_langbodystringSìLingua di destinazione.
source_langbodystringNoLingua di origine.

Una richiesta può contenere al massimo 200 elementi e 100.000 caratteri complessivi (valori predefiniti dell'installazione); oltre questi limiti la risposta è 422.

{
"items": [
{ "id": "titolo", "text": "Politica di reso" },
{ "id": "testo", "text": "Il reso è gratuito entro 30 giorni dalla consegna." }
],
"source_lang": "it",
"target_lang": "en"
}

Esempio di risposta (200 OK)

{
"items": [
{ "id": "titolo", "translated_text": "Return policy" },
{ "id": "testo", "translated_text": "Returns are free within 30 days of delivery." }
],
"provider": "openai"
}

Errori specifici

CodiceSignificato
400Lingua non gestita dal servizio di traduzione.
403Funzionalità translation non attiva (FEATURE_FLAG_DISABLED) oppure permesso translation.use non coperto dalla chiave (PERMISSION_DENIED).
422Validazione non superata oppure troppi elementi o caratteri nella richiesta batch.
429Quota di traduzione esaurita.
502Errore del servizio di traduzione.

5. Connettori MCP​

Connettori MCP (Model Context Protocol) registrati nell'organizzazione e associabili agli agenti. Permessi: admin.integrations.read per la lettura, admin.integrations.manage per le modifiche.

POST /mcp-servers​

Registra un connettore.

CampoInTipoObbligatorioDescrizione
namebodystring (1–255)SìNome del connettore.
descriptionbodystringNoDescrizione.
transportbodystringSìstreamable-http, sse oppure stdio.
urlbodystring (max 500)Per sse e streamable-httpIndirizzo del server.
command, argsbodystring, string[]Per stdioComando e argomenti.
envbodyobject (string→string)NoIntestazioni (per esempio Authorization) o variabili d'ambiente. I valori non vengono mai restituiti: le letture riportano "***".
protocol_modebodystringNoauto (predefinito), stateless oppure session: modalità del protocollo; con auto viene rilevata al primo collegamento.
curl -X POST "https://ai.askme.it/api/v2/mcp-servers" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Calendario",
"description": "Connettore per la gestione del calendario",
"transport": "streamable-http",
"url": "https://mcp.example.com/calendar",
"env": { "Authorization": "Bearer <token>" }
}'

Esempio di risposta (201 Created)

{
"id": 12,
"tenant_id": "5b0e2f7a-2c41-4d0e-9a6b-1c9e8f3d4a21",
"name": "Calendario",
"description": "Connettore per la gestione del calendario",
"transport": "streamable-http",
"command": null,
"args": null,
"url": "https://mcp.example.com/calendar",
"env": { "Authorization": "***" },
"status": "unknown",
"protocol_mode": "auto",
"detected_protocol": null,
"tools_count": 0,
"tools_cache": null,
"linked_agents_count": null,
"last_health_check": null,
"created_at": "2026-09-24T10:50:00Z",
"updated_at": "2026-09-24T10:50:00Z"
}

Altri endpoint dei connettori​

EndpointMetodoDescrizione
/mcp-serversGETElenco dei connettori (search, status, transport, offset, limit), con linked_agents_count.
/mcp-servers/{server_id}GET, PATCH, DELETEDettaglio, modifica (campi facoltativi; inviando di nuovo "***" in env il valore salvato resta invariato), eliminazione (204).
/mcp-servers/{server_id}/toolsGETStrumenti esposti dal connettore, con input_schema.
/mcp-servers/{server_id}/tools/{tool_name}PATCHAbilita o disabilita uno strumento e ne imposta l'approvazione: { "enabled": false }, { "requires_approval": true }. I campi omessi restano invariati.
/mcp-servers/{server_id}/refresh-toolsPOSTRilegge l'elenco degli strumenti dal connettore.
/mcp-servers/{server_id}/testPOSTVerifica il collegamento: { "success": bool, "message": string }.
/mcp-servers/{server_id}/callsGETRegistro delle chiamate agli strumenti: tool_name, outcome, agent_id, conversation_id, duration_ms, error_message. Filtri outcome, tool_name, ordinamento sort_by/order, paginazione.
/mcp-servers/healthGETUltimo stato noto di tutti i connettori, senza nuove verifiche.
/mcp-servers/health/refreshPOSTAvvia in background la verifica di tutti i connettori (202, { "scheduled": n, "status": "scheduled" }); lo stato aggiornato si legge poi con GET /mcp-servers/health.
/mcp-servers/{server_id}/health/refreshPOSTVerifica immediata di un singolo connettore.

6. Valutazioni e test A/B​

Endpoint per misurare la qualità degli agenti su insiemi di domande e confrontare varianti di configurazione. Richiedono le funzionalità corrispondenti del piano.

EndpointMetodoDescrizione
/evaluations/datasetsGET, POSTElenco e creazione dei dataset di valutazione.
/evaluations/datasets/{dataset_id}GET, PATCH, DELETEDettaglio, modifica, eliminazione di un dataset.
/evaluations/runPOSTAvvia una valutazione di un agente su un dataset.
/evaluations/runsGETElenco delle esecuzioni.
/evaluations/runs/{run_id}GET, DELETERisultato di un'esecuzione ed eliminazione.
/ab-experimentsGET, POSTElenco e creazione degli esperimenti A/B tra varianti di un agente.
/ab-experiments/{experiment_id}GET, DELETEDettaglio ed eliminazione.
/ab-experiments/{experiment_id}/runPOSTAvvia l'esperimento.
/ab-experiments/{experiment_id}/cancelPOSTInterrompe l'esperimento.
/ab-experiments/{experiment_id}/resultsGETRisultati aggregati.
/ab-experiments/{experiment_id}/promote/{variant}POSTApplica all'agente la configurazione della variante scelta.

7. Template di prompt​

Template di prompt riutilizzabili e versionati.

POST /prompt-templates​

CampoInTipoObbligatorioPredefinitoDescrizione
namebodystring (1–255)Sì—Nome del template.
contentbodystringSì—Testo del prompt; può contenere variabili {{variabile}}.
rolebodystringNosystemRuolo del messaggio: system, user, assistant.
descriptionbodystringNo—Descrizione.
variablesbodyarrayNo[][{ "name", "description", "default_value" }].
parent_idbodyintNo—Template genitore.
tagsbodystring[]No[]Etichette libere.
statusbodystringNodraftdraft, published, archived.

Esempio di risposta (201 Created)

{
"id": 55,
"tenant_id": "5b0e2f7a-2c41-4d0e-9a6b-1c9e8f3d4a21",
"name": "Saluto cliente",
"description": "Apertura standard delle conversazioni di supporto",
"content": "Buongiorno {{nome_cliente}}, sono l'assistente di {{azienda}}.",
"role": "system",
"variables": [
{ "name": "nome_cliente", "description": "Nome del cliente", "default_value": "" },
{ "name": "azienda", "description": "Nome dell'azienda", "default_value": "Askme" }
],
"parent_id": null,
"tags": ["benvenuto", "supporto"],
"status": "draft",
"version": 1,
"created_by": "apikey:28",
"created_at": "2026-09-24T12:00:00Z",
"updated_at": "2026-09-24T12:00:00Z"
}

Altri endpoint dei template​

EndpointMetodoDescrizione
/prompt-templatesGETElenco, con filtri parent_id, status, search, root_only e paginazione (limit massimo 200).
/prompt-templates/{template_id}GET, PUT, DELETEDettaglio, modifica (incrementa version), eliminazione (204).
/prompt-templates/{template_id}/versionsGETVersioni salvate.
/prompt-templates/{template_id}/rollback/{version_number}POSTRipristina una versione precedente.
/prompt-templates/{template_id}/childrenGETTemplate figli.
/prompt-templates/{template_id}/renderPOSTRestituisce il testo con le variabili sostituite dai valori inviati.

Pagine correlate​