Vai al contenuto

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.

URL di base dell’API
https://telofia.com/api/v1
curl · Prova la chiave
curl https://telofia.com/api/v1/me \
  -H "Authorization: Bearer tf_live_…"
200 OK
{
  "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
  }
}

Avvio rapido

La tua prima richiesta in due minuti

  1. 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. 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. 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 · Prova la chiave
curl https://telofia.com/api/v1/me \
  -H "Authorization: Bearer tf_live_…"
JavaScript: tutte le chiamate con prenotazione, pagina per pagina
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 chiave

    Recupera l’account corrente

    Restituisce l’account a cui appartiene la chiave API. Utile come chiamata di “test della connessione”.

  • GET/assistantsPermesso: qualsiasi chiave

    Elenca 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 chiave

    Recupera 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:assistants

    Modifica 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 chiave

    Elenca i numeri di telefono

    I numeri di telefono dell’account con paese, tipo, stato e l’assistente che risponde.

  • GET/callsPermesso: read:calls

    Elenca le chiamate

    Chiamate dalla più recente, senza trascrizioni. Le chiamate demo non sono mai incluse.

  • GET/calls/{id}Permesso: read:calls

    Recupera una chiamata

    Una singola chiamata con la trascrizione completa e gli appuntamenti prenotati durante la chiamata.

  • GET/calls/{id}/recordingPermesso: read:calls

    Ottieni 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:appointments

    Elenca gli appuntamenti

    Prossimi appuntamenti in ordine di inizio (per impostazione predefinita da adesso).

  • GET/appointments/{id}Permesso: read:appointments

    Recupera un appuntamento

    Un appuntamento del tuo account.

  • POST/appointments/{id}/cancelPermesso: write:appointments

    Annulla 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:appointments

    Sposta 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:contacts

    Elenca 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:contacts

    Recupera un contatto

    Un contatto con nome, email, tag, note e l’origine di nome ed email (call, system o manual).

  • POST/contactsPermesso: write:contacts

    Crea 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:contacts

    Aggiorna 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:tasks

    Elenca le attività

    Richieste di richiamata, messaggi e altre attività dalle chiamate, dalla più recente.

  • GET/tasks/{id}Permesso: read:tasks

    Recupera un’attività

    Un’attività del tuo account.

  • PATCH/tasks/{id}Permesso: write:tasks

    Aggiorna 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:calls

    Crea 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:calls

    Recupera 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:calls

    Annulla 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:messages

    Elenco 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:messages

    Inviare 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 trascrizioni
  • read:appointmentsLeggere appuntamenti
  • write:appointmentsAnnullare e spostare appuntamenti
  • read:contactsLeggere contatti
  • write:contactsCreare e modificare contatti
  • read:tasksLeggere attività e richieste di richiamata
  • write:tasksCambiare lo stato delle attività
  • write:callsAvviare chiamate in uscita, verificarle e annullarle
  • read:messagesLeggere gli SMS e le risposte dei clienti
  • write:messagesInviare SMS ai tuoi contatti
  • read:assistantsLeggere il prompt dell’assistente (istruzioni, saluto, profilo aziendale)
  • write:assistantsModificare il prompt dell’assistente

Errori

  • 400invalid_request: un parametro manca o non è valido
  • 401unauthorized: chiave API mancante, non valida o revocata
  • 403insufficient_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 piano
  • 404not_found: l’oggetto non esiste nel tuo account
  • 409conflict — 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-After
  • 500server_error: si è verificato un problema da parte nostra
  • 503service_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 completata

    Riepilogo, 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 prenotato

    L’assistente ha prenotato un appuntamento.

  • appointment.canceledAppuntamento annullato

    Un appuntamento è stato annullato al telefono o tramite API.

  • appointment.rescheduledAppuntamento spostato

    Un appuntamento è stato spostato a un nuovo orario (con l’orario precedente).

  • task.createdRichiamata / attività creata

    Chi ha chiamato ha chiesto una richiamata o ha lasciato un’attività.

  • contact.createdNuovo contatto

    Una persona che chiamava per la prima volta è stata salvata come contatto.

  • outbound_call.finishedChiamata in uscita conclusa

    Una 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.booked
  • Telofia-DeliveryID univoco della consegna
  • User-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.
Consegna di esempio: call.completed
{
  "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.

Node.js · Verifica la firma
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);
}
Python · Verifica la firma
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", ""))
Ricevitore di esempio (Express)
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.
Codice da incorporare (la chiave è nella dashboard)
<script src="https://telofia.com/widget.js" data-key="tfw_…" async></script>
API JavaScript
// 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 page

Hai 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.
Token di identità
// 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

  • phonestringobbligatorio
    Numero di telefono, meglio in formato E.164. I numeri nazionali vengono letti con il prefisso del paese del tuo account.
  • consenttrueobbligatorio
    Deve essere true: la persona ha accettato di essere contattata per telefono, ad es. nel tuo modulo di registrazione.
  • namestringfacoltativo
    Nome, fino a 120 caratteri.
  • emailstringfacoltativo
    Indirizzo email.
  • contextstringfacoltativo
    Cosa deve sapere l’assistente su questa persona, fino a 1.000 caratteri (ad es. il piano scelto).
  • external_idstring | numberfacoltativo
    L’ID della persona nel tuo sistema (testo o numero). Lo stesso ID viene iscritto una sola volta.
curl
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}'
201 Created
{
  "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.

  • external_id | enrollment_id | phoneobbligatorio
    Esattamente uno tra: external_id (come inviato all’iscrizione), enrollment_id (dalla risposta dell’iscrizione) o phone.
  • reasonfacoltativo
    Motivo facoltativo, fino a 200 caratteri, conservato nel registro di audit del tuo account.
  • 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
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"}'
200 OK
{
  "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.

call.completed per una chiamata di sequenza
{
  "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.

PianoRichieste / minRichieste / giornoChiavi APIWebhook
Prova gratuita (accesso di test)20100011
Line30200022
Desk6010.00055
Office18050.0001010
Network600200.0002520

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.