In breve
- Per ogni agente puoi elencare i dati che servono prima di fissare un appuntamento. Finché un dato obbligatorio manca, l'appuntamento non viene fissato: l'agente viene informato di che cosa chiedere, lo chiede, lo salva e fissa. Vale anche se lo script non nominava quel dato.
- Si configura con una sola richiesta, PUT /agents/ID/appointment-settings, che imposta la durata in minuti e l'elenco dei dati. Ogni dato ha un'etichetta, un percorso che dice dove leggerlo e l'indicazione se è obbligatorio.
- I dati che hanno un valore compaiono nella descrizione dell'evento su Google Calendar, nell'ordine in cui li hai elencati. L'invito parte verso l'email del contatto: per una videochiamata rendi obbligatorio lead_info.email.
- La durata va da 5 a 480 minuti, a passi di 5, e vale per ogni appuntamento fissato da quell'agente. Senza configurazione resta di 30 minuti. L'agente propone solo orari in cui l'appuntamento intero trova posto.
Con le API di Aptiva decidi, per ogni agente vocale AI, quali dati servono prima di fissare un appuntamento e quanto dura l'appuntamento. Finché un dato obbligatorio manca, l'appuntamento non viene fissato: Aptiva lo rifiuta e dice all'agente che cosa chiedere. L'agente lo chiede, lo salva e fissa. Vale anche se lo script non nominava quel dato.
Il caso tipico è la videochiamata. Senza l'email della persona l'invito non parte, e una videochiamata fissata senza invito non serve a nulla. Una riga nello script non basta a escluderlo: l'agente può saltarla. Con un dato obbligatorio il controllo non dipende più dallo script.
I dati raccolti compaiono poi nella descrizione dell'evento su Google Calendar: chi va all'appuntamento li ha davanti.
Questa guida mostra i due casi più comuni con l'esempio completo, la videochiamata e il sopralluogo. Poi spiega ogni campo, i dati che puoi usare e i codici di errore. Le convenzioni comuni (chiave, header X-API-Key, formato degli errori) sono nella guida ai primi passi. Tutti i percorsi vanno aggiunti all'indirizzo base https://api.aptiva.cloud/external/api.
Cosa ti serve prima di iniziare#
Per configurare gli appuntamenti di un agente servono tre cose:
- La chiave API: la guida ai primi passi spiega dove trovarla.
- L'ID dell'agente (
agentId): nel pannello è accanto al nome dell'agente, nella forma#42. - Google Calendar attivo su quell'agente: nel pannello, alla pagina «Integrazioni», apri Google Calendar e nella sezione «Agenti» scegli i calendari dell'agente e attivalo. Senza calendario la configurazione si salva e si rilegge, ma non ha effetto: l'agente non fissa appuntamenti.
Dati obbligatori e durata si configurano solo via API: il pannello non ha una schermata dedicata.
Come funziona il controllo#
Il controllo avviene nel momento in cui l'agente fissa, prima di qualunque scrittura sul calendario:
- Salvi la configurazione dell'agente con una richiesta
PUT /agents/ID/appointment-settings: la durata e l'elenco dei dati. - Durante la telefonata la persona sceglie un orario e l'agente prova a fissare. Aptiva controlla i dati obbligatori dell'elenco.
- Se un dato manca, l'appuntamento non viene creato. Sul calendario non compare nulla. L'agente riceve l'elenco dei dati mancanti e sa che cosa fare: usare il dato se la persona lo ha già detto, altrimenti chiederlo e farselo confermare, poi salvarlo.
- L'agente fissa lo stesso orario. Ora il dato c'è e l'evento viene creato, con i dati dell'elenco nella descrizione.
Tre cose da sapere:
- Un dato manca quando non c'è o è vuoto. Un testo vuoto o di soli spazi non conta come valore. Contano invece
falsee0. - L'agente è istruito a non inventare e a non insistere. Le istruzioni che riceve gli vietano i valori di comodo, come «non fornito». Se la persona non vuole dare il dato, l'appuntamento non si fissa.
- Una modifica all'elenco vale subito, anche per una telefonata già in corso. La durata, invece, è quella in vigore all'inizio della telefonata.
Decidi nello script che cosa succede quando un appuntamento non si può fissare: prendere un messaggio per l'ufficio, proporre un richiamo, passare la chiamata a una persona. L'agente segue quelle istruzioni. Se lo script non dice nulla, spiega alla persona che verrà ricontattata per fissare l'appuntamento. Ogni rifiuto di questo controllo comincia con le parole «Appuntamento NON fissato», anche il primo, a cui l'agente rimedia chiedendo il dato. Nello script puoi riferirti a quelle, ma lega l'alternativa al caso in cui il dato non si riesce ad avere. Un orario fuori fascia o già occupato arriva all'agente con un testo diverso.
Videochiamata: l'email è obbligatoria#
L'invito di Google Calendar parte verso l'email del contatto. Per essere certo che ogni videochiamata abbia il suo invito, rendi obbligatoria l'email del contatto, lead_info.email:
curl -sS -X PUT "https://api.aptiva.cloud/external/api/agents/42/appointment-settings" \
-H "X-API-Key: $APTIVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"durationMinutes": 30,
"fields": [
{ "label": "Email", "jmespath": "lead_info.email", "required": true }
]
}'
La risposta è 200 con la configurazione salvata. Ogni dato vi porta anche hint, che vale null se non lo hai scritto:
{
"durationMinutes": 30,
"fields": [
{ "label": "Email", "jmespath": "lead_info.email", "required": true, "hint": null }
]
}
In chiamata succede questo. La persona chiede la videochiamata e sceglie un orario. Se il contatto ha già un'email, per esempio perché l'hai creato via API con il campo email, l'agente fissa subito. Se non ce l'ha, l'agente è istruito a chiederla, a farsela confermare e a salvarla sul contatto; poi fissa. L'evento nasce con l'invitato e l'invito parte; se il calendario lo prevede, l'evento porta anche il link di Google Meet.
Il percorso deve essere proprio lead_info.email: l'invitato dell'evento è sempre l'email del contatto. Un'email salvata altrove comparirebbe nella descrizione, ma l'invito non partirebbe.
Sopralluogo: indirizzo obbligatorio, telefono facoltativo, un'ora#
Per un sopralluogo servono un'ora di tempo e l'indirizzo. Il telefono è utile al tecnico, ma non deve bloccare la prenotazione:
curl -sS -X PUT "https://api.aptiva.cloud/external/api/agents/42/appointment-settings" \
-H "X-API-Key: $APTIVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"durationMinutes": 60,
"fields": [
{
"label": "Indirizzo del sopralluogo",
"jmespath": "call_info.sopralluogo.indirizzo",
"required": true,
"hint": "Chiedi via, numero civico e comune, poi ripeti tutto per conferma."
},
{
"label": "Telefono",
"jmespath": "call_info.sopralluogo.telefono || lead_info.phone",
"required": false
}
]
}'
Che cosa ottieni:
- Durata di un'ora. L'agente propone solo orari in cui un'ora intera è libera, e l'evento dura 60 minuti.
- Indirizzo obbligatorio. L'agente non fissa finché non lo ha salvato fra i dati della chiamata. Il testo di
hintgli dice come chiederlo. - Telefono facoltativo, con un'alternativa. Se lo script dice all'agente di salvare fra i dati della chiamata, in
sopralluogo.telefono, il numero che la persona lascia per il giorno del sopralluogo, nell'evento compare quello. Altrimenti compare il numero del contatto. Se mancano entrambi, la riga si salta e l'appuntamento si fissa lo stesso.
La descrizione dell'evento sul calendario:
Appuntamento con Laura Bianchi di Energia Esempio Srl fissato durante la telefonata del 20/10/2026 10:12 id contatto 1285
Indirizzo del sopralluogo: Via Esempio 1, 00100 Roma RM
Telefono: +393331234567
I campi della richiesta#
Il corpo di PUT /agents/ID/appointment-settings ha due campi, entrambi obbligatori. La richiesta sostituisce l'intera configurazione: l'elenco che invii prende il posto di quello salvato. L'elenco è uno per agente e vale per ogni appuntamento che quell'agente fissa.
| Campo | Tipo | Cosa fa |
|---|---|---|
durationMinutes | intero da 5 a 480, multiplo di 5 | Durata in minuti di ogni appuntamento fissato dall'agente |
fields | elenco, al massimo 15 voci | I dati dell'appuntamento, nell'ordine in cui compaiono nell'evento. Può essere vuoto |
Ogni voce di fields descrive un dato:
| Campo | Tipo | Obbligatorio | Cosa fa |
|---|---|---|---|
label | stringa da 1 a 60 caratteri, su una riga | sì | Il nome del dato. Compare nell'evento e arriva all'agente quando un dato obbligatorio manca. Unico nell'elenco, senza distinguere maiuscole e minuscole |
jmespath | stringa da 1 a 200 caratteri | sì | Il percorso: dove leggere il dato (vedi i dati che puoi usare) |
required | booleano | sì | true: senza questo dato l'appuntamento non si fissa. Ammesso solo su alcuni percorsi |
hint | stringa da 1 a 300 caratteri, su una riga | no | Un suggerimento per l'agente su come ottenere il dato. Ha effetto solo su un dato obbligatorio |
Scrivi etichette parlanti: «Indirizzo del sopralluogo», non «addr1». L'etichetta la legge chi apre l'evento, e l'agente la riceve quando un dato obbligatorio manca, e la usa per capire che cosa chiedere.
I dati che puoi usare#
Al momento di fissare, Aptiva compone un oggetto JSON con i dati del contatto e della telefonata. Ogni percorso si legge su questo oggetto:
{
"lead_info": {
"id": 1285,
"name": "Mario",
"last_name": "Rossi",
"email": "mario.rossi@example.com",
"phone": "+393331234567",
"lead_company_name": "Rossi Srl",
"additional_info": { "origine": "form preventivo" }
},
"call": {
"id": 9876,
"direction": "outbound",
"context": { "pratica": "A-17" }
},
"call_info": {
"sopralluogo": { "indirizzo": "Via Esempio 1, 00100 Roma RM" }
}
}
| Percorso | Che cosa contiene | Da dove arriva |
|---|---|---|
lead_info.name, lead_info.last_name, lead_info.email, lead_info.lead_company_name | Nome, cognome, email e azienda del contatto | L'agente durante la chiamata, le API dei lead, l'importazione dei contatti |
lead_ | Il numero del contatto in formato internazionale | Il numero da cui la persona chiama, o quello del lead che hai creato. Manca per chi chiama con il numero nascosto |
lead_ | I campi liberi del contatto: gli stessi di additionalInfo nelle API dei lead | L'agente durante la chiamata, le API dei lead, l'importazione dei contatti |
lead_ | L'ID del contatto | Aptiva |
call.id, call.direction | L'ID della chiamata e il verso: inbound o outbound | Aptiva |
call.context.<chiave> | Il contesto che il tuo sistema ha passato avviando la chiamata via API (callConfig.context di POST /calls/start; lo schema completo è nella reference interattiva) | Il tuo sistema |
call_ | I dati di questa telefonata | L'agente durante la chiamata |
La differenza che conta è fra le due famiglie:
- I dati del contatto (
lead_info) restano sul contatto e valgono per le chiamate successive. Sono il posto giusto per ciò che non cambia: l'email, il nome, la ragione sociale. - I dati della chiamata (
call_info) appartengono a quella telefonata. Sono il posto giusto per ciò che riguarda questo appuntamento: l'indirizzo del sopralluogo, il numero a cui richiamare. A fine chiamata li ritrovi nel campocallInfodel dettaglio della chiamata.
Restano fuori leadMetadata, lo storico delle chiamate e ciò che l'agente legge da un'integrazione, per esempio dal tuo gestionale. Un dato letto da un'integrazione entra solo se l'agente lo salva fra i dati della chiamata.
Come si scrive il percorso di un dato#
Il corpo della richiesta è in camelCase, come tutte le API di Aptiva. I percorsi dentro jmespath usano invece i nomi dell'oggetto qui sopra, in snake_case: lead_info.last_name, non lead_info.lastName; lead_info.additional_info, non lead_info.additionalInfo.
Le forme ammesse sono due:
- Un percorso: nomi separati da punti, a partire da
lead_info,callocall_info. Un nome con spazi o simboli si scrive fra virgolette doppie. - Più percorsi in alternativa, separati da
||: vale il primo che dà un valore. L'alternativa successiva entra in gioco quando la precedente manca, è vuota o valefalse.
| Percorso | Esito | Perché |
|---|---|---|
lead_ | Accettato | Un percorso di nomi |
call.context.pratica.codice | Accettato | Un percorso di nomi, a qualunque profondità |
call_ | Accettato | Due percorsi in alternativa |
lead_ | Accettato | Un nome con spazi, fra virgolette doppie |
length(lead_ | Rifiutato | Nessuna funzione |
call_ | Rifiutato | Nessun indice, filtro o proiezione |
lead_ | Rifiutato | Nessun valore fisso |
leads.email | Rifiutato | leads non è una delle tre radici |
lead.email | Rifiutato | La radice del contatto è lead_info, non lead |
La sintassi è quella di JMESPath, limitata a queste due forme. Un percorso che non le rispetta viene rifiutato al salvataggio con 422, mai durante una telefonata.
Il salvataggio controlla la forma, non che la chiave esista: lead_info.lastName in un dato facoltativo viene accettato e non dà mai un valore. Dopo aver salvato, controlla la descrizione di un evento di prova.
Quali dati possono essere obbligatori#
Un dato obbligatorio deve poter essere raccolto durante la telefonata. Per questo required a true è ammesso solo su un percorso singolo, fra quelli che l'agente sa salvare:
| Percorso | Dove l'agente salva il dato |
|---|---|
lead_info.name, lead_info.last_name, lead_info.email, lead_info.lead_company_name | Sul contatto |
lead_ | Nei campi liberi del contatto |
call_info.<chiave>, call_info.<chiave>.<sottochiave> | Fra i dati della chiamata |
lead_ | Non lo salva: il numero c'è sempre, tranne che per chi chiama con il numero nascosto |
Tutto il resto è ammesso solo come dato facoltativo: le alternative con ||, lead_info.id, i percorsi sotto call e i livelli più profondi di quelli della tabella. Un required a true su uno di questi risponde 422 con il tipo appointment_field_required_path_not_writable.
In lead_info.additional_info non possono essere obbligatorie le chiavi nome, cognome, e-mail, email_aziendale, ragione_sociale, name, last_name, email, lead_company_name e status. Per nome, cognome, email e azienda usa i percorsi del contatto: lead_info.name, lead_info.last_name, lead_info.email, lead_info.lead_company_name.
Il suggerimento per l'agente (hint)#
hint è una riga facoltativa di istruzioni per l'agente. Aptiva la aggiunge, così com'è, a ciò che l'agente riceve quando quel dato è obbligatorio e manca. Su un dato facoltativo si salva ma non ha effetto: di quel dato l'agente non riceve nulla, e a chiederlo deve pensare lo script. Il suggerimento serve quando «chiedilo» non basta:
- da dove prendere il dato: «Per un cliente già riconosciuto è l'indirizzo della sua scheda: chiedi solo conferma»;
- in che forma raccoglierlo: «Chiedi via, numero civico e comune»;
- che cosa farsi confermare: «Ripeti l'email lettera per lettera».
Come i messaggi del trasferimento di chiamata, è un'istruzione e non una frase letta parola per parola. Sta su una riga sola e ha al massimo 300 caratteri.
La durata dell'appuntamento#
durationMinutes è la durata, in minuti, di ogni appuntamento fissato dall'agente: da 5 a 480, a passi di 5. Un agente mai configurato fissa appuntamenti di 30 minuti.
La durata cambia due cose:
- Gli orari proposti. L'agente riceve solo gli intervalli liberi lunghi almeno quanto l'appuntamento, e propone un inizio che lasci posto all'appuntamento intero.
- L'evento sul calendario, che finisce all'ora di inizio più la durata.
La durata è una per agente: vale per ogni appuntamento che quell'agente fissa. L'orario in cui si fissa è fisso, dalle 9:00 alle 19:00: un appuntamento deve cominciare e finire in quella fascia. Un sopralluogo di un'ora alle 18:30 viene rifiutato.
Cosa compare nell'evento sul calendario#
La descrizione dell'evento comincia con la riga che Aptiva scrive da sempre. Seguono una riga vuota e una riga per ogni dato che ha un valore, nell'ordine dell'elenco, nella forma Etichetta: valore.
- Compare ogni dato che ha un valore, obbligatorio o no. Un dato facoltativo senza valore si salta.
- Un valore
trueofalsesi scrive «sì» o «no». Un elenco di valori si scrive separato da virgole. - Ogni valore sta su una riga. Oltre i 300 caratteri viene troncato, con «…» in fondo.
- Nelle righe dei dati i caratteri
<e>diventano‹e›: la descrizione è testo semplice. Il link di Google Meet, se c'è, resta in fondo. - Con un elenco vuoto la descrizione resta identica a prima.
La descrizione arriva anche all'invitato, insieme all'invito. Non mettere nell'elenco un dato che la persona non deve leggere, per esempio un codice interno passato in call.context.
Leggere la configurazione e tornare ai valori predefiniti#
La configurazione si legge con GET /agents/ID/appointment-settings:
curl -sS "https://api.aptiva.cloud/external/api/agents/42/appointment-settings" \
-H "X-API-Key: $APTIVA_API_KEY"
Un agente mai configurato risponde con i valori predefiniti:
{ "durationMinutes": 30, "fields": [] }
Due regole per le modifiche:
- Per aggiungere o togliere un dato, reinvia l'elenco intero. La
PUTsostituisce tutto, e l'ordine delle voci è quello dell'evento. La via più sicura è leggere conGET, modificare e reinviare. La risposta dellaGETsi può reinviare così com'è:hintanullequivale ad assente. - Ripetere la stessa richiesta non cambia nulla. Puoi inviarla a ogni rilascio del tuo sistema.
Non esiste una DELETE. Per tornare ai valori predefiniti invia la durata di 30 minuti e l'elenco vuoto:
curl -sS -X PUT "https://api.aptiva.cloud/external/api/agents/42/appointment-settings" \
-H "X-API-Key: $APTIVA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "durationMinutes": 30, "fields": [] }'
Codici di errore e cosa fare#
Tutti gli errori seguono il formato comune detail e code descritto nella guida ai primi passi.
code | Stato | Quando | Cosa fare |
|---|---|---|---|
not_ | 404 | L'agente non esiste o appartiene a un'altra azienda | Verifica l'ID nel pannello |
forbidden | 403 | Il tuo account non ha il permesso di leggere o modificare gli agenti | Usa un account con quel permesso, o scrivici |
validation_ | 422 | Corpo non valido: nulla viene salvato | Leggi details: ogni voce ha la posizione in loc e un type stabile |
AGENT_ | 409 | Configurazione salvata non coerente, non leggibile né aggiornabile in sicurezza | Scrivici con l'X-Request-ID |
Un errore di validazione indica la voce dell'elenco contando da zero. Qui il telefono dell'esempio del sopralluogo, seconda voce, è stato reso obbligatorio: ma un'alternativa con || può essere solo facoltativa.
{
"detail": "Validation failed",
"code": "validation_error",
"details": [
{
"type": "appointment_field_required_path_not_writable",
"loc": ["body", "fields", 1, "required"],
"msg": "a required field needs a path the agent can fill: `lead_info.name`, `lead_info.last_name`, `lead_info.email`, `lead_info.lead_company_name`, `lead_info.phone`, `lead_info.additional_info.<key>`, `call_info.<key>` or `call_info.<key>.<nested key>`",
"input": true
}
]
}
I valori di type da conoscere:
type | Dove | Cosa correggere |
|---|---|---|
greater_than_equal, less_than_equal, multiple_of, int_type | durationMinutes | Un intero da 5 a 480, multiplo di 5 |
too_ | fields | Al massimo 15 voci |
appointment_ | fields | Due etichette uguali: cambiane una |
string_too_short, string_too_long | label, jmespath, hint | Rispetta le lunghezze della tabella dei campi; un testo vuoto non è ammesso |
appointment_ | label, hint | Togli gli a capo: una riga sola |
appointment_ | jmespath | Il percorso ha un errore di sintassi |
appointment_ | jmespath | Usa un percorso di nomi, o più percorsi con ||: niente funzioni, indici, filtri o valori fissi |
appointment_ | jmespath | Il percorso deve partire da lead_info, call o call_info |
appointment_ | required | Scegli un percorso ammesso per i dati obbligatori, o metti required a false |
missing, extra_forbidden, bool_type | il campo indicato | Un campo obbligatorio manca, un campo non è previsto, required non è un booleano |
Limiti da conoscere#
- Numero nascosto. I dati di chi chiama con il numero nascosto non si salvano sul contatto. Se manca un dato obbligatorio del contatto, come
lead_info.email, l'agente non fissa e segue il tuo script; se lo script non dice nulla, raccoglie la richiesta e spiega che la persona verrà ricontattata per fissare l'appuntamento. Un dato obbligatorio della chiamata (call_info) funziona anche per il numero nascosto. Rendere obbligatoriolead_info.phoneequivale a non fissare appuntamenti a chi chiama con il numero nascosto. - Il controllo dice che il dato c'è, non che è esatto. Un'email dettata male resta un'email dettata male. Per questo l'agente è istruito a farsi confermare il dato che chiede.
- Nell'evento compare solo ciò che è stato salvato. Un'informazione che l'agente ha solo sentito, o che ha letto da un'integrazione, non compare finché l'agente non la salva sul contatto o fra i dati della chiamata. Per i dati obbligatori ci pensa il controllo. Per quelli facoltativi serve che lo script dica all'agente di salvarli, con la stessa chiave scritta nel percorso.
- Vale per Google Calendar collegato dal pannello. Se il tuo agente fissa gli appuntamenti su un altro sistema, per esempio l'agenda del tuo gestionale tramite un'integrazione su misura, questo controllo non si applica.
- L'orario è fisso. La fascia dalle 9:00 alle 19:00 non si configura.
Prossimi passi#
- Configura il tuo caso partendo da uno dei due esempi, poi fai una chiamata di prova: chiedi un appuntamento senza dare il dato obbligatorio e ascolta come l'agente lo chiede. Poi apri l'evento sul calendario e controlla la descrizione.
- Se l'agente non fissa ancora appuntamenti, collega Google Calendar dal pannello. Che cosa fa l'agente quando fissa lo trovi nella pagina Presa appuntamenti.
- Se i contatti nascono dal tuo sito o dal tuo CRM, passa già l'email quando crei il lead: l'agente non dovrà chiederla. Lo spiega API: creare lead e avviare chiamate. Se ti serve un dato o un comportamento che qui non trovi, scrivici dalla pagina Contatti.
Fonti
A cura di Redazione Aptiva
Costruiamo e gestiamo in casa la piattaforma di agenti vocali AI di Aptiva: queste guide nascono dall'esperienza diretta sul prodotto e sulle chiamate reali dei clienti.