Per sviluppatori
Collega Telofia ai sistemi che usi già
Leggi chiamate, trascrizioni, appuntamenti e contatti tramite REST API, ricevi webhook firmati appena succede qualcosa, lascia che l’assistente controlli dati in tempo reale nel tuo sistema durante la chiamata e aggiungi un assistente vocale al tuo sito con una riga di codice.
REST API e webhook sono inclusi in tutti i piani, da Line; i piani superiori hanno limiti più alti. Durante la prova gratuita hai un accesso di test: 1 chiave API, 20 richieste al minuto.
https://telofia.com/api/v1curl https://telofia.com/api/v1/me \
-H "Authorization: Bearer tf_live_…"{
"object": "account",
"id": "1f2e3d4c-5b6a-4789-8a7b-6c5d4e3f2a1b",
"name": "Smile Dental",
"timezone": "Europe/Warsaw",
"locale": "en",
"country": "PL",
"currency": "PLN",
"status": "active",
"plan": {
"id": "team",
"billing_cycle": "month",
"trial_ends_at": null,
"period_start": "2026-10-01T00:00:00Z",
"period_end": "2026-11-01T00:00:00Z",
"recording_history_days": 365
},
"minutes": {
"included": 3000,
"extra": 100,
"total": 3100,
"used": 412.5,
"remaining": 2687.5
},
"api_key_id": "2a3b4c5d-6e7f-4a8b-9c0d-1e2f3a4b5c6d",
"scopes": [
"read:calls",
"read:appointments",
"read:contacts",
"read:tasks"
],
"limits": {
"plan": "team",
"requests_per_minute": 180,
"requests_per_day": 50000,
"max_api_keys": 10,
"max_webhook_endpoints": 10
}
}Cosa puoi collegare
Sette modi per integrare Telofia nella tua attività
Scegli ciò che fa per te: automazioni senza codice, poche righe di codice o un’integrazione completa nei due sensi.
- In tutti i piani
REST API
Leggi chiamate con trascrizione e registrazione, appuntamenti, contatti e attività. Crea e aggiorna contatti, annulla o sposta appuntamenti e chiudi attività dal tuo sistema.
- In tutti i piani
Webhook
Eventi JSON firmati in tempo reale: chiamata iniziata o conclusa, appuntamento prenotato, annullato o spostato, nuovo contatto, richiesta di richiamata.
- In tutti i piani
Dati in diretta via MCP
Collega il tuo server MCP e l’assistente controlla giacenze, disponibilità o stato degli ordini durante la chiamata.
- Da Office
Widget vocale per il sito
Un tag script aggiunge il pulsante “Parla con noi”. I visitatori parlano con il tuo assistente dal browser.
- In tutti i piani
Onboarding telefonico
Invia le nuove registrazioni dal tuo sistema e l’assistente le chiama per aiutarle a iniziare.
- In tutti i piani
Calendario e CRM
Google Calendar per le prenotazioni, HubSpot e Pipedrive per contatti, chiamate, riunioni e attività.
- In tutti i piani
Zapier, Make, n8n
Flussi senza codice basati su webhook e API: Google Sheets, Slack, email, qualsiasi CRM.
Avvio rapido
La tua prima richiesta in due minuti
- 1
Crea una chiave API
Nella dashboard vai su Sviluppatori → Chiavi API, dai un nome alla chiave e scegli i permessi. La chiave (tf_live_…) viene mostrata una sola volta: salvala subito nel tuo gestore di segreti.
- 2
Prova la connessione
Chiama GET /me. Funziona con qualsiasi chiave valida e restituisce il tuo account, i permessi della chiave e i limiti del piano.
- 3
Leggi i dati o iscriviti agli eventi
Elenca chiamate, appuntamenti e contatti, oppure aggiungi un endpoint in Sviluppatori → Webhook per ricevere gli eventi in tempo reale.
curl https://telofia.com/api/v1/me \
-H "Authorization: Bearer tf_live_…"const API = "https://telofia.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.TELOFIA_API_KEY}` };
// All calls booked since 1 October, page by page
let cursor = null;
while (true) {
const url = new URL(`${API}/calls`);
url.searchParams.set("outcome", "booked");
url.searchParams.set("since", "2026-10-01T00:00:00Z");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, { headers });
if (res.status === 429) {
// rate limited: wait for the number of seconds in Retry-After, then retry the same page
await new Promise((r) => setTimeout(r, Number(res.headers.get("Retry-After") ?? 1) * 1000));
continue;
}
if (!res.ok) throw new Error((await res.json()).error.message);
const page = await res.json();
for (const call of page.data) console.log(call.started_at, call.from, call.summary);
if (!page.has_more) break;
cursor = page.next_cursor;
}REST API v1
Chiamate, appuntamenti e contatti via HTTPS
JSON in entrata e in uscita. Ogni richiesta è autenticata con una chiave API e ha i limiti del tuo piano. Le richieste compaiono nella dashboard (metodo, percorso, stato e durata, mai il contenuto di richieste o risposte).
Autenticazione
Crea una chiave in Chiavi API e inviala come token Bearer. Le chiavi iniziano con tf_live_ e appartengono a un solo account.
Authorization: Bearer tf_live_…Paginazione
Gli endpoint di elenco restituiscono fino a limit elementi (1–100, predefinito 25) in un ordine stabile. Se has_more è true, passa next_cursor invariato come cursor (con gli stessi filtri) per ottenere la pagina successiva. Un cursore non valido restituisce 400 invalid_request.
Errori
Gli errori usano i codici di stato HTTP standard e un corpo JSON con un tipo e un messaggio leggibile.
{ "error": { "type": "…", "message": "…" } }Endpoint
- GET
/mePermesso: qualsiasi chiaveRecupera l’account corrente
Restituisce l’account a cui appartiene la chiave API. Utile come chiamata di “test della connessione”.
- GET
/assistantsPermesso: qualsiasi chiaveElenca gli assistenti
I tuoi assistenti con lingua, stato e numeri di telefono assegnati. Usa l’id come assistant_id per filtrare le chiamate.
- GET
/assistants/{id}Permesso: qualsiasi chiaveRecupera un assistente
Un assistente con lingua, stato e numeri di telefono. Con lo scope read:assistants (o write:assistants) restituisce anche il prompt: instructions, greeting, company_profile e updated_at.
- PATCH
/assistants/{id}Permesso: write:assistantsModifica il prompt dell’assistente
Modifica istruzioni, saluto o profilo aziendale. I campi omessi restano invariati. Stessi limiti della dashboard: istruzioni fino a 20.000 caratteri, profilo fino a 10.000, saluto di 5–600 caratteri che deve dire che chi chiama parla con un’IA (altrimenti 400 con code ai_disclosure). Ogni modifica finisce nella cronologia versioni dell’assistente (origine API) e vale dalla chiamata successiva. Le regole di onestà della piattaforma (avviso IA e registrazione) valgono sempre.
- GET
/phone-numbersPermesso: qualsiasi chiaveElenca i numeri di telefono
I numeri di telefono dell’account con paese, tipo, stato e l’assistente che risponde.
- GET
/callsPermesso: read:callsElenca le chiamate
Chiamate dalla più recente, senza trascrizioni. Le chiamate demo non sono mai incluse.
- GET
/calls/{id}Permesso: read:callsRecupera una chiamata
Una singola chiamata con la trascrizione completa e gli appuntamenti prenotati durante la chiamata.
- GET
/calls/{id}/recordingPermesso: read:callsOttieni la registrazione di una chiamata
Link firmati (validi 1 ora) per ascoltare e scaricare la registrazione MP3 (stereo: chiamante a sinistra, assistente a destra). Una registrazione più vecchia dello storico del tuo piano restituisce 403 plan_required con recording_history_days; una chiamata senza registrazione restituisce 404.
- GET
/appointmentsPermesso: read:appointmentsElenca gli appuntamenti
Prossimi appuntamenti in ordine di inizio (per impostazione predefinita da adesso).
- GET
/appointments/{id}Permesso: read:appointmentsRecupera un appuntamento
Un appuntamento del tuo account.
- POST
/appointments/{id}/cancelPermesso: write:appointmentsAnnulla un appuntamento
Annulla un appuntamento futuro, lo rimuove dal calendario Google collegato e invia il webhook appointment.canceled. calendar_sync indica se il calendario è stato aggiornato.
- POST
/appointments/{id}/reschedulePermesso: write:appointmentsSposta un appuntamento
Sposta un appuntamento futuro a un nuovo orario. Risponde 409 se l’orario si sovrappone a un altro appuntamento o a un periodo occupato nel calendario collegato. Senza ends_at la durata resta invariata. Invia il webhook appointment.rescheduled.
- GET
/contactsPermesso: read:contactsElenca i contatti
Le persone che ti hanno chiamato, dalla più recente. L’assistente le riconosce da una chiamata all’altra.
- GET
/contacts/{id}Permesso: read:contactsRecupera un contatto
Un contatto con nome, email, tag, note e l’origine di nome ed email (call, system o manual).
- POST
/contactsPermesso: write:contactsCrea un contatto
Aggiunge un contatto, ad esempio dal tuo CRM, così l’assistente conosce il nome di chi chiama. Nome ed email salvati tramite API sono marcati manual e l’assistente non li sovrascrive mai. Restituisce 409 con contact_id se il numero esiste già. Invia il webhook contact.created.
- PATCH
/contacts/{id}Permesso: write:contactsAggiorna un contatto
Modifica nome, email, note o blocco. I campi omessi restano invariati e null svuota un campo. Un nome o un’email modificati sono marcati manual, quindi l’assistente non li sovrascriverà. Il numero di telefono non si può cambiare.
- GET
/tasksPermesso: read:tasksElenca le attività
Richieste di richiamata, messaggi e altre attività dalle chiamate, dalla più recente.
- GET
/tasks/{id}Permesso: read:tasksRecupera un’attività
Un’attività del tuo account.
- PATCH
/tasks/{id}Permesso: write:tasksAggiorna un’attività
Imposta lo stato dell’attività su open, done o dismissed, ad esempio dopo che il tuo team ha richiamato il cliente.
- POST
/calls/outboundPermesso: write:callsCrea una chiamata in uscita
Il tuo assistente chiama una persona dal numero della tua azienda con l’obiettivo che indichi, come un passaggio di una sequenza di onboarding. La chiamata parte subito o a call_at, sempre negli orari di chiamata (lun–sab, 9:00–20:00 nel fuso orario del tuo account; fuori orario viene spostata al primo momento consentito e call_at indica quando). Se nessuno risponde, riprova fino a 3 volte, a 2 ore di distanza. Restituisce 202 con la chiamata nello stato scheduled. Errori: 400 consent_missing, invalid_phone, number_not_callable, international o invalid_call_at; 409 opted_out (la persona ha chiesto di non essere chiamata), already_scheduled (con existing_id), assistant_not_live, over_quota o no_outbound_number; 429 daily_outbound_limit con limit (200 chiamate ogni 24 ore per impostazione predefinita). L’esito arriva nei webhook call.completed e outbound_call.finished con il tuo external_id.
- GET
/calls/outbound/{id}Permesso: write:callsRecupera una chiamata in uscita
Stato di una chiamata in uscita pianificata: scheduled, dialing, done (con il call_id della conversazione), failed (last_error, ad es. no_answer dopo tutti i tentativi) o canceled. Funziona anche con il callback_id dei webhook per le chiamate di onboarding e le richiamate.
- DELETE
/calls/outbound/{id}Permesso: write:callsAnnulla una chiamata in uscita
Annulla una chiamata in uscita creata tramite API che è ancora pianificata. Si può ripetere senza rischi (se è già annullata restituisce 200). Restituisce 409 not_cancelable se la chiamata è in composizione o conclusa, oppure per le chiamate di onboarding (in quel caso rimuovi la persona con POST /api/outreach/unenroll).
- GET
/messagesPermesso: read:messagesElenco SMS
SMS inviati dal tuo account e risposte dei clienti, dal più recente. phone è il numero del cliente (destinatario o mittente di una risposta). generated_by: template, ai o manual; charged_from: plan o credits.
- POST
/messagesPermesso: write:messagesInviare un SMS
Invia un SMS a uno dei tuoi contatti o chiamanti: un testo tuo o un modello del tuo account con vars (date, time, name, service, link, amount). Conta nel limite SMS del piano e negli SMS aggiuntivi. Errori: 400 invalid_request (consent_missing, invalid_phone, too_long, missing_vars); 409 conflict (opted_out — il cliente ha risposto STOP, over_quota, recipient_not_allowed — crea prima il contatto, blocked_destination); 429 rate_limited.
Permessi
Ogni chiave ha le autorizzazioni scelte alla creazione. Le autorizzazioni non si possono cambiare in seguito: se te ne servono altre, crea una nuova chiave. Se alla chiave manca l’autorizzazione richiesta, gli endpoint rispondono 403 insufficient_scope. GET /me, /assistants e /phone-numbers funzionano con qualsiasi chiave valida.
read:callsLeggere chiamate, riepiloghi e trascrizioniread:appointmentsLeggere appuntamentiwrite:appointmentsAnnullare e spostare appuntamentiread:contactsLeggere contattiwrite:contactsCreare e modificare contattiread:tasksLeggere attività e richieste di richiamatawrite:tasksCambiare lo stato delle attivitàwrite:callsAvviare chiamate in uscita, verificarle e annullarleread:messagesLeggere gli SMS e le risposte dei clientiwrite:messagesInviare SMS ai tuoi contattiread:assistantsLeggere il prompt dell’assistente (istruzioni, saluto, profilo aziendale)write:assistantsModificare il prompt dell’assistente
Errori
400invalid_request: un parametro manca o non è valido401unauthorized: chiave API mancante, non valida o revocata403insufficient_scope: alla chiave manca l’autorizzazione dell’endpoint; plan_required: l’account non ha un piano attivo oppure la registrazione è più vecchia dello storico registrazioni del piano404not_found: l’oggetto non esiste nel tuo account409conflict — l’orario è già occupato, l’appuntamento non può essere modificato, esiste già un contatto con questo numero oppure non è possibile effettuare una chiamata in uscita (code: opted_out, already_scheduled, assistant_not_live, over_quota, no_outbound_number, not_cancelable)429rate_limited — troppe richieste; riprova dopo il tempo indicato nell’intestazione Retry-After500server_error: si è verificato un problema da parte nostra503service_unavailable: problema temporaneo; riprova dopo il tempo indicato nell’header Retry-After
La documentazione completa dell’API, con parametri e risposte di esempio, è nella dashboard in Sviluppatori → Documentazione API.
Webhook
Eventi inviati al tuo server in tempo reale
Aggiungi un endpoint https nella dashboard, scegli gli eventi e invieremo una busta JSON firmata (POST) appena succede qualcosa. “Invia test” consegna un esempio del tuo primo evento, utile per mappare i campi in Zapier o Make.
Eventi
call.completedChiamata completataRiepilogo, esito, sentiment, trascrizione, contatto e prenotazioni; per le chiamate in uscita anche la sequenza o la richiesta API (callback_id, external_id, outreach).
call.startedChiamata iniziataÈ stata risposta una chiamata (in entrata, in uscita o dal web).
appointment.bookedAppuntamento prenotatoL’assistente ha prenotato un appuntamento.
appointment.canceledAppuntamento annullatoUn appuntamento è stato annullato al telefono o tramite API.
appointment.rescheduledAppuntamento spostatoUn appuntamento è stato spostato a un nuovo orario (con l’orario precedente).
task.createdRichiamata / attività creataChi ha chiamato ha chiesto una richiamata o ha lasciato un’attività.
contact.createdNuovo contattoUna persona che chiamava per la prima volta è stata salvata come contatto.
outbound_call.finishedChiamata in uscita conclusaUna chiamata in uscita pianificata (API, sequenza di onboarding o richiamata) è conclusa o non è riuscita, anche quando nessuno ha risposto dopo tutti i tentativi.
Intestazioni di ogni consegna
Telofia-SignatureFirma: t=<tempo unix>,v1=<HMAC-SHA256 hex>Telofia-EventTipo di evento, ad es. appointment.bookedTelofia-DeliveryID univoco della consegnaUser-AgentTelofia-Webhooks/1.0 · Identifica il nostro mittente dei webhook
Consegna e nuovi tentativi
- Rispondi con qualsiasi stato 2xx entro 10 secondi. I reindirizzamenti non vengono seguiti.
- Le consegne non riuscite vengono ripetute dopo 1 min, 5 min, 30 min, 2 h, 6 h e 12 h (7 tentativi, circa 21 ore).
- Lo stesso evento può arrivare più di una volta. Usa l’id dell’evento per scartare i duplicati.
- Sono accettati solo indirizzi https pubblici. Dopo 50 errori consecutivi l’endpoint viene messo in pausa e la dashboard ne spiega il motivo.
- La dashboard conserva un registro delle consegne con codici di stato e risposte e permette di ripetere una consegna a mano.
{
"id": "evt_3f9a1c7e5b2d4f6a8c0e1b3d5f7a9c1e",
"type": "call.completed",
"created_at": "2026-10-01T09:17:45Z",
"account_id": "1f2e3d4c-5b6a-4789-8a7b-6c5d4e3f2a1b",
"data": {
"id": "5b1f0c6e-2a8d-4f3e-9d51-7c0a4e2b9f10",
"object": "call",
"assistant_id": "0e6f4c8a-3b2d-4a1e-8f7c-5d9b2a1c3e4f",
"phone_number_id": "4d3c2b1a-0f9e-4d8c-b7a6-958473625140",
"contact_id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
"direction": "inbound",
"status": "completed",
"from": "+48601234567",
"to": "+48221234567",
"started_at": "2026-10-01T09:14:03Z",
"ended_at": "2026-10-01T09:17:41Z",
"duration_sec": 218,
"summary": "Anna Kowalska booked a first consultation for Friday 10:00.",
"outcome": "booked",
"sentiment": "positive",
"tags": [
"new-customer"
],
"has_recording": true,
"end_reason": "caller_hangup",
"callback_id": null,
"external_id": null,
"outreach": null,
"caller_spoke": true,
"caller_words": 6,
"transcript": [
{
"role": "caller",
"text": "I'd like to book a consultation this week.",
"at": 4.1
}
],
"contact": {
"id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
"object": "contact",
"phone": "+48601234567",
"name": "Anna Kowalska",
"name_source": "call",
"email": "anna.kowalska@example.com",
"email_source": "call",
"notes": null,
"tags": [
"customer"
],
"blocked": false,
"calls_count": 3,
"last_call_at": "2026-10-01T09:14:03Z",
"created_at": "2026-08-12T15:02:11Z"
},
"appointments": [
{
"id": "c3d2e1f0-a9b8-4c7d-8e6f-5a4b3c2d1e0f",
"object": "appointment",
"call_id": "5b1f0c6e-2a8d-4f3e-9d51-7c0a4e2b9f10",
"contact_id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
"customer_name": "Anna Kowalska",
"customer_phone": "+48601234567",
"customer_email": "anna.kowalska@example.com",
"service": "First consultation",
"starts_at": "2026-10-03T08:00:00Z",
"ends_at": "2026-10-03T08:30:00Z",
"status": "booked",
"external_id": "google:7h3k9s2l1m0n",
"created_at": "2026-10-01T09:16:20Z"
}
]
}
}Verifica delle firme. Ogni consegna include un header Telofia-Signature nel formato t=timestamp,v1=signature. Calcola l’HMAC-SHA256 di “timestamp.raw_body” con il tuo segreto di firma e confrontalo con v1. Rifiuta i timestamp più vecchi di 5 minuti.
import crypto from "node:crypto";
// Express: app.post("/webhook", express.raw({ type: "application/json" }), handler)
export function verify(rawBody, signatureHeader, secret) {
// Telofia-Signature: t=1727774265,v1=5f2c…
const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
const given = Buffer.from(parts.v1 ?? "");
// timingSafeEqual needs buffers of the same length
return fresh && given.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), given);
}import hmac, hashlib, time
def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in signature_header.split(","))
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
fresh = abs(time.time() - int(parts["t"])) < 300
return fresh and hmac.compare_digest(expected, parts.get("v1", ""))import express from "express";
import { verify } from "./verify.js";
const app = express();
const seen = new Set(); // use your database in production
app.post("/telofia/webhook", express.raw({ type: "application/json" }), (req, res) => {
const raw = req.body.toString("utf8");
if (!verify(raw, req.get("Telofia-Signature") ?? "", process.env.TELOFIA_WEBHOOK_SECRET)) return res.sendStatus(401);
const event = JSON.parse(raw);
if (seen.has(event.id)) return res.sendStatus(200); // retried delivery, already handled
seen.add(event.id);
if (event.type === "appointment.booked") {
const a = event.data;
console.log("New booking:", a.customer_name, a.service, a.starts_at);
}
res.sendStatus(200); // answer with 2xx within 10 seconds
});
app.listen(3000);Valori stabili
Questi valori nelle chiamate (API e webhook call.*) e nelle chiamate in uscita (outbound_call.finished, /calls/outbound) sono un contratto stabile: potremmo aggiungere nuovi valori, ma non modificheremo né rimuoveremo questi. I tentativi in uscita senza risposta, occupati o rifiutati non creano mai una chiamata, quindi per loro non c’è call.completed: dopo l’ultimo tentativo ricevi outbound_call.finished con last_error no_answer. Una chiamata a cui risponde la segreteria telefonica conta come risposta (di solito una chiamata breve con outcome other).
Stato della chiamata
in_progress- La chiamata è in corso.
completed- La persona ha parlato con l’assistente.
missed- Nessuno ha parlato, oppure l’assistente non ha potuto rispondere (vedi end_reason).
failed- Non è stato possibile gestire la chiamata a causa di un errore.
Esito della chiamata
booked- È stato prenotato un appuntamento.
transferred- La chiamata è stata trasferita a una persona.
message- È stato raccolto un messaggio, una richiesta di richiamata, un ordine o un follow-up.
info- La persona ha ricevuto informazioni; non serviva altro.
spam- Spam, telemarketing o numero bloccato.
other- Qualsiasi altro caso, ad es. una chiamata molto breve o la segreteria.
Motivo di fine chiamata (end_reason)
caller_hangup- L’altra persona ha riattaccato.
caller_hangup_greeting- Chiamata in uscita: la persona ha riattaccato durante il saluto o subito dopo, senza dire una parola (chiamata fino a 45 s). In questo caso caller_spoke è false.
agent_hangup- L’assistente ha chiuso la chiamata dopo i saluti.
transferred- La chiamata è stata trasferita a una persona.
silence- Terminata dopo un lungo silenzio.
max_duration- È stata raggiunta la durata massima della chiamata.
spam- Terminata come spam.
blocked- Il numero è bloccato nei contatti.
busy- Tutte le linee dell’account erano occupate.
over_quota- Minuti di chiamata esauriti.
trial_expired- La prova gratuita è terminata.
inactive- Nessun piano attivo.
assistant_not_live- L’assistente è in pausa.
no_assistant- Nessun assistente risponde a questo numero.
ai_budget- Gestita senza IA a causa di un limite temporaneo; al team è stato chiesto di richiamare.
error- Un errore tecnico ha chiuso la chiamata.
Stato della chiamata in uscita
scheduled- In attesa del suo orario (o del prossimo tentativo).
dialing- Sta chiamando ora.
done- Risposta; call_id è la conversazione.
failed- Nessuna risposta dopo tutti i tentativi, oppure non è stato possibile effettuarla (vedi last_error).
canceled- Annullata (API, persona rimossa dalla sequenza o sequenza disattivata).
last_error della chiamata in uscita
no_answer- Nessuno ha risposto (anche linea occupata o chiamata rifiutata).
failed- L’assistente non era disponibile al momento della chiamata (piano, minuti o pausa).
no_result- Nessun esito della chiamata entro 15 minuti.
expired- La chiamata era in ritardo di oltre 2 ore, quindi non è stata effettuata.
outside_window- Spostata ai prossimi orari di chiamata (lo stato resta scheduled).
dial_error- La rete telefonica ha rifiutato la chiamata (inviato come dial_<reason>).
over_quota- Minuti di chiamata esauriti.
inactive- Nessun piano attivo.
assistant_not_live- L’assistente è in pausa.
no_outbound_number- Nessun numero aziendale da cui chiamare.
canceled_by_api- Annullata con DELETE /calls/outbound/{id}.
unenrolled- La persona è stata rimossa dalla sequenza (POST /api/outreach/unenroll).
opt_out- La persona ha chiesto di non essere chiamata.
replaced- Sostituita da una richiamata più recente allo stesso numero.
Dati in diretta via MCP
L’assistente consulta il tuo sistema durante la chiamata
Collega un server MCP remoto (Model Context Protocol), come il catalogo del tuo negozio, il magazzino o il sistema di prenotazioni o ordini. Scegli tu esattamente quali strumenti e risorse (sola lettura) può usare l’assistente.
Impara in anticipo
Per contenuti che cambiano di rado, come listini, descrizioni dei prodotti o condizioni. Le risorse e gli strumenti di sola lettura scelti vengono importati nelle conoscenze dell’assistente ogni 1–168 ore o su richiesta. Nessun ritardo durante la chiamata.
Controlla in diretta in chiamata
Per ciò che cambia: giacenze, disponibilità, stato dell’ordine. L’assistente usa lo strumento durante la conversazione con un breve “un attimo, controllo”. Se il tuo server non risponde entro circa 2,5 secondi, dice che ora non può confermarlo e propone un ricontatto dal tuo team.
Cosa ti serve
- Un server MCP raggiungibile via https (Streamable HTTP, ad es. https://mcp.example.com/mcp; i vecchi server HTTP+SSE vengono rilevati automaticamente).
- Autenticazione: nessuna, un token Bearer o un’intestazione personalizzata come X-API-Key. I segreti sono cifrati (AES-256-GCM) e non arrivano mai al browser.
- Strumenti di sola lettura. Quelli segnati come distruttivi sono bloccati; per quelli non segnati come di sola lettura confermi che leggono soltanto dati.
- Fino a 5 fonti e 50 strumenti in diretta per assistente. I controlli in diretta dovrebbero rispondere in circa 2 secondi.
- Facoltativo per il widget del sito: in uno strumento «All’inizio della chiamata», scegli l’argomento che riceve il token di identità del visitatore che ha effettuato l’accesso (vedi Widget vocale per il sito).
Gli argomenti vengono validati con lo schema dello strumento, i risultati vengono accorciati e trattati solo come dati (mai come istruzioni) e ogni controllo viene registrato senza i dati di chi chiama. Gli indirizzi privati e interni vengono rifiutati.
Widget vocale per il sito
Il tuo assistente sul tuo sito, con una riga di codice
I visitatori cliccano un pulsante e parlano, dal browser, con lo stesso assistente che risponde al tuo telefono. Le chiamate web usano i minuti del piano, senza costi di telefonia.
Da Office
- Circa 14 KB, senza dipendenze, isolato in Shadow DOM: gli stili del tuo sito non possono romperlo.
- Parla la lingua della tua pagina (<html lang>) o quella impostata con data-lang="de".
- Sottotitoli in diretta; se il microfono è bloccato, il visitatore può scrivere e l’assistente risponde a voce.
- Limita il widget ai tuoi domini: si avvierà solo su quei siti.
<script src="https://telofia.com/widget.js" data-key="tfw_…" async></script>// optional: open the widget from your own button
document.querySelector("#talk-to-us").addEventListener("click", () => window.TelofiaWidget?.open());
window.TelofiaWidget?.close(); // close the panel
window.TelofiaWidget?.destroy(); // remove the widget from the pageHai una Content Security Policy restrittiva? Consenti script-src https://telofia.com https://cdn.jsdelivr.net, connect-src https://telofia.com wss://*.livekit.cloud https://*.livekit.cloud e media-src blob:.
Utenti che hanno effettuato l’accesso (token di identità)
Se i visitatori hanno effettuato l’accesso al tuo sito, l’assistente può sapere chi sta parlando senza chiedere l’e-mail.
- Il tuo server emette un token firmato e di breve durata per l’utente che ha effettuato l’accesso (es. HMAC, valido 15 minuti). Non mettere mai nel browser un indirizzo e-mail o un ID utente: chiunque potrebbe scrivere quello di un altro nella console.
- Chiama TelofiaWidget.identify({ token }) in qualsiasi momento; una chiamata successiva sostituisce il token e identify(null) lo cancella. Prima che widget.js sia caricato, imposta window.TelofiaIdentity = { token, expires_at }: viene letto all’inizio della conversazione e un token scaduto viene ignorato.
- Nella dashboard scegli l’argomento del token di identità nel tuo strumento MCP «All’inizio della chiamata». Telofia passa il token invariato solo a quell’argomento, non lo salva né lo mostra mai e lo tiene fuori da trascrizioni, riepiloghi, webhook e log; l’assistente non lo vede mai.
- Da 8 a 400 caratteri: lettere, cifre e . _ ~ + / = - (es. base64url). Rinnovalo prima della scadenza, per esempio ogni 10 minuti. Lo verifica il tuo server MCP; un token non valido o scaduto dovrebbe dare lo stesso risultato dell’assenza di token. Le chiamate telefoniche e le conversazioni senza token funzionano come prima.
// signed-in user: a short-lived, signed token issued by YOUR server (never an e-mail or user ID)
const { token, expires_at } = await fetch("/api/telofia-identity").then((r) => r.json());
window.TelofiaIdentity = { token, expires_at }; // read when the conversation starts, also before widget.js loads
window.TelofiaWidget?.identify({ token, expires_at }); // replaces the token at any time
// refresh before it expires (e.g. every 10 minutes); on sign-out:
window.TelofiaIdentity = null;
window.TelofiaWidget?.identify(null);Onboarding telefonico
I tuoi nuovi clienti ricevono in automatico una chiamata di benvenuto
Quando qualcuno si registra nel tuo sistema, inseriscilo in una sequenza di chiamate. L’assistente chiama dal numero della tua azienda, aiuta a iniziare e ricontatta qualche giorno dopo. Le chiamate partono negli orari di chiamata della sequenza: per impostazione predefinita dal lunedì al sabato, dalle 9:00 alle 20:00 nel tuo fuso orario, oppure nei giorni e negli orari che imposti.
POST/api/outreach/enroll
Autenticati con la chiave della sequenza (tlo_…) dalla dashboard, come token Bearer o nell’intestazione X-Telofia-Key. Ogni sequenza ha la sua chiave.
Corpo della richiesta
- Numero di telefono, meglio in formato E.164. I numeri nazionali vengono letti con il prefisso del paese del tuo account.
phonestringobbligatorio - Deve essere true: la persona ha accettato di essere contattata per telefono, ad es. nel tuo modulo di registrazione.
consenttrueobbligatorio - Nome, fino a 120 caratteri.
namestringfacoltativo - Indirizzo email.
emailstringfacoltativo - Cosa deve sapere l’assistente su questa persona, fino a 1.000 caratteri (ad es. il piano scelto).
contextstringfacoltativo - L’ID della persona nel tuo sistema (testo o numero). Lo stesso ID viene iscritto una sola volta.
external_idstring | numberfacoltativo
curl -X POST "https://telofia.com/api/outreach/enroll" \
-H "Authorization: Bearer tlo_…" \
-H "Content-Type: application/json" \
-d '{"phone":"+48601234567","name":"Anna Kowalska","email":"anna@example.com","context":"Signed up today, Start plan","external_id":"user_123","consent":true}'{
"ok": true,
"enrollment_id": "8f7e6d5c-4b3a-4c2d-9e1f-0a9b8c7d6e5f",
"external_id": "user_123",
"status": "active",
"next_call_at": "2026-10-09T10:20:00Z",
"limits": {
"per_day": 500,
"remaining_today": 499
}
}Risposte
- 201: iscritta. enrollment_id, external_id, status, next_call_at (orario della prima chiamata), intro_sms_at (quando parte l’SMS prima della prima chiamata, oppure null) e limits { per_day, remaining_today }
- 200: già iscritta (stesso external_id, oppure questo numero è già in corso nella sequenza), con duplicate: true
- 400: invalid_request, invalid_phone o consent_required
- 401: invalid_key
- 409: sequence_disabled, consent_missing o opted_out (la persona non vuole essere chiamata)
- 429: limit, raggiunto il limite giornaliero di iscrizioni della sequenza (500 nuove persone ogni 24 ore; il corpo contiene limit). rate_limited: più di 120 richieste al minuto con questa chiave (intestazione Retry-After)
Orari di chiamata: nella dashboard imposta per ogni sequenza i giorni e una fascia oraria tra le 7:00 e le 21:00. Se nessuno risponde, l’assistente riprova fino a 3 volte, a 2 ore di distanza, entro quegli orari.
SMS prima della chiamata: se è attivo nella sequenza (dashboard), la persona riceve un breve messaggio dal numero da cui chiamerà l’assistente, per impostazione predefinita 20 minuti prima della prima chiamata (5–120 min). Se la prima chiamata cadesse prima, viene spostata in modo che l’SMS parta sempre per primo, entro gli orari di chiamata. Un SMS non riuscito (la persona ha risposto STOP, gli SMS a disposizione sono esauriti) non blocca mai la chiamata. Ogni SMS viene scalato dagli SMS a tua disposizione e compare nella dashboard, nella sezione SMS.
Saluto: nella dashboard imposti la prima frase della chiamata per ogni passaggio (o come predefinita per l’intera sequenza) — un testo fisso con le variabili {first_name}, {first_name_vocative} (vocativo polacco, ad es. Krystianie), {assistant_name}, Telofia (nome dell’azienda nelle chiamate, dalle impostazioni dell’assistente) e {name}, con una variante a parte per le iscrizioni senza nome — oppure una modalità in cui l’assistente scrive la prima frase da name, context, obiettivo del passaggio e risultato degli strumenti «All’inizio della chiamata». Che chiama un assistente IA e che la chiamata è registrata viene sempre aggiunto alla prima frase se il testo non lo dice.
Rimuovere una persona dalla sequenza
POST/api/outreach/unenroll
Quando qualcuno non ha più bisogno delle chiamate (ad es. dopo la prima vendita o se ha disdetto), interrompi la sua sequenza con la stessa chiave. Le chiamate pianificate vengono annullate subito. Una chiamata già in corso non viene interrotta, ma non ne seguono altre.
- Esattamente uno tra: external_id (come inviato all’iscrizione), enrollment_id (dalla risposta dell’iscrizione) o phone.
external_id | enrollment_id | phoneobbligatorio - Motivo facoltativo, fino a 200 caratteri, conservato nel registro di audit del tuo account.
reasonfacoltativo
- 200: interrotta (changed: true) o già conclusa: status stopped, completed o failed (changed: false). Si può ripetere senza rischi.
- 400: invalid_request (nessun identificativo o più di uno) o invalid_phone
- 401: invalid_key
- 404: not_found, nessuna iscrizione corrispondente in questa sequenza
- 429: rate_limited
curl -X POST "https://telofia.com/api/outreach/unenroll" \
-H "Authorization: Bearer tlo_…" \
-H "Content-Type: application/json" \
-d '{"external_id":"user_123","reason":"first_sale"}'{
"ok": true,
"enrollment_id": "8f7e6d5c-4b3a-4c2d-9e1f-0a9b8c7d6e5f",
"external_id": "user_123",
"status": "stopped",
"changed": true
}Esiti delle chiamate nei webhook
call.started e call.completed per le chiamate di una sequenza contengono callback_id, external_id e outreach { sequence_id, enrollment_id, external_id, step } (tutti null per le chiamate in entrata). I tentativi senza risposta non creano una chiamata, quindi per loro non c’è call.completed: dopo l’ultimo tentativo ricevi outbound_call.finished con status failed e last_error no_answer. I nuovi tentativi di uno stesso passaggio contano come un unico esito. call.completed include anche caller_spoke e caller_words (quante parole ha detto la persona). Se qualcuno ha risposto e ha riattaccato durante il saluto o subito dopo senza dire nulla, end_reason è caller_hangup_greeting.
{
"id": "5b1f0c6e-2a8d-4f3e-9d51-7c0a4e2b9f10",
"object": "call",
"assistant_id": "0e6f4c8a-3b2d-4a1e-8f7c-5d9b2a1c3e4f",
"phone_number_id": "4d3c2b1a-0f9e-4d8c-b7a6-958473625140",
"contact_id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
"direction": "outbound",
"status": "completed",
"from": "+48732127980",
"to": "+48601234567",
"started_at": "2026-10-01T09:14:03Z",
"ended_at": "2026-10-01T09:17:41Z",
"duration_sec": 218,
"summary": "Jan added the company name and tax ID; asked for a call tomorrow at 10:00 about payments.",
"outcome": "message",
"sentiment": "positive",
"tags": [],
"has_recording": true,
"end_reason": "agent_hangup",
"callback_id": "0f1e2d3c-4b5a-4968-8776-655443322110",
"external_id": "gapli-evt-1842",
"outreach": {
"sequence_id": "11111111-1111-4111-8111-111111111111",
"enrollment_id": "8f7e6d5c-4b3a-4c2d-9e1f-0a9b8c7d6e5f",
"external_id": "gapli-evt-1842",
"step": 1
},
"caller_spoke": true,
"caller_words": 112
}Calendario, CRM e automazioni
Integrazioni pronte, senza codice
Google Calendar
L’assistente verifica la disponibilità reale e prenota, sposta e annulla gli appuntamenti nel tuo calendario. Legge solo gli orari occupati, mai i titoli degli eventi.
HubSpot
Ogni chiamata viene registrata sul contatto, le prenotazioni diventano riunioni e le richiamate attività. Facoltativamente crea contatti e trattative.
Pipedrive
Chiamate come attività o note, prenotazioni come riunioni, richiamate come attività. Facoltativamente crea persone, trattative o lead.
Zapier, Make e n8n
Guide passo passo nella dashboard. Si basano su webhook e API, inclusi in tutti i piani.
Piani e limiti
Di quale piano hai bisogno
Limiti per account: richieste al minuto (anche per chiave, finestra mobile) e al giorno (UTC). Oltre il limite ricevi 429 rate_limited con l’intestazione Retry-After.
Widget vocale per il sito: dal piano Office.
Ti servono limiti più alti? Scrivici e possiamo aumentarli per il tuo account.
Accesso anticipato: sii tra le prime attività ad affidare il telefono all’IA.
Pronto a collegarti?
Inizia la prova gratuita, crea una chiave API di test e invia la tua prima richiesta in pochi minuti. L’API è inclusa in tutti i piani, da Line.