Prodotto italiano di Agile Technology

Per sviluppatori

Persona-as-a-Service

Una persona digitale è un servizio governabile via API key: la interroghi da /v1, con scope e quota dichiarati sulla chiave. Nessun browser, nessun cookie, nessun CSRF — l'autenticazione è la chiave stessa.

Il modello

La persona è un endpoint, non una piattaforma

Il tuo programma parla con la persona del tuo cliente usando la sua chiave. L'ordine dei passi è sempre lo stesso e non è negoziabile: riconosci la chiave → autorizza prima di eseguire → esegui → registra il consumo.

🔑

API key, non sessione

La chiave viaggia in Authorization: Bearer o in X-Persona-Key. Mai nella querystring, mai in un cookie.

📏

Scope e quota

Gli scope sono ciò che è stato acquistato. Non esiste una chiamata che li estenda: se serve di più, si compra di più.

📟

Consumo registrato

Ogni operazione registra il consumo dopo l'esecuzione, con i valori veri. Un turno non servito non si paga.

🧠

Memoria unica

La persona ricorda l'interlocutore attraverso i canali: la chat di oggi e la telefonata di domani sono la stessa conversazione.

La chiave

Come si ottiene una chiave, davvero

Non c'è un bottone «genera una chiave di prova». Una chiave nasce con l'acquisto di una persona digitale (o di un singolo componente sovrano), perché scope e quote sono ciò che è stato comprato: non esistono prima dell'ordine.

  1. 1 · Si configura e si ordina

    Dal configuratore si compone la persona — cervello, organi, canali — e si arriva al checkout. In alternativa si compra un componente standalone (per esempio la sola voce): riceve una chiave sua, con gli scope del solo organo.

    Per una trattativa, un profilo di conformità particolare o un motore su misura, si passa dal modulo di richiesta: non emette una chiave, apre un contatto.

  2. 2 · Al pagamento la chiave nasce, dentro l'ordine

    Il provisioning crea il tenant della persona e, nella stessa transazione, la riga della chiave con gli scopes e le quote dell'ordine. Il nome che porta è letteralmente «chiave di consegna — ordine riferimento»: serve a ritrovarla nell'elenco.

  3. 3 · Arriva per email, e si vede una volta sola

    La consegna è un messaggio di posta al cliente dell'ordine. Il valore in chiaro non viene salvato da nessuna parte: il database conserva l'impronta SHA-256 e il prefisso (i primi 16 caratteri), che basta a riconoscerla in un elenco e non basta a indovinarla.

    Mettila subito dove la tieni — una variabile d'ambiente, un gestore di segreti. Se la perdi non si recupera: si rigenera.

  4. 4 · Se si perde, si rigenera dall'area riservata

    Nell'area riservata, alla voce delle tue persone, c'è «rigenera». La chiave vecchia viene revocata prima che la nuova nasca: non esiste un istante in cui valgono entrambe, quindi la rigenerazione è un'interruzione di servizio — breve, ma va programmata.

    Anche la nuova arriva per email. Se la posta non parte, la risposta lo dice: la vecchia è comunque morta.

  5. Quello che oggi non c'è
    • Nessuna chiave di prova senza acquisto, e nessun ambiente sandbox separato: non c'è una registrazione self-service che consegni una chiave.
    • Nessuna rotta di /v1 emette, ruota o revoca chiavi. Le 45 rotte del contratto usano la chiave, non la amministrano: la rigenerazione richiede una sessione dell'area riservata, quindi non si automatizza da programma.
    • Le chiavi emesse oggi non scadono. Il rifiuto per scadenza esiste ed è attivo, ma il campo della scadenza nasce vuoto e nessun codice lo compila: finché resta così, chiave_scaduta non si vedrà mai. Ruotare è una scelta tua, non un promemoria nostro.
    • Nessun preavviso automatico prima di una revoca o di una scadenza.

Questo elenco è scritto perché un'assenza dichiarata costa meno di un flusso raccontato e poi non trovato. Quando uno di questi passi esisterà, cambierà questa pagina.

Quickstart

Dalla chiave alla prima risposta

Tre chiamate: chi è la persona, quanto le resta, e come le si parla. La chiave sta in una variabile d'ambiente — mai incollata nel codice.

  1. 1 · Chi è la persona — GET /v1/persona

    La carta d'identità: scope acquistati, quote residue, vincoli e l'asse di sovranità. È la prima chiamata che si fa, ed è la più economica che esista qui: non carica file e non accende una GPU. Non è gratis però — conta come una richiesta sulla quota richieste_giorno, come ogni altra.

    È anche l'unica che non chiede uno scope particolare: se la tua chiave è attiva, questa risponde.

La chiave qui sotto è finta. Ha la forma giusta (adp_pk_ più 40-64 caratteri) ma non esiste in nessun database: copiandola otterrai 401 chiave_non_valida. Metti la tua, quella arrivata per email.
GET /v1/personabash
# la chiave è nell'ambiente, non nel sorgente
export ADP_KEY="adp_pk_QUESTA-CHIAVE-E-FINTA-non-funziona-0000000000"

curl https://adp.agile.software/v1/persona \
  -H "Authorization: Bearer $ADP_KEY"
Rispostajson
{
  "persona": { "agent_key": "giulia", "slug": "giulia-back-office", "stadio": "operativa" },
  "scopes": ["channels.chat", "memory.read", "organs.voce"],
  "quote": {
    "richieste_giorno": { "tetto": 2000, "usato": 137, "restante": 1863, "finestra": "giorno" }
  },
  "vincoli": { "sovranita": { "valore": "ue", "livello": "duro" } },
  "sovranita": "ue",
  "cervello": { "base": "…", "veloce": "…", "ammessi": [] },
  "skills": []
}
  1. 2 · Quanto le resta — GET /v1/consumi

    Il consumo, da solo: la chiamata che si mette in un cruscotto per sapere se aspettare o comprare di più.

GET /v1/consumibash
curl https://adp.agile.software/v1/consumi \
  -H "X-Persona-Key: $ADP_KEY"
Rispostajson
{
  "quote": {
    "richieste_giorno": { "tetto": 2000, "usato": 137, "restante": 1863, "finestra": "giorno" },
    "minuti_voce":      { "tetto": 300,  "usato": 12,  "restante": 288,  "finestra": "mese" }
  },
  "momento": "2026-01-01T12:00:00.000Z"
}
  1. 3 · Parlale — POST /v1/messaggi/invia

    Il tuo sistema scrive, la persona risponde. La memoria dell'interlocutore è unica attraverso i canali. Autorizza prima, esegue, poi registra il costo reale del turno.

POST /v1/messaggi/inviabash
curl https://adp.agile.software/v1/messaggi/invia \
  -H "Authorization: Bearer $ADP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "canale": "chat",
    "mittente": "cliente-482",
    "nome": "Marco Rossi",
    "testo": "Quando scade la mia pratica?"
  }'

Un corpo malformato risponde 400 con { "errore": ... }; quota esaurita risponde con tetto, usato e finestra, così il tuo codice sa se ritentare. Il cervello non disponibile è un 503 — e quel turno non si paga.

Nella risposta c'è anche verificaNumerica, ed è nuovo dal 18/9/2026: ogni numero che la persona scrive viene passato a un motore di calcolo deterministico, e quello che non si è potuto verificare esce dichiarato. esito vale pulito, marcato (c'è almeno un numero non verificato, ed è in nonVerificati) o sbagliato (un calcolo falso, con dentro quanto fa davvero). La risposta arriva comunque: sta al tuo sistema mostrare l'avviso accanto al testo, mai dentro — se si confonde con ciò che la persona afferma, non serve a nulla.

Quando va storto

Che cosa risponde, e che cosa devi farci

Il corpo di un errore ha sempre la stessa forma: { "errore": "<codice>", "dettaglio": … }. Il codice è una parola stabile — è su quella che si scrive la gestione, non sul testo.

I quattro che incontrerai per primi.
StatoCodiceChe cos'è, e che cosa fare
401 chiave_non_valida Chiave assente, malformata, sconosciuta, revocata, o persona archiviata: i casi sono indistinguibili di proposito, perché chi prova chiavi a caso non deve imparare nulla dalla risposta. Non ritentare: controlla l'header, e se la chiave è stata rigenerata prendi quella nuova.
401 chiave_scaduta La chiave è vera ma oltre la sua data: te lo diciamo perché tu non vada a cercare un guasto che non c'è. Porta scaduta_il. Lo stato resta 401 apposta — la tua gestione degli errori non cambia, cambia solo la parola. Oggi non lo vedrai: le chiavi nascono senza scadenza.
423 persona_sospesa La chiave è giusta, ma la persona è stata sospesa dall'area riservata: non risponde su nessun condotto. Qui il perche si dice, perché chi ha la chiave giusta è il proprietario. Si risolve riprendendola dall'area, e riparte esattamente dallo stadio in cui era.
429 quota_esaurita La quota acquistata è finita. Il dettaglio porta quota, tetto, usato e finestra, e l'header Retry-After dice i secondi che mancano perché il consumo più vecchio esca dalla finestra. Aspetta quei secondi, oppure compra di più.
Gli altri che il codice può restituire, e che vale la pena gestire.
StatoCodiceChe cos'è, e che cosa fare
403 scope_mancante La chiamata esiste, ma il suo scope non è fra quelli acquistati. Il dettaglio dice serve e hai: non è un'informazione utile a un estraneo, e a te serve. Nessuna chiamata estende uno scope — si compra.
402 quota_non_acquistata Per quell'operazione non c'è una quota, oppure è a zero. Una quota non dichiarata non vuol dire illimitata: vuol dire non comprata, e qui si fallisce chiusi.
403 vietato_dal_profilo Il profilo di conformità della persona vieta quella famiglia di operazioni — per esempio il profilo minori sulle chiamate di voce. Non si aggira con uno scope comprato.
429 troppe_richieste È un 429 diverso: non la quota, la frequenza. Il freno è per indirizzo IP, con finestra di un minuto (240 richieste sulle rotte di lettura, 60 su quelle che fanno lavoro). La risposta porta bucket e gli header standard RateLimit. Distingui i due 429 sul campo errore, mai sullo stato.

Il contratto a macchina dichiara per ogni rotta 401, 423 e 429. I tre della seconda tabella li restituisce il codice ma il contratto non li elenca ancora: sono qui perché gestirli ti evita un guasto, non perché siano documentati là.

La superficie

Le 45 rotte di /v1

Sono ventidue, e sono tutte qui. Ogni chiamata è governata dallo scope della chiave: quello che la persona non ha comprato risponde 403 scope_mancante. Lo scope indicato accanto a ogni rotta è quello che il codice pretende davvero.

POST/v1/personeforgia una persona nuova: nasce in «staging», l'ordine la promuoveforgia.persone
GET/v1/personele persone che hai forgiato e non ancora comprato. L’elenco è tagliato a 200 righe e non c’è paginazione: la risposta porta totale, inQuestaPagina e troncato, così sai se ne esistono altrenessuno scope
POST/v1/persone/:agentKey/promuovida «staging» a «produzione»: vuole un ordine pagato della tua organizzazioneforgia.persone
GET/v1/persone/:agentKey/metodola checklist di nascita: quali dei 6 pezzi del metodo questa persona ha già (il libro, i fatti, le domande, le tabelle, gli strumenti, il collaudo) e dove si scrivono quelli che mancanonessuno scope
PATCH/v1/persone/:agentKey/profilocorregge nome, ruolo, carattere, carattere della voce, caratteristiche: tocca solo i campi che mandi, e agent_key non cambia maiforgia.persone
GET/v1/personaidentità, scope, quotenessuno scope
GET/v1/consumiquote residuenessuno scope
POST/v1/messaggi/inviaun turno di conversazionechannels.chat
GET/v1/capacitache cosa questa persona può fare su un canale, su quali canali, e l'elenco chiuso degli esiti di ogni capacità: si legge prima di scrivere il proprio switchnessuno scope
POST/v1/canale/arrivoè arrivato un messaggio: la persona capisce, decide e risponde — oppure dice perché no. Lo stesso uid due volte dà una rispostail canale della richiesta
POST/v1/canale/scrivila persona scrive per prima: la chiave di idempotenza logica la decidi tu, consenso e soppressione li impone il trasportoil canale della richiesta
POST/v1/canale/passa-a-umanopassa a un umano: il referente viene dal forge, mai cablato nel canaleil canale della richiesta
GET/v1/canale/consegna/:idè partita davvero? risposto vuol dire accodato, e accodato non è consegnatonessuno scope
POST/v1/canale/fermatila persona si ferma e lo dice: il rifiuto entra nel registro e torna la frase da dire. Non consuma quota — un rifiuto non si fatturanessuno scope
GET/v1/memoria/:interlocutorelo storico di un interlocutorememory.read
POST/v1/memoria/:interlocutore/dimenticadiritto all'oblio (art. 17)memory.write
POST/v1/memoria/:interlocutore/collegastessa persona, canale nuovo: il codice arriva sul canale NUOVOmemory.write
POST/v1/memoria/:interlocutore/collega/confermail codice, digitato sul canale di primamemory.write
POST/v1/voce/sintetizzatesto → audioorgans.voce
POST/v1/voce/trascriviaudio → testoorgans.orecchie
POST/v1/voce/turnoaudio → audio: un turno interoorgans.orecchie + channels.chat + organs.voce
POST/v1/videochat/apriuna sessione con volto e vocechannels.videochat
POST/v1/videochat/chiudichiude la stanza e addebita i minuti verichannels.videochat
POST/v1/atelier/schedauna scheda di esercizi (PDF vero)mani.atelier
POST/v1/atelier/documentoun documento (markdown) nel cassettomani.atelier
GET/v1/atelieril cassetto dei materiali, tagliato a 50 righe e senza paginazione: la risposta porta totale, inQuestaPagina e troncatomani.atelier
GET/v1/atelier/:idscarica un materialemani.atelier
POST/v1/agendala persona PROPONE un impegno (mai nei giorni vietati)mani.agenda
POST/v1/agenda/:id/statoconcordare o disdiremani.agenda
GET/v1/agendai prossimi impegnimani.agenda
GET/v1/calendario/aggregatoil calendario AGGREGATO dell'aula per un partner: istanti e capienza, nessun identificativo di studentemani.agenda
POST/v1/bibliotecaassorbe un libro posseduto (il DRM si respinge, mai si aggira)organs.biblioteca
POST/v1/biblioteca/cercacerca per testo o per PAGINA («pagina 184»)organs.biblioteca
GET/v1/bibliotecalo zaino dei volumiorgans.biblioteca
DELETE/v1/biblioteca/:idtoglie un volume dallo zainoorgans.biblioteca
POST/v1/conoscenzacarica una fonte della tua conoscenza (corpo GREZZO, metadati in query): nasce in bozza, non fa fedeconoscenza.scrivi
GET/v1/conoscenzail catalogo delle fonti, con la loro certificazione e la modalita del firewallconoscenza.leggi
POST/v1/conoscenza/urlcarica da un indirizzo: solo https pubblico, ogni salto rigiudicato, tipi e byte col tettoconoscenza.scrivi
POST/v1/conoscenza/:id/certificada qui fa fede: chi firma e la chiave, e servono validita e AMBITOconoscenza.scrivi
POST/v1/conoscenza/:id/revocatoglie la fede da subito; i brani restano, la revoca e un fattoconoscenza.scrivi
DELETE/v1/conoscenza/:idcancella la fonte e i suoi brani (resta la riga di audit)conoscenza.scrivi
POST/v1/conoscenza/cercache cosa sa la persona su una domanda: brani, punteggi e soglia, senza farla parlareconoscenza.leggi
POST/v1/conoscenza/reindicizzarifa i vettori (indicizzazione fallita, o modello cambiato). Idempotenteconoscenza.scrivi
GET/v1/conoscenza/verdettiil referto del firewall: quanti NO, quanti SI, e per quale motivoconoscenza.leggi
POST/v1/mani/operaopera un'applicazione col contratto a verbi (scope-dati obbligatorio; default = prova)mani.operate_app

Attenzione a un'asimmetria che costa tempo: gli scope qui sopra sono quelli che governano le rotte, e non coincidono uno a uno con le voci del listino. Comprare il solo cervello dà lo scope converse, che nessuna di queste trentasette rotte controlla: per far rispondere /v1/messaggi/invia serve channels.chat. La GET /v1/persona ti dice sempre quali scope hai davvero in mano — è il motivo per cui è la prima chiamata da fare.

Una persona sospesa dall'area riservata risponde 423 persona_sospesa su ogni endpoint: chi ha la chiave giusta ha diritto al motivo — la ripresa dall'area la rimette esattamente dov'era.

Il diritto all'oblio è un endpoint: il tuo cliente è titolare del trattamento dei suoi interlocutori, e la cancellazione cancella davvero — non azzera campi. La risposta elenca anche le registrazioni che devi distruggere tu.

Il contratto

La specifica a macchina

Questa pagina è la spiegazione. La verità formale sta in un file OpenAPI 3.0.3, con le 45 rotte, il metodo, il percorso, il permesso di ognuna e le tre risposte d'errore del contratto.

docs/openapi-v1.yaml

Il server dichiarato è il percorso relativo /v1: nessun host è cablato dentro il contratto, perché l'host lo decide il rilascio. La sicurezza è dichiarata in due modi alternativi per la stessa chiave — Authorization: Bearer oppure l'header X-Persona-Key: usa quello che il tuo client gestisce meglio.

Non si modifica a mano. Il file è generato dal codice delle rotte, quindi non può descrivere una rotta che non esiste né dimenticarne una che è stata aggiunta. Se un giorno divergesse dal comportamento, il difetto è nel codice, non nella specifica.

Due cose che è giusto sapere prima di puntarci uno strumento: il contratto non è pubblicato su HTTP — sta nel repository del progetto, e te lo passiamo insieme alla chiave — e non dichiara gli schemi dei corpi di richiesta e risposta, lasciati aperti di proposito. Per generare un client tipizzato oggi non basta: per sapere che cosa esiste, che cosa pretende e come rifiuta, sì.

Sovranità

Due assi, dichiarati sempre

Ogni cosa vendibile porta con sé la risposta a due domande indipendenti. La GET /v1/persona le restituisce entrambe: chi integra non deve chiederle a nessuno.

Dove gira il calcolo

esecuzione: nostra (motori sovrani self-host), ue (provider in Unione Europea) o extra-ue. Il profilo di conformità della persona può vincolarlo — e allora una scelta fuori regione viene rifiutata, non silenziosamente accettata.

Dove finiscono i dati

dati: sovrani (restano nel nostro perimetro) o condivisi (passano dal provider). Sono due assi separati: un calcolo in UE non implica dati sovrani, e il sistema non lascia confondere le due cose.

Né provider né voice_id si accettano dal corpo della richiesta: la voce e il volto della persona sono quelli che ha comprato, risolti dal Lettore Unico. Un parametro dal chiamante non la farà parlare con una voce che non è la sua, sul nostro conto.

Motori sovrani

Gli organi come prodotti versionati

I motori self-host sono prodotti a sé, con revisione semantica e stato di rilascio (sviluppo / beta / attiva / deprecata / ritirata). "L'ultima" è sempre l'ultima attiva, mai una beta. Girano su hardware in UE, on-demand, con licenza in affitto (e, in prospettiva, perpetua).

Voce

agile-tts

La sintesi vocale sovrana: testo dentro, audio fuori. È l'organo voce di default, con dati sovrani.

Orecchie

agile-whisper

La trascrizione sovrana (STT): audio dentro, testo fuori. È l'organo orecchie di default.

Occhi

agile-pixel

La visione sovrana su GPU: legge documenti e immagini. È l'organo occhi di default.

Accanto ai motori sovrani restano i provider esterni (ElevenLabs, Deepgram, Tavus…): stesso organo, asse dei dati diverso. Il catalogo vendibile, con codice, revisione attiva e i due assi, è pubblico su GET /api/servizi.

Distinta base

Compra il componente, non la piattaforma

Una persona digitale è una distinta base di componenti sovrani: cervello, voce, orecchie, occhi, volto, mani, canali. Ognuno è un prodotto con un part number stabile — un progressivo che non si riusa mai, come nei sistemi maturi.

Puoi comprare un singolo componente sovrano e usarlo via API, senza assumere una persona intera: una voce o delle orecchie diventano un servizio a sé, con la loro chiave e la loro quota. La distinta AS-CONFIGURED nasce dal configuratore e arriva intatta fino all'assunzione.

Gli organi, come li vende il listino

Cervelloconverse
Voceorgans.voce
Orecchieorgans.orecchie
Occhiorgans.occhi
Voltoorgans.volto
Maniorgans.mani

Questi sono i nomi con cui gli organi si comprano. Gli scope che aprono le rotte di /v1 stanno accanto a ogni endpoint, e non sono gli stessi: la fonte di verità su che cosa hai in mano è sempre GET /v1/persona.

Multi-canale

Una API, tutti i canali

Chat, email, WhatsApp, telefono e videochiamata sono scope sulla chiave. Il campo canale del messaggio dice da dove arriva l'interlocutore; la memoria resta unica quando cambia.

scopechannels.chatchat
scopechannels.emailemail
scopechannels.waWhatsApp
scopechannels.telefonovoce, richiede orecchie
scopechannels.videochatvolto + voce

Di questi, quelli che oggi aprono una rotta di /v1 sono due: channels.chat (che governa /v1/messaggi/invia, qualunque sia il valore del campo canale) e channels.videochat. Email, WhatsApp e telefono si comprano e si configurano, ma non hanno una rotta dedicata nel contratto: passano di lì.

Una chiave, e la tua persona è un servizio.

Chiedi una API key per la persona del tuo cliente e integrala nel tuo software. Scope e quota li decide il contratto, non il codice.

Chiedi una chiave La versione per le aziende