Passa al contenuto principale

Endpoints

Riferimento completo delle API REST pubbliche di Askme AI.

Convenzioni generali

Base URL

Tutti gli endpoint sono prefissati da:

https://ai.askme.it/api/v2

Autenticazione

Ogni richiesta richiede due header:

HeaderValoreDescrizione
X-Api-Keyamai_<chiave>Chiave API associata al tenant. Si genera dalla console di Askme AI.
X-Source-Appuno tra askmechat, askmedesk, api_direct, askmeai, internalIdentifica l'applicazione che effettua la chiamata. Utile per la reportistica e l'attribuzione costi.

Header opzionali ma raccomandati:

HeaderTipoDescrizione
X-External-Idstring (max 255)ID opaco del tuo sistema (es. ID ticket, ID ordine). Permette di correlare conversazioni e job al tuo backend.
Idempotency-KeystringChiave di idempotenza per le operazioni POST critiche (creazione job di analisi).

Paginazione

Le liste accettano i parametri standard offset e limit (default offset=0, limit=50). La risposta è sempre nel formato:

{
"items": [ ... ],
"total": 123,
"offset": 0,
"limit": 50
}

Errori

CodiceSignificato
400 Bad RequestPayload non valido (es. campo obbligatorio mancante, valore fuori intervallo).
401 UnauthorizedX-Api-Key mancante o non valida.
403 ForbiddenLa risorsa non appartiene al tenant della chiave API.
404 Not FoundRisorsa inesistente.
409 ConflictConflitto di stato (es. associazione MCP già esistente).
413 Payload Too LargeFile caricato oltre il limite consentito dal piano.
422 Unprocessable EntityValidazione Pydantic fallita su uno o più campi del body.
429 Too Many RequestsQuota o rate-limit del piano superati.

Il corpo dell'errore segue il formato FastAPI:

{ "detail": "Agent not found" }

1. Agenti

Gestione degli agenti AI: configurazione, knowledge base associate, server MCP, prompt, modelli e politiche RAG.

POST /agents

Crea un nuovo agente nel tenant.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
namebodystring (1–255)Nome visualizzato dell'agente.
descriptionbodystringNoDescrizione libera.
model_providerbodystringNoopenaiProvider del modello. Valori: openai, anthropic, google, mistral, ollama, local.
model_namebodystring (max 100)Nogpt-4o-miniNome del modello da usare (es. gpt-4o, claude-sonnet-4-5-20250929).
system_promptbodystringNoPrompt di sistema dell'agente. Supporta variabili {{nome_var}}.
temperaturebodyfloat (0.0–2.0)No0.7Temperatura di campionamento.
max_tokensbodyint (1–128000)No2048Token massimi nella risposta.
reasoning_effortbodystringNoSolo per modelli con reasoning. Valori: minimal, low, medium, high.
tools_configbodyobjectNoConfigurazione tool (function calling, structured output).
rag_configbodyobjectNoConfigurazione RAG: retrieval_top_k, similarity_threshold, query_rewrite_mode (none/simple/multi), scope_check_enabled, disable_out_of_scope_refusal, hybrid_search, hybrid_alpha.
handoff_configbodyobjectNoConfigurazione del passaggio a operatore umano (regole di confidenza, intent).
output_schemabodyobject (JSON Schema)NoSchema JSON forzato sulla risposta del modello (structured output).
mcp_server_idsbodyint[]NonullID dei server MCP da associare. null o omesso = nessuna associazione; [] = svuota.
parent_idbodyintNoAgente genitore: il prompt di sistema effettivo è la concatenazione lungo la catena (max 10 livelli).
is_temporarybodyboolNofalseSe true, l'agente è nascosto dalle liste standard.

Esempio 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 customer care",
"description": "Risponde alle domande dei clienti su spedizioni e resi.",
"model_provider": "openai",
"model_name": "gpt-4o-mini",
"system_prompt": "Sei un assistente cortese di supporto clienti.",
"temperature": 0.4,
"max_tokens": 1024,
"mcp_server_ids": [12]
}'

Esempio risposta (201 Created)

{
"id": 87,
"tenant_id": "acme",
"name": "Assistente customer care",
"description": "Risponde alle domande dei clienti su spedizioni e resi.",
"model_provider": "openai",
"model_name": "gpt-4o-mini",
"system_prompt": "Sei un assistente cortese di supporto clienti.",
"temperature": 0.4,
"max_tokens": 1024,
"tools_config": null,
"rag_config": null,
"handoff_config": null,
"reasoning_effort": null,
"mcp_server_ids": [12],
"parent_id": null,
"is_temporary": false,
"output_schema": null,
"status": "draft",
"version": 1,
"created_by": "user-uuid",
"created_at": "2026-04-30T09:12:33Z",
"updated_at": "2026-04-30T09:12:33Z"
}

Errori specifici

CodiceSignificato
400Nome vuoto, valore di model_provider non ammesso, oppure mcp_server_ids contiene ID non appartenenti al tenant.
429Quota agents esaurita per il piano corrente.

GET /agents

Elenca gli agenti del tenant in modo paginato.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
offsetqueryint (≥0)No0Offset di paginazione.
limitqueryint (1–100)No50Numero massimo di elementi.
searchquerystringNoRicerca testuale su nome e descrizione.
statusquerystringNoFiltro stato. Valori: draft, active, paused, archived.
model_namequerystringNoFiltro per modello esatto.
include_temporaryqueryboolNofalseInclude agenti temporanei (creati da analisi PDF chat-with-doc).
sort_byquerystringNoCampo di ordinamento (name, created_at, updated_at).
orderquerystringNodescDirezione: asc o desc.

Esempio richiesta

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

Esempio risposta (200 OK)

{
"items": [
{
"id": 87,
"tenant_id": "acme",
"name": "Assistente customer care",
"model_provider": "openai",
"model_name": "gpt-4o-mini",
"status": "active",
"version": 3,
"mcp_server_ids": [12],
"created_at": "2026-04-30T09:12:33Z",
"updated_at": "2026-04-30T11:02:00Z"
}
],
"total": 1,
"offset": 0,
"limit": 20
}

GET /agents/{agent_id}

Recupera un agente specifico.

Attributi richiesta

CampoInTipoObbligatorioDescrizione
agent_idpathintIdentificativo dell'agente.

Esempio richiesta

curl "https://ai.askme.it/api/v2/agents/87" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct"

Esempio risposta (200 OK): stesso schema di POST /agents.

Errori specifici

CodiceSignificato
404Agente non trovato o appartenente ad altro tenant.

PUT /agents/{agent_id}

Aggiorna l'agente. Tutti i campi del body sono opzionali; solo i campi forniti vengono modificati. La modifica incrementa version e crea uno snapshot.

Attributi richiesta

Stessi campi di POST /agents, tutti opzionali. In più:

CampoInTipoDescrizione
statusbodystringStato dell'agente. Valori: draft, active, paused, archived.
mcp_server_idsbodyint[] | nullnull = mantiene attuali; [] = rimuove tutte; [n,m] = sostituisce esattamente con questi (semantica idempotente: il backend calcola il diff e applica add/remove).

Esempio richiesta

curl -X PUT "https://ai.askme.it/api/v2/agents/87" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Content-Type: application/json" \
-d '{
"status": "active",
"temperature": 0.2,
"mcp_server_ids": [12, 15]
}'

DELETE /agents/{agent_id}

Elimina l'agente. La quota agents viene rilasciata. Risposta 204 No Content.


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

Riporta la configurazione dell'agente a una versione precedente. Crea automaticamente una nuova entry di versione con changelog "Rollback to version N".

Attributi richiesta

CampoInTipoObbligatorioDescrizione
agent_idpathintAgente target.
version_numberpathintNumero di versione da ripristinare.

Errori specifici

CodiceSignificato
404Versione inesistente per l'agente.

GET /agents/{agent_id}/versions

Elenca le versioni archiviate della configurazione dell'agente.


Associazioni MCP per agente

Oltre al campo mcp_server_ids nei POST/PUT /agents, sono disponibili endpoint dedicati per gestire singole associazioni:

  • POST /agents/{agent_id}/mcp-servers — body { "mcp_server_id": 12 }. Risponde 201 o 409 se già associato.
  • GET /agents/{agent_id}/mcp-servers — elenco completo dei server associati con il dettaglio.
  • DELETE /agents/{agent_id}/mcp-servers/{mcp_server_id} — rimuove l'associazione (204 o 404).

2. Chat

Endpoint principale per inviare un messaggio a un agente o a un modello LLM diretto. Supporta streaming Server-Sent Events.

POST /chat

Invia un messaggio. Due modalità:

  • Modalità agente: passa agent_id. Modello, system prompt, RAG e MCP vengono dedotti dalla configurazione dell'agente.
  • Modalità diretta: ometti agent_id e fornisci model + system_prompt espliciti.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
messagebodystring (1–32000)Testo del messaggio utente.
agent_idbodyint | nullNo*nullID dell'agente. *Se omesso, sono richiesti model e system_prompt.
conversation_idbodyintNoConversazione esistente; se assente ne viene creata una nuova.
external_conversation_idbodystringNoID conversazione del tuo sistema (alternativa a conversation_id).
streambodyboolNofalseSe true la risposta è uno stream SSE.
modelbodystringNo*Solo modalità diretta (es. gpt-4o-mini).
system_promptbodystringNo*Solo modalità diretta.
temperaturebodyfloatNo(default agente)Override della temperatura.
max_tokensbodyintNo(default agente)Override del limite token.
filesbodyarrayNoAllegati: [{ filename, content_type, data }] con data base64.
include_sourcesbodyboolNotrueSe true la risposta include rag_sources.
include_hidden_sourcesbodyboolNofalseSe true include anche fonti con is_visible=false (usate ma normalmente non citate).
template_varsbodyobject (string→string)NoVariabili sostituite nel system prompt (es. {{nome_cliente}}).
classification_intentsbodyarrayNoIntent custom per la classificazione: [{ name, description }].
force_handoffbodyboolNofalseForza il passaggio a operatore umano.
skip_handoffbodyboolNofalseDisabilita la valutazione handoff per questo messaggio.
skip_scope_checkbodyboolNofalseDisabilita il controllo "fuori scope" per questo messaggio.
response_formatbodystringNomarkdownmarkdown o html.
llm_response_formatbodyobjectNoSchema JSON per structured output one-shot.
metadatabodyobjectNoMetadati liberi propagati nel record di costo.
mcp_authbodyobject (string→string)NoToken utente per MCP che richiedono auth (passati come header per quel MCP).
tool_approvalbodyobjectNoRisposta a un'approvazione di tool: { approved: bool, pending_message_id: int }.
external_idbodystring (max 255)NoOverride dell'header X-External-Id a livello di richiesta.
source_appbodystring (max 50)NoOverride dell'header X-Source-App a livello di richiesta.
X-External-IdheaderstringNoID esterno per il record di costo e attribuzione.

Esempio richiesta (non-streaming)

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: ordine-7728" \
-H "Content-Type: application/json" \
-d '{
"agent_id": 87,
"message": "Quali sono i tempi medi di consegna in Italia?",
"stream": false
}'

Esempio risposta (200 OK, non-streaming)

{
"message_id": 5512,
"conversation_id": 4421,
"external_conversation_id": null,
"content": "I tempi medi di consegna in Italia sono compresi tra 24 e 72 ore lavorative ...",
"thinking_content": null,
"content_format": "markdown",
"role": "assistant",
"model_used": "gpt-4o-mini",
"tokens_input": 412,
"tokens_output": 88,
"latency_ms": 1430,
"rag_sources": [
{
"document_id": "117",
"chunk_id": "chunk-117-3",
"title": "Politica spedizioni",
"content_preview": "Le spedizioni standard partono entro 24 ore lavorative ...",
"relevance_score": 0.83,
"metadata": { "page": 2 },
"is_visible": true
}
],
"confidence_score": 0.91,
"needs_review": false,
"handoff_requested": false,
"handoff_reason": null,
"intent": "delivery_info",
"sentiment": "neutral",
"is_in_scope": true,
"tool_calls_count": 0,
"tools_used": [],
"pending_tool_approval": false,
"created_at": "2026-04-30T11:22:14Z"
}

Risposta in streaming (SSE)

Quando stream: true, il server risponde con Content-Type: text/event-stream. Ogni evento ha la forma:

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

Tipi di evento emessi (campo type):

TipoDescrizioneCampi principali
rag_thinkingStatus testuale durante la fase RAG (es. "ricerca documenti…").content
thinkingToken del ragionamento interno (per modelli con reasoning).content
delta / contentToken incrementale della risposta.content
sourcesLista delle fonti RAG individuate.sources[]
tool_callIl modello sta invocando un tool MCP.tool_name, tool_args
tool_approval_requiredTool che richiede approvazione esplicita.pending_tool_calls[], pending_message_id
confidenceConfidence score consolidato.confidence_score, confidence_signals, needs_review
handoff_decisionDecisione di handoff verso operatore umano.handoff_requested, handoff_reason, handoff_trigger
usageBilancio finale token + metadati turn.usage.{message_id,conversation_id,model_used,tokens_input,tokens_output,latency_ms,…}
doneMarker di fine stream.
errorErrore in corso di stream.error, code

Esempio di stream (estratto):

data: {"type":"rag_thinking","content":"Cerco nelle fonti..."}

data: {"type":"sources","sources":[{"document_id":"117","relevance_score":0.83,...}]}

data: {"type":"delta","content":"I tempi"}

data: {"type":"delta","content":" medi di consegna"}

data: {"type":"confidence","confidence_score":0.91,"needs_review":false}

data: {"type":"usage","usage":{"message_id":5512,"conversation_id":4421,"model_used":"gpt-4o-mini","tokens_input":412,"tokens_output":88,"latency_ms":1430}}

data: {"type":"done"}

Errori specifici

CodiceSignificato
400agent_id mancante senza model/system_prompt; message vuoto o oltre 32000 caratteri.
404Agente o conversazione non trovati.
429Quota messaggi del piano esaurita.

3. Conversazioni

Storico, lookup tramite ID esterno, feedback sui messaggi.

GET /conversations

Elenca le conversazioni dell'utente corrente.

Attributi richiesta

CampoInTipoDefaultDescrizione
offsetqueryint0Paginazione.
limitqueryint (1–100)50Page size.

Esempio risposta (200 OK)

{
"items": [
{
"id": 4421,
"tenant_id": "acme",
"agent_id": 87,
"agent_name": "Assistente customer care",
"user_id": "user-uuid",
"title": "Domanda spedizioni",
"status": "active",
"message_count": 6,
"external_id": "ordine-7728",
"created_at": "2026-04-30T11:20:00Z",
"updated_at": "2026-04-30T11:24:10Z"
}
],
"total": 1,
"offset": 0,
"limit": 50
}

GET /conversations/monitoring

Vista monitoring: tutte le conversazioni del tenant (richiede permessi adeguati). Supporta filtri estesi.

Attributi richiesta

CampoInTipoDescrizione
offset, limitqueryintPaginazione standard.
statusquerystringFiltra per stato (active, closed, archived).
agent_idqueryintFiltra per agente.
date_fromquerydatetime ISO 8601Dalla data inclusa.
date_toquerydatetime ISO 8601Fino alla data inclusa.

GET /conversations/{conversation_id}

Dettaglio di una conversazione (senza messaggi).

Esempio risposta (200 OK)

{
"id": 4421,
"tenant_id": "acme",
"agent_id": 87,
"user_id": "user-uuid",
"title": "Domanda spedizioni",
"status": "active",
"metadata": null,
"external_id": "ordine-7728",
"insights": null,
"created_at": "2026-04-30T11:20:00Z",
"updated_at": "2026-04-30T11:24:10Z"
}

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

Recupera la conversazione tramite l'ID esterno fornito al primo POST /chat. Utile per riprendere una sessione lato tuo backend senza tenere traccia di conversation_id interni.

Attributi richiesta

CampoInTipoDescrizione
external_idpathstringID opaco fornito alla creazione.
agent_idqueryint(opzionale) limita la ricerca a un singolo agente, utile se lo stesso external_id è stato usato con più agenti.

Errori specifici

CodiceSignificato
404Nessuna conversazione corrisponde all'external_id per il tenant.

GET /conversations/{conversation_id}/messages

Recupera i messaggi della conversazione.

Attributi richiesta

CampoInTipoDefaultDescrizione
conversation_idpathintConversazione target.
offsetqueryint0Paginazione.
limitqueryint (1–500)100Page size.

Esempio risposta (200 OK)

{
"items": [
{
"id": 5511,
"conversation_id": 4421,
"role": "user",
"content": "Quali sono i tempi medi di consegna in Italia?",
"created_at": "2026-04-30T11:22:00Z"
},
{
"id": 5512,
"conversation_id": 4421,
"role": "assistant",
"content": "I tempi medi di consegna ...",
"tokens_input": 412,
"tokens_output": 88,
"model_used": "gpt-4o-mini",
"created_at": "2026-04-30T11:22:14Z"
}
],
"total": 2,
"offset": 0,
"limit": 100
}

PUT /conversations/{conversation_id}

Aggiorna titolo o stato della conversazione (anche PATCH).

Attributi richiesta

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

DELETE /conversations/{conversation_id}

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


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

Registra il feedback dell'utente finale su una risposta dell'assistente.

Attributi richiesta

CampoInTipoObbligatorioDescrizione
ratingbodystringpositive o negative.
commentbodystringNoCommento testuale.

Esempio risposta (200 OK)

{ "message_id": 5512, "rating": "positive", "comment": "Risposta chiara." }

4. Knowledge Base

Knowledge base, documenti, FAQ, scraping web e sorgenti DB.

POST /knowledge-bases

Crea una nuova knowledge base.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
namebodystring (1–255)Nome KB.
descriptionbodystringNoDescrizione libera.
typebodystringNomanualmanual, scraping, db, mixed.
embedding_modelbodystringNotext-embedding-3-smallModello di embedding. Per modelli Mistral è obbligatorio configurare vector_store_config su Qdrant a 1024 dimensioni.
chunk_strategybodystringNorecursiveStrategia di chunking.
chunk_sizebodyint (100–4000)No512Dimensione chunk in caratteri.
chunk_overlapbodyint (0–1000)No50Sovrapposizione tra chunk.
languagesbodystring[]No["it"]Codici lingua ISO 639-1. Le query in lingue fuori da questo set sono auto-tradotte alla prima lingua dell'array.
parent_idbodyintNoKB genitore (per gerarchie).
is_temporarybodyboolNofalseKB nascosta dalle liste standard.
vector_store_configbodyobjectNopgvector{ "provider": "pgvector", "dimensions": 1536 } oppure { "provider": "qdrant", "url": "...", "collection_name": "...", "dimensions": 1536 }.
configbodyobjectNoConfigurazione RAG di default per la KB (override possibile a livello agente). Vedi i campi rag_config documentati nell'endpoint agenti.

Esempio richiesta

curl -X POST "https://ai.askme.it/api/v2/knowledge-bases" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Content-Type: application/json" \
-d '{
"name": "Manuali tecnici",
"description": "Documentazione prodotto",
"type": "manual",
"languages": ["it", "en"],
"chunk_size": 800,
"chunk_overlap": 100
}'

Esempio risposta (201 Created)

{
"id": 24,
"tenant_id": "acme",
"name": "Manuali tecnici",
"description": "Documentazione prodotto",
"type": "manual",
"embedding_model": "text-embedding-3-small",
"chunk_strategy": "recursive",
"chunk_size": 800,
"chunk_overlap": 100,
"config": {},
"vector_store_config": null,
"status": "active",
"document_count": 0,
"total_chunks": 0,
"languages": ["it", "en"],
"is_temporary": false,
"parent_id": null,
"created_by": "user-uuid",
"created_at": "2026-04-30T09:00:00Z",
"updated_at": "2026-04-30T09:00:00Z"
}

GET /knowledge-bases

Elenca le knowledge base del tenant.

Attributi richiesta

CampoInTipoDefaultDescrizione
offsetqueryint0Paginazione.
limitqueryint (1–100)50Page size.
searchquerystringRicerca su nome/descrizione.
statusquerystringFiltro stato.
sort_byquerystringCampo di ordinamento.
orderquerystringasc o desc.
include_temporaryqueryboolfalseInclude KB temporanee (es. quelle create da analisi PDF chat-with-doc).

GET /knowledge-bases/{kb_id}

Dettaglio della KB.

PATCH /knowledge-bases/{kb_id}

Aggiorna la KB (campi opzionali: name, description, status, chunk_strategy, chunk_size, chunk_overlap, config, parent_id, languages). Il vector_store_config non è modificabile dopo la creazione.

DELETE /knowledge-bases/{kb_id}

Elimina la KB, i documenti e i chunk associati. Rilascia la quota knowledge_bases. Risposta 204 No Content.


GET /knowledge-bases/{kb_id}/quality-metrics

Metriche strutturali della KB (numero documenti, distribuzione chunk, pagine scrapate, ecc.). Nessuna chiamata LLM.

Esempio risposta (200 OK)

{
"total_documents": 38,
"indexed_documents": 36,
"pending_documents": 1,
"error_documents": 1,
"doc_status_breakdown": { "indexed": 36, "pending": 1, "error": 1 },
"source_type_breakdown": { "file": 20, "url": 15, "text": 3 },
"total_chunks": 1240,
"avg_chunk_tokens": 380.4,
"min_chunk_tokens": 120,
"max_chunk_tokens": 510,
"docs_with_empty_chunks": 0,
"scraping_jobs_count": 2
}

GET /knowledge-bases/{kb_id}/export

Esporta la KB come archivio ZIP (streaming application/zip).


Documenti — /knowledge-bases/{kb_id}/documents

POST /knowledge-bases/{kb_id}/documents/upload

Carica un file (multipart). Tipi supportati: PDF, DOCX, TXT, MD, HTML, CSV, XLSX, JSON.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
fileform-datafileIl file da caricare.
priorityform-dataintNo2Priorità di elaborazione.
categoryform-datastringNoEtichetta libera.
languageform-datastringNoCodice lingua.

Esempio richiesta

curl -X POST "https://ai.askme.it/api/v2/knowledge-bases/24/documents/upload" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-F "[email protected]" \
-F "priority=1" \
-F "language=it"

Esempio risposta (201 Created)

{
"id": 711,
"knowledge_base_id": 24,
"title": "manuale.pdf",
"source_type": "file",
"source_url": null,
"file_path": "tenant/acme/kb/24/manuale.pdf",
"mime_type": "application/pdf",
"status": "processing",
"file_size": 2148572,
"chunk_count": 0,
"metadata": null,
"error_message": null,
"created_at": "2026-04-30T09:30:00Z",
"updated_at": "2026-04-30T09:30:00Z",
"priority": 1,
"is_visible": true
}

Errori specifici

CodiceSignificato
413File oltre il limite del piano (file_upload_size_mb).

POST /knowledge-bases/{kb_id}/documents/text

Crea un documento da testo grezzo.

Attributi richiesta

CampoInTipoObbligatorioDescrizione
titlebodystring (1–500)Titolo del documento.
contentbodystring (≥1)Contenuto testuale.
metadatabodyobjectNoMetadati liberi.

GET /knowledge-bases/{kb_id}/documents

Elenca i documenti della KB. Parametri standard di paginazione offset/limit.

GET /knowledge-bases/{kb_id}/documents/{document_id}/preview

Anteprima testuale del documento.

GET /knowledge-bases/{kb_id}/documents/{document_id}/download

Download del file originale.

DELETE /knowledge-bases/{kb_id}/documents/{document_id}

Elimina il documento e i suoi chunk. Risposta 204.

DELETE /knowledge-bases/{kb_id}/documents/bulk

Eliminazione multipla. Body: { "ids": [711, 712, 713] }.

PATCH /knowledge-bases/{kb_id}/documents/{document_id}/visibility

Mostra/nasconde il documento come fonte citata. Quando is_visible=false, il contenuto è ancora usato per il contesto RAG ma il documento non appare nelle citazioni della risposta.

Attributi richiesta

CampoInTipoObbligatorioDescrizione
is_visiblebodybooltrue per rendere visibile, false per nascondere.

FAQ — /knowledge-bases/{kb_id}/faqs

POST /knowledge-bases/{kb_id}/faqs

Crea una FAQ.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
questionbodystring (max 500)Domanda canonica.
answerbodystring (max 5000)Risposta.
categorybodystring (max 255)NoCategoria.
prioritybodyintNo2Priorità nel ranking.
variantsbodystring[]No[]Riformulazioni alternative della domanda.
editorial_statusbodystringNodraftStato editoriale (draft, published, ecc.).

Esempio risposta (201 Created)

{
"id": 401,
"knowledge_base_id": 24,
"question": "Quali sono i tempi di consegna?",
"answer": "Le consegne avvengono entro 24-72 ore lavorative.",
"category": "spedizioni",
"priority": 1,
"variants": ["Quando arriva il pacco?", "Tempi di spedizione?"],
"editorial_status": "published",
"is_visible": true,
"created_at": "2026-04-30T10:00:00Z",
"updated_at": "2026-04-30T10:00:00Z"
}

GET /knowledge-bases/{kb_id}/faqs

Lista paginata delle FAQ.

PUT /knowledge-bases/{kb_id}/faqs/{faq_id}

Aggiornamento completo. Stessi campi di POST (tutti opzionali tranne question e answer).

DELETE /knowledge-bases/{kb_id}/faqs/{faq_id}

Eliminazione (204).

PATCH /knowledge-bases/{kb_id}/faqs/{faq_id}/visibility

Body: { "is_visible": true }. Stessa semantica di documents/{id}/visibility.

POST /knowledge-bases/{kb_id}/faqs/import

Import massivo da file CSV o JSON (multipart [email protected]). Restituisce { "imported": <int> }.


Scraping web — /knowledge-bases/{kb_id}/scraping-jobs

Riconosce automaticamente sitemap XML e feed RSS/Atom (estensioni .rss, .atom, /feed, content-type application/rss+xml, application/atom+xml).

POST /knowledge-bases/{kb_id}/scraping-jobs

Crea un job di scraping.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
urlbodystringURL di partenza. Può essere una pagina, una sitemap o un feed RSS/Atom.
depthbodyint (1–5)No1Profondità del crawl.
schedule_cronbodystringNoCron expression per esecuzione ricorrente.
configbodyobjectNoOpzioni avanzate (selettori CSS, esclusioni, ecc.).

Esempio risposta (201 Created)

{
"id": 33,
"knowledge_base_id": 24,
"url": "https://example.com/sitemap.xml",
"status": "pending",
"depth": 1,
"pages_scraped": 0,
"pages_discovered": 0,
"last_run_at": null,
"schedule_cron": null,
"trigger": "manual",
"config": null,
"error_message": null,
"created_at": "2026-04-30T10:30:00Z",
"updated_at": "2026-04-30T10:30:00Z"
}

GET /knowledge-bases/{kb_id}/scraping-jobs

Elenco dei job.

POST /knowledge-bases/{kb_id}/scraping-jobs/{job_id}/discover

Avvia la fase di discovery (sitemap + crawl) senza scaricare le pagine. Restituisce contatori sitemap_urls_count, crawl_urls_count.

GET /knowledge-bases/{kb_id}/scraping-jobs/{job_id}/discovered-pages

Pagine trovate, paginabili. Ogni pagina ha selected: bool e status (pending, scraped, skipped, error).

PATCH /knowledge-bases/{kb_id}/scraping-jobs/{job_id}/discovered-pages/selection

Seleziona/deseleziona pagine prima dello scraping vero e proprio.

Attributi richiesta

CampoInTipoDescrizione
page_idsbodyint[]ID specifici da modificare.
selectedbodyboolNuovo stato.
select_allbodyboolSe true ignora page_ids e applica a tutte.
filter_sourcebodystringsitemap o crawl per filtrare.

POST /knowledge-bases/{kb_id}/scraping-jobs/{job_id}/trigger

Esegue lo scraping delle pagine selezionate. Risposta 202 Accepted.

GET /knowledge-bases/{kb_id}/scraping-jobs/{job_id}/progress

Stato di avanzamento in tempo reale del job.

DELETE /knowledge-bases/{kb_id}/scraping-jobs/{job_id}

Elimina il job (204). Per eliminazione massiva: DELETE .../scraping-jobs/bulk con body { "ids": [...] }.


Sorgenti database — /knowledge-bases/{kb_id}/db-source

PUT /knowledge-bases/{kb_id}/db-source

Crea o aggiorna la configurazione di una sorgente DB (un solo connettore per KB).

Attributi richiesta

CampoInTipoObbligatorioDescrizione
connection_typebodystringpostgresql, mysql, mssql.
namebodystringNoNome del connettore.
hostbodystringHost del DB.
portbodyint (1–65535)Porta.
databasebodystringNome del database.
usernamebodystringUtente.
passwordbodystringNoPassword. Cifrata at-rest.
schemabodystringNoNome dello schema (PostgreSQL/MSSQL).
tablebodystringNoTabella sorgente (alternativa a query).
querybodystringNoQuery SQL custom (alternativa a table).
sync_interval_minutesbodyint (≥1)NoIntervallo di sync in minuti. Convertito internamente in cron.

POST /knowledge-bases/{kb_id}/db-source/test

Verifica la connessione senza salvarla. Stessi campi di PUT esclusi gli attributi di sync. Risponde { "success": true|false, "message": "..." }.

GET /knowledge-bases/{kb_id}/db-source/preview

Anteprima di poche righe dalla sorgente configurata. Risposta:

{
"rows": [
{ "id": 1, "title": "...", "content": "..." }
],
"columns": ["id", "title", "content"]
}

POST /knowledge-bases/{kb_id}/db-source/run

Avvia un'estrazione manuale. Risposta:

{
"documents_created": 124,
"rows_processed": 124,
"message": "Estrazione completata."
}

GET /knowledge-bases/{kb_id}/db-source/{connector_id}/runs

Storico esecuzioni (started_at, completed_at, rows_extracted, chunks_created, error_message).

DELETE /knowledge-bases/{kb_id}/db-source/{connector_id}/runs

Pulisce lo storico esecuzioni del connettore (204).

DELETE /knowledge-bases/{kb_id}/db-source/{connector_id}

Elimina la sorgente DB (204).


POST /search

Ricerca ibrida (vettoriale + BM25 + RRF + FAQ) su una o più KB.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
querybodystring (1–2000)Testo della query.
knowledge_base_idsbodyint[]Almeno una KB.
top_kbodyint (1–100)No10Numero di risultati.
min_scorebodyfloat (0.0–1.0)No0.0Soglia minima di rilevanza.
use_rerankingbodyboolNofalseAbilita il reranker (cross-encoder o Cohere).
enable_bm25bodyboolNotrueIncludi BM25 nella fusione RRF.

Esempio richiesta

curl -X POST "https://ai.askme.it/api/v2/search" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Content-Type: application/json" \
-d '{
"query": "tempi medi consegna Italia",
"knowledge_base_ids": [24],
"top_k": 5,
"use_reranking": true
}'

Esempio risposta (200 OK)

{
"query": "tempi medi consegna Italia",
"chunks": [
{
"id": "chunk-117-3",
"document_id": 117,
"knowledge_base_id": 24,
"content": "Le spedizioni standard partono entro 24 ore lavorative ...",
"score": 0.83,
"metadata": { "page": 2 }
}
],
"faqs": [
{
"id": 401,
"knowledge_base_id": 24,
"question": "Quali sono i tempi di consegna?",
"answer": "Le consegne avvengono entro 24-72 ore lavorative.",
"score": 0.92,
"is_visible": true
}
],
"total_results": 6,
"search_time_ms": 132.4
}

Endpoint atomici

Stesso DTO di /search. Differiscono per la strategia retrieval, utili in pipeline di fan-out:

  • POST /search/advanced — ricerca con filtri estesi e reranking. Accetta ?document_ids=... (lista) come query string.
  • POST /search/vector — solo retrieval vettoriale puro (no BM25, no rerank, no fusion).
  • POST /search/fulltext — solo BM25 / Postgres FTS (KB con vector store esterno solamente vengono ignorate).
  • POST /search/faq — solo FAQ matching (vettoriale + opzionale BM25 con RRF). I risultati sono nel campo faqs; chunks è sempre vuoto.

5. Server MCP

Server MCP (Model Context Protocol) registrati a livello tenant e associabili agli agenti.

POST /mcp-servers

Registra un nuovo server MCP.

Attributi richiesta

CampoInTipoObbligatorioDescrizione
namebodystring (1–255)Nome visualizzato.
descriptionbodystringNoDescrizione libera.
transportbodystringTrasporto. Valori: stdio, sse, streamable-http.
commandbodystring (max 500)Solo per stdioComando eseguibile.
argsbodystring[]NoArgomenti del comando.
urlbodystring (max 500)Solo per sse/streamable-httpURL del server.
envbodyobject (string→string)NoVariabili ambiente (per stdio) o header custom.

Esempio richiesta

curl -X POST "https://ai.askme.it/api/v2/mcp-servers" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Content-Type: application/json" \
-d '{
"name": "Calendar MCP",
"description": "Server MCP per gestione calendario",
"transport": "streamable-http",
"url": "https://mcp.example.com/calendar",
"env": { "Authorization": "Bearer ..." }
}'

Esempio risposta (201 Created)

{
"id": 12,
"tenant_id": "acme",
"name": "Calendar MCP",
"description": "Server MCP per gestione calendario",
"transport": "streamable-http",
"command": null,
"args": null,
"url": "https://mcp.example.com/calendar",
"env": { "Authorization": "Bearer ..." },
"status": "unknown",
"tools_count": 0,
"tools_cache": null,
"last_health_check": null,
"created_at": "2026-04-30T10:50:00Z",
"updated_at": "2026-04-30T10:50:00Z"
}

Errori specifici

CodiceSignificato
400Validazione fallita (es. transport=sse senza url, transport=stdio senza command).

GET /mcp-servers

Elenca i server MCP del tenant. Filtri: search, status, transport, oltre a offset/limit.

GET /mcp-servers/{server_id}

Dettaglio + cache dei tool.

PATCH /mcp-servers/{server_id}

Aggiorna il server (campi opzionali). Stessi vincoli di trasporto.

DELETE /mcp-servers/{server_id}

Elimina il server (204).


GET /mcp-servers/{server_id}/tools

Restituisce i tool esposti dal server, con relativo input_schema (JSON Schema).

POST /mcp-servers/{server_id}/refresh-tools

Forza il refresh della cache tool dal server. Restituisce conteggio e lista aggiornata.

POST /mcp-servers/{server_id}/test

Esegue un test di connessione live. Risposta { "success": bool, "message": string }.


Health

Lo stato status del server è cacheato in DB. Le chiamate di health probano i server in tempo reale e persistono il risultato.

GET /mcp-servers/health

Stato cacheato di tutti i server (nessuna probe). Restituisce un array di McpServerResponse.

POST /mcp-servers/health/refresh

Probe live in parallelo di tutti i server e persiste i risultati.

POST /mcp-servers/{server_id}/health/refresh

Probe live di un singolo server.


6. Analisi

Job di analisi orchestrati: contenuto testuale, PDF, CV, dati strutturati, classificazione, OCR.

Modello di esecuzione: ogni POST /analysis/<tipo> accetta il body, restituisce 202 Accepted con un job in stato pending e schedula l'elaborazione asincrona. Si interroga poi GET /analysis/{id} per ottenere il risultato. Per i tipi che lo supportano sono disponibili anche le varianti /sync che attendono il completamento (200 OK).

Header opzionale Idempotency-Key: se ripetuto entro la finestra di idempotenza, restituisce lo stesso job invece di crearne uno nuovo.

Opzioni comuni (options)

Tutti i body POST espongono un campo opzionale options:

CampoTipoDefaultDescrizione
modelstringOverride del modello LLM (es. claude-haiku-4-5-20251001).
temperaturefloat (0.0–2.0)Sampling temperature.
max_tokensint (1–128000)Limite token risposta.
languagestringHint lingua (it, en, ecc.).
output_formatstringjsonjson, html, markdown.
guardrailsboolfalseAbilita controlli PII/injection/toxicity.
confidence_checkboolfalseAbilita validazione qualità risultato.
webhook_idintWebhook (registrato con /webhooks) da notificare a fine job.

Inoltre tutti i body accettano:

CampoTipoDescrizione
template_idintID di un template di analisi: il suo input_config viene fuso col body.
namestring (max 255)Nome visualizzato del job.

POST /analysis/content

Analisi testuale generica (sentiment, entità, parole chiave, riassunto).

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
textbodystring (1–200000)Testo da analizzare.
custom_instructionsbodystring (max 4000)NoIstruzioni aggiuntive per il prompt.
max_charsbodyint (100–200000)No20000Troncamento prima dell'invio al modello.
template_id, name, optionsbodyNo(vedi sopra).

Esempio richiesta

curl -X POST "https://ai.askme.it/api/v2/analysis/content" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Idempotency-Key: 2c9e5c0e-..." \
-H "Content-Type: application/json" \
-d '{
"name": "Analisi recensione",
"text": "Il prodotto è arrivato con un giorno di ritardo ma il servizio clienti è stato ottimo.",
"options": { "language": "it" }
}'

Esempio risposta (202 Accepted)

{
"id": 88102,
"tenant_id": "acme",
"type": "content",
"status": "pending",
"input_config": {
"name": "Analisi recensione",
"text": "Il prodotto è arrivato con un giorno di ritardo...",
"max_chars": 20000,
"source_app": "api_direct"
},
"result": null,
"error_message": null,
"created_by": "user-uuid",
"started_at": null,
"completed_at": null,
"created_at": "2026-04-30T11:00:00Z"
}

L'endpoint POST /analysis/content/sync ha lo stesso body ma attende il completamento e risponde 200 OK col result popolato.


POST /analysis/pdf

Analisi di un documento PDF tramite LLM. Opzionalmente crea una KB temporanea + agente per la modalità chat-with-doc.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
filenamebodystring (max 512)Nome del file (determina nome KB/agente).
file_contentbodystring base64Sì*Contenuto PDF in base64. *Esattamente uno tra file_content e file_path.
file_pathbodystringSì*Path su object storage di un file già caricato.
custom_promptbodystring (max 8000)NoIstruzioni libere per l'analisi.
agent_idbodyintNoAgente di fallback per il prompt.
temp_agent_namebodystring (max 512)NoNome dell'agente temporaneo (richiesto in alcune lingue).
create_kb_agentbodyboolNofalseSe true, crea KB+agente temporanei con il documento per la chat.
skip_analysisbodyboolNofalseSalta lo step di analisi LLM e crea solo KB+agente. Richiede create_kb_agent=true.
template_id, name, optionsbodyNo(vedi sopra).

Esempio risposta (202 Accepted)

{
"id": 88103,
"tenant_id": "acme",
"type": "pdf",
"status": "pending",
"input_config": {
"filename": "policy.pdf",
"create_kb_agent": true,
"skip_analysis": false,
"source_app": "api_direct"
},
"result": null,
"created_at": "2026-04-30T11:05:00Z"
}

Errori specifici

CodiceSignificato
422file_contentfile_path forniti, oppure entrambi; oppure skip_analysis=true senza create_kb_agent=true.

L'endpoint /pdf/sync esegue sincrono.


POST /analysis/cv

Scoring di un CV contro le job position configurate dal tenant.

Attributi richiesta

CampoInTipoObbligatorioDescrizione
file_contentbodystring base64CV (PDF o DOCX) in base64.
filenamebodystring (max 512)Nome file con estensione (determina parser).
job_position_idbodyintNoLimita lo scoring a una posizione. Se omesso, valuta contro tutte le posizioni del tenant.
cv_prompt_idbodyintNoOverride del prompt CV. Default: prompt configurato dal tenant.
template_id, name, optionsbodyNo(vedi sopra).

L'endpoint /cv/sync esegue sincrono.


POST /analysis/data

Analisi su dati tabellari (CSV/XLSX letti come lista di dict).

Attributi richiesta

CampoInTipoObbligatorioDescrizione
databodyobject[] (1–10000)Righe come { colonna: valore }.
columnsbodystring[]NoSottoinsieme di colonne da analizzare (default: tutte).
custom_promptbodystring (max 4000)NoIstruzioni LLM aggiuntive.
agent_idbodyintNoAgente di fallback per il prompt.
template_id, name, optionsbodyNo(vedi sopra).

7. Classificazione (catalogo Similarity)

La classificazione di testi avviene attraverso il catalogo Similarity: si costruisce un indice a partire da esempi (con o senza etichette) e poi si classificano nuovi testi rispetto a quell'indice. Tutti gli endpoint sono prefissati da /api/v2/analysis/catalogs.

POST /analysis/catalogs/build

Avvia la build di un catalogo. Risposta 202 Accepted: la build è asincrona, polling sullo stato del catalogo.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
namebodystring (1–100)Nome del catalogo.
modebodystringsupervised (richiede label_path su almeno una coppia) o unsupervised.
thresholdbodyfloat (0.0–1.0)No0.6Soglia minima di similarità per accettare un candidato.
pairsbodyobject[]Lista non vuota di coppie. Ogni elemento: ticket (string, obbligatorio), response (string), label_path (string[]).

Esempio richiesta (supervisionato)

curl -X POST "https://ai.askme.it/api/v2/analysis/catalogs/build" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Content-Type: application/json" \
-d '{
"name": "Triage richieste clienti",
"mode": "supervised",
"threshold": 0.6,
"pairs": [
{ "ticket": "Vorrei sapere quando arriva il pacco", "label_path": ["spedizione"] },
{ "ticket": "Il prodotto è arrivato rotto", "label_path": ["reso"] },
{ "ticket": "Posso modificare l'\''indirizzo di consegna?", "label_path": ["modifica ordine"] }
]
}'

Esempio risposta (202 Accepted)

{
"id": 14,
"tenant_id": "c9fe50b1-be08-...",
"name": "Triage richieste clienti",
"mode": "supervised",
"status": "queued",
"refinement_status": "templates_refined",
"embedding_model": "text-embedding-3-small",
"threshold": 0.6,
"template_count": 0,
"created_by": "...",
"created_at": "2026-04-30T12:00:00Z"
}

Errori specifici

CodiceSignificato
400pairs vuoto; oppure mode=supervised senza alcuna coppia con label_path.

GET /analysis/catalogs

Lista paginata dei cataloghi del tenant.

Query

CampoTipoDefaultDescrizione
offsetint0Indice del primo elemento.
limitint (1–200)50Numero di elementi.
statusstringFiltro per stato: queued, building, ready, failed, cancelled.
modestringsupervised o unsupervised.

GET /analysis/catalogs/{catalog_id}

Dettaglio del catalogo, inclusa la lista dei templates (esempi rappresentativi). Da usare per esplorare i cluster nei cataloghi non supervisionati o le etichette in quelli supervisionati.


DELETE /analysis/catalogs/{catalog_id}

Elimina il catalogo. Può essere invocata anche su un catalogo in stato building: la cancellazione interrompe la build.


POST /analysis/catalogs/classify

Classifica uno o più testi rispetto a un catalogo ready e restituisce i candidati top-N con punteggio di similarità.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
catalog_idbodyintID del catalogo.
textsbodystring[]Testi da classificare.
top_nbodyint (1–10)No3Numero di candidati per testo.
threshold_overridebodyfloat (0.0–1.0)NoSovrascrive la soglia del catalogo per questa chiamata.

Esempio richiesta

curl -X POST "https://ai.askme.it/api/v2/analysis/catalogs/classify" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-H "Content-Type: application/json" \
-d '{
"catalog_id": 14,
"texts": ["Quando arriva il mio ordine?", "L'\''articolo che ho ricevuto è difettoso"],
"top_n": 3
}'

Esempio risposta

{
"catalog_id": 14,
"catalog_name": "Triage richieste clienti",
"catalog_mode": "supervised",
"refinement_status": "templates_refined",
"total_texts": 2,
"processing_time_seconds": 0.42,
"threshold_used": 0.6,
"top_n": 3,
"results": [
{
"text": "Quando arriva il mio ordine?",
"candidates": [
{ "label_path": ["spedizione"], "similarity": 0.91, "template_id": 22, "template_text": "Vorrei sapere quando arriva il pacco" }
],
"best_label_path": ["spedizione"],
"best_similarity": 0.91,
"verdict": "strong"
}
],
"distribution": { "spedizione": 1, "reso": 1 }
}

verdict è uno di strong, medium, weak, none ed è calcolato sul punteggio del primo candidato e sul delta col secondo.


GET /analysis/catalogs/queue-status

Stato della coda di build (depth, in-flight, dead-letter).


POST /analysis/catalogs/{catalog_id}/requeue

Rilancia un catalogo in stato failed o cancelled.


POST /analysis/catalogs/{catalog_id}/refine-labels

Affina i nomi dei cluster (solo cataloghi non supervisionati) con un passaggio LLM.


POST /analysis/catalogs/{catalog_id}/refine-templates

Seleziona i template più rappresentativi per ciascun cluster.


PATCH /analysis/catalogs/{catalog_id}/templates/{template_id}

Modifica manualmente testo o label_path di un singolo template.

Body

CampoTipoDescrizione
textstringNuovo testo del template.
label_pathstring[]Nuova etichetta.

DELETE /analysis/catalogs/{catalog_id}/templates/{template_id}

Rimuove un template dal catalogo.


POST /analysis/ocr

Estrazione di testo da immagini o PDF scansionati. Multipart/form-data (non JSON).

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
fileform-datafileImmagine o PDF (max 50 MB).
languageform-datastringNoitaLingua Tesseract: ita, eng, fra, deu, spa.
template_idform-dataintNoTemplate OCR.
webhook_idform-dataintNoWebhook di notifica a completamento.

Esempio richiesta

curl -X POST "https://ai.askme.it/api/v2/analysis/ocr" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
-F "[email protected]" \
-F "language=ita"

Errori specifici

CodiceSignificato
400Tipo MIME non supportato o file vuoto.
413File oltre 50 MB.

GET /analysis

Elenca i job di analisi del tenant.

Attributi richiesta

CampoInTipoDefaultDescrizione
offsetqueryint0Paginazione.
limitqueryint (1–200)50Page size.
statusquerystringpending, running, completed, failed.
typequerystringcontent, pdf, cv, data, ocr.

Esempio risposta (200 OK)

{
"items": [
{
"id": 88102,
"tenant_id": "acme",
"type": "content",
"status": "completed",
"input_config": { "name": "Analisi recensione", "source_app": "api_direct" },
"error_message": null,
"created_by": "user-uuid",
"started_at": "2026-04-30T11:00:01Z",
"completed_at": "2026-04-30T11:00:08Z",
"created_at": "2026-04-30T11:00:00Z"
}
],
"total": 1,
"offset": 0,
"limit": 50
}

GET /analysis/{analysis_id}

Dettaglio del job, incluso result (struttura specifica per tipo).

Esempio risposta (200 OK, content analysis completata)

{
"id": 88102,
"tenant_id": "acme",
"type": "content",
"status": "completed",
"input_config": { "text": "...", "source_app": "api_direct" },
"result": {
"summary": "Il cliente segnala un ritardo ma riconosce la qualità del servizio.",
"sentiment": { "label": "neutral", "score": 0.62 },
"keywords": ["ritardo", "servizio clienti"],
"entities": [{ "text": "servizio clienti", "type": "department" }],
"language": "it"
},
"error_message": null,
"started_at": "2026-04-30T11:00:01Z",
"completed_at": "2026-04-30T11:00:08Z",
"created_at": "2026-04-30T11:00:00Z"
}

GET /analysis/{analysis_id}/status

Solo lo stato del job (no result). Adatto al polling frequente.

Esempio risposta (200 OK)

{
"id": 88102,
"type": "content",
"status": "running",
"started_at": "2026-04-30T11:00:01Z",
"completed_at": null,
"error_message": null
}

DELETE /analysis/{analysis_id}

Soft-delete del job. Risposta 204.


7. Monitoring

Utilizzo, costi e dashboard. I valori monetari (cost_usd) sono visibili solo a profili specifici; per gli altri sono restituiti azzerati (i conteggi token e record restano accurati).

GET /usage

Elenca i record di utilizzo del tenant.

Attributi richiesta

CampoInTipoDefaultDescrizione
start_timequerydatetime ISO 8601Inizio finestra.
end_timequerydatetime ISO 8601Fine finestra.
servicequerystringFiltra per servizio (es. ai-core, knowledge).
offset, limitqueryint0, 100Paginazione (limit max 1000).

Esempio risposta (200 OK)

{
"items": [
{
"id": 9001,
"tenant_id": "acme",
"service": "ai-core",
"resource": "chat",
"operation": "message",
"quantity": 1,
"unit": "message",
"metadata": { "agent_id": 87 },
"timestamp": "2026-04-30T11:22:14Z"
}
],
"total": 1,
"offset": 0,
"limit": 100
}

GET /costs/summary

Sintesi costi del periodo, con breakdown per servizio, modello, operazione, source app, cost tier e giorno.

Attributi richiesta

CampoInTipoObbligatorioDescrizione
start_timequerydatetime ISO 8601Inizio finestra.
end_timequerydatetime ISO 8601Fine finestra.
servicequerystringNoFiltro.
modelquerystringNoFiltro.
source_appquerystringNoFiltro.
operation_typequerystringNoFiltro su metadata.operation_type.
cost_tierquerystringNoFiltro.

Esempio richiesta

curl -G "https://ai.askme.it/api/v2/costs/summary" \
-H "X-Api-Key: amai_xxxxxxxxxxxxxxxx" \
-H "X-Source-App: api_direct" \
--data-urlencode "start_time=2026-04-01T00:00:00Z" \
--data-urlencode "end_time=2026-04-30T23:59:59Z"

Esempio risposta (200 OK)

{
"tenant_id": "acme",
"start_time": "2026-04-01T00:00:00Z",
"end_time": "2026-04-30T23:59:59Z",
"total_cost_usd": "12.4810",
"total_input_tokens": 412300,
"total_output_tokens": 88142,
"by_service": [
{ "key": "ai-core", "total_cost_usd": "10.20", "total_input_tokens": 320000, "total_output_tokens": 64000, "record_count": 1102 }
],
"by_model": [
{ "key": "gpt-4o-mini", "total_cost_usd": "8.10", "total_input_tokens": 290000, "total_output_tokens": 60000, "record_count": 980 }
],
"by_operation_type": [
{ "key": "chat.generation", "total_cost_usd": "9.40", "total_input_tokens": 300000, "total_output_tokens": 70000, "record_count": 950 }
],
"by_source_app": [
{ "key": "api_direct", "total_cost_usd": "5.20", "total_input_tokens": 150000, "total_output_tokens": 30000, "record_count": 410 }
],
"by_date": [
{ "date": "2026-04-01", "total_cost_usd": "0.42", "total_input_tokens": 11200, "total_output_tokens": 2820 }
]
}

GET /costs/by-category

Breakdown costi per operation_type (es. chat.generation, chat.query_rewrite, chat.rerank, analysis.pdf, ecc.).

Attributi richiesta: start_time, end_time (entrambi obbligatori).

Esempio risposta (200 OK)

[
{ "key": "chat.generation", "total_cost_usd": 9.40, "total_input_tokens": 300000, "total_output_tokens": 70000, "record_count": 950 },
{ "key": "chat.query_rewrite", "total_cost_usd": 0.20, "total_input_tokens": 8000, "total_output_tokens": 1200, "record_count": 410 },
{ "key": "unknown", "total_cost_usd": 0.00, "total_input_tokens": 1200, "total_output_tokens": 200, "record_count": 12 }
]

I record privi del tag finiscono nel bucket unknown.

Endpoint analoghi: GET /costs/by-service, GET /costs/by-model, GET /costs/by-source-app, GET /costs/by-cost-tier.


GET /costs

Lista paginata dei singoli record di costo con filtri estesi (service, model, source_app, operation_type, cost_tier, conversation_id, turn_id, external_id, agent_id, is_streaming).


GET /costs/conversations/{conversation_id}/turns

Riepilogo costi per ogni turn della conversazione.

GET /costs/turns/{turn_id}/events

Tutti gli eventi di costo di un singolo turn (utile per audit dettagliato).


GET /dashboard/metrics

Metriche aggregate per la dashboard (cache ~2s).

Esempio risposta (200 OK)

{
"conversationsToday": 142,
"conversationsChange": 8.2,
"activeAgents": 12,
"activeAgentsChange": 0.0,
"knowledgeBases": 6,
"mtdCost": 4.81,
"mtdCostChange": -3.4,
"handoffsToday": 4,
"handoffsChange": 33.3,
"quotaUsagePercent": 42.0,
"quotaUsageChange": 5.1,
"isSuperAdmin": false
}

GET /dashboard/trend

Trend conversazioni per giorno (parametro days, default 30).

GET /dashboard/top-agents

Classifica degli agenti per volume di conversazioni.

GET /metrics

Metriche Prometheus in formato testo (text/plain). Endpoint operativo, generalmente consumato dal sistema di monitoring infrastrutturale.


8. Prompt Templates

Template di prompt riutilizzabili e versionabili.

POST /prompt-templates

Crea un template.

Attributi richiesta

CampoInTipoObbligatorioDefaultDescrizione
namebodystring (1–255)Nome del template.
contentbodystringTesto del prompt; può contenere {{variabile}}.
rolebodystringNosystemRuolo del messaggio (system, user, assistant).
descriptionbodystringNoDescrizione.
variablesbodyarrayNo[][{ name, description, default_value }].
parent_idbodyintNoTemplate genitore.
tagsbodystring[]No[]Tag liberi.
statusbodystringNodraftdraft, published, archived.

Esempio risposta (201 Created)

{
"id": 55,
"tenant_id": "acme",
"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 azienda", "default_value": "Askme" }
],
"parent_id": null,
"tags": ["welcome", "support"],
"status": "draft",
"version": 1,
"created_by": "user-uuid",
"created_at": "2026-04-30T12:00:00Z",
"updated_at": "2026-04-30T12:00:00Z"
}

GET /prompt-templates

Elenca i template.

Attributi richiesta

CampoInTipoDefaultDescrizione
parent_idqueryintFiltra per template genitore.
statusquerystringFiltro stato.
searchquerystringRicerca testuale.
root_onlyqueryboolfalseSe true mostra solo i template senza genitore.
offset, limitqueryint0, 50Paginazione (limit max 200).

PUT /prompt-templates/{template_id}

Aggiornamento (campi opzionali). Incrementa version.

DELETE /prompt-templates/{template_id}

Eliminazione (204).


Operazioni non esposte

Le operazioni amministrative non documentate qui (es. provisioning di tenant, gestione piani e quote, configurazione globale del sistema) non sono accessibili tramite la chiave API tenant. Per queste necessità contatta il team IT di Askme.