Pour les développeurs
Connectez Telofia aux outils que vous utilisez déjà
Récupérez appels, transcriptions, rendez-vous et contacts via une API REST, recevez des webhooks signés dès que quelque chose se produit, laissez l’assistant consulter vos données en direct pendant l’appel et ajoutez un assistant vocal à votre site en une ligne de code.
L’API REST et les webhooks sont inclus dans tous les forfaits, dès Line ; les forfaits supérieurs ont des limites plus élevées. Pendant l’essai gratuit, vous avez un accès de test : 1 clé API, 20 requêtes par minute.
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
}
}Ce que vous pouvez connecter
Sept façons d’intégrer Telofia à votre activité
Choisissez ce qui vous convient : automatisations sans code, quelques lignes de code ou intégration complète dans les deux sens.
- Tous les forfaits
API REST
Récupérez les appels avec transcription et enregistrement, les rendez-vous, les contacts et les tâches. Créez et modifiez des contacts, annulez ou déplacez des rendez-vous et clôturez des tâches depuis votre propre système.
- Tous les forfaits
Webhooks
Événements JSON signés en temps réel : appel commencé ou terminé, rendez-vous pris, annulé ou déplacé, nouveau contact, demande de rappel.
- Tous les forfaits
Données en direct via MCP
Connectez votre serveur MCP : l’assistant vérifie le stock, la disponibilité ou le statut d’une commande pendant l’appel.
- Dès Office
Widget vocal pour votre site
Une balise script ajoute un bouton « Parlez-nous ». Les visiteurs parlent à votre assistant dans le navigateur.
- Tous les forfaits
Onboarding téléphonique
Envoyez les nouvelles inscriptions depuis votre système : l’assistant les appelle pour les aider à démarrer.
- Tous les forfaits
Agenda et CRM
Google Agenda pour les réservations, HubSpot et Pipedrive pour les contacts, appels, réunions et tâches.
- Tous les forfaits
Zapier, Make, n8n
Scénarios sans code basés sur les webhooks et l’API : Google Sheets, Slack, e-mail, n’importe quel CRM.
Démarrage rapide
Votre première requête en deux minutes
- 1
Créez une clé API
Dans le tableau de bord, ouvrez Développeurs → Clés API, nommez la clé et choisissez ses autorisations. La clé (tf_live_…) n’est affichée qu’une fois : enregistrez-la tout de suite dans votre gestionnaire de secrets.
- 2
Testez la connexion
Appelez GET /me. Cela fonctionne avec toute clé valide et renvoie votre compte, les autorisations de la clé et les limites de votre forfait.
- 3
Lisez les données ou abonnez-vous aux événements
Listez appels, rendez-vous et contacts, ou ajoutez un point de réception dans Développeurs → Webhooks pour recevoir les événements en direct.
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;
}API REST v1
Appels, rendez-vous et contacts via HTTPS
Du JSON en entrée comme en sortie. Chaque requête est authentifiée par une clé API et limitée selon votre forfait. Les requêtes apparaissent dans le tableau de bord (méthode, chemin, statut et durée — jamais le contenu des requêtes ni des réponses).
Authentification
Créez une clé dans Clés API et envoyez-la comme jeton Bearer. Les clés commencent par tf_live_ et sont liées à un seul compte.
Authorization: Bearer tf_live_…Pagination
Les endpoints de liste renvoient jusqu’à limit éléments (1–100, 25 par défaut) dans un ordre stable. Si has_more vaut true, passez next_cursor tel quel comme cursor (avec les mêmes filtres) pour obtenir la page suivante. Un curseur invalide renvoie 400 invalid_request.
Erreurs
Les erreurs utilisent les codes de statut HTTP standard et un corps JSON contenant un type et un message lisible.
{ "error": { "type": "…", "message": "…" } }Points de terminaison
- GET
/meAutorisation: toute cléRécupérer le compte actuel
Renvoie le compte auquel appartient la clé API. Pratique pour « tester la connexion ».
- GET
/assistantsAutorisation: toute cléLister les assistants
Vos assistants avec leur langue, leur statut et les numéros de téléphone attribués. Utilisez l’id comme assistant_id pour filtrer les appels.
- GET
/assistants/{id}Autorisation: toute cléRécupérer un assistant
Un assistant avec sa langue, son statut et ses numéros. Avec le scope read:assistants (ou write:assistants), renvoie aussi le prompt : instructions, greeting, company_profile et updated_at.
- PATCH
/assistants/{id}Autorisation: write:assistantsModifier le prompt de l’assistant
Modifie les instructions, l’accueil ou le profil de l’entreprise. Les champs omis restent inchangés. Mêmes limites que dans le tableau de bord : instructions jusqu’à 20 000 caractères, profil jusqu’à 10 000, accueil de 5 à 600 caractères qui doit indiquer que l’appelant parle à une IA (sinon 400 avec code ai_disclosure). Chaque modification est enregistrée dans l’historique des versions (source API) et s’applique dès le prochain appel. Les règles d’honnêteté de la plateforme (mention de l’IA et de l’enregistrement) s’appliquent toujours.
- GET
/phone-numbersAutorisation: toute cléLister les numéros de téléphone
Les numéros de téléphone de votre compte avec pays, type, statut et l’assistant qui y répond.
- GET
/callsAutorisation: read:callsLister les appels
Les appels, du plus récent au plus ancien, sans transcription. Les appels de démo ne sont jamais inclus.
- GET
/calls/{id}Autorisation: read:callsRécupérer un appel
Un appel avec sa transcription complète et les rendez-vous pris pendant l’appel.
- GET
/calls/{id}/recordingAutorisation: read:callsObtenir l’enregistrement d’un appel
Liens signés (valables 1 heure) pour écouter et télécharger l’enregistrement MP3 (stéréo : appelant à gauche, assistant à droite). Un enregistrement plus ancien que l’historique de votre forfait renvoie 403 plan_required avec recording_history_days ; un appel sans enregistrement renvoie 404.
- GET
/appointmentsAutorisation: read:appointmentsLister les rendez-vous
Les rendez-vous à venir, par ordre chronologique (à partir de maintenant par défaut).
- GET
/appointments/{id}Autorisation: read:appointmentsRécupérer un rendez-vous
Un rendez-vous de votre compte.
- POST
/appointments/{id}/cancelAutorisation: write:appointmentsAnnuler un rendez-vous
Annule un rendez-vous à venir, le retire du calendrier Google connecté et envoie le webhook appointment.canceled. calendar_sync indique si le calendrier a été mis à jour.
- POST
/appointments/{id}/rescheduleAutorisation: write:appointmentsDéplacer un rendez-vous
Déplace un rendez-vous à venir vers un nouvel horaire. Répond 409 si le créneau chevauche un autre rendez-vous ou une période occupée du calendrier connecté. Sans ends_at, la durée reste la même. Envoie le webhook appointment.rescheduled.
- GET
/contactsAutorisation: read:contactsLister les contacts
Vos appelants, du plus récent au plus ancien. L’assistant s’en souvient d’un appel à l’autre.
- GET
/contacts/{id}Autorisation: read:contactsRécupérer un contact
Un contact avec nom, e-mail, tags, notes et l’origine du nom et de l’e-mail (call, system ou manual).
- POST
/contactsAutorisation: write:contactsCréer un contact
Ajoute un contact, par exemple depuis votre CRM, pour que l’assistant connaisse le nom de l’appelant. Le nom et l’e-mail enregistrés via l’API sont marqués manual et l’assistant ne les écrase jamais. Renvoie 409 avec contact_id si le numéro existe déjà. Envoie le webhook contact.created.
- PATCH
/contacts/{id}Autorisation: write:contactsModifier un contact
Modifie le nom, l’e-mail, les notes ou le blocage. Les champs omis restent inchangés et null vide un champ. Un nom ou un e-mail modifié est marqué manual, l’assistant ne l’écrasera donc pas. Le numéro de téléphone ne peut pas être modifié.
- GET
/tasksAutorisation: read:tasksLister les tâches
Demandes de rappel, messages et autres tâches issues des appels, des plus récentes aux plus anciennes.
- GET
/tasks/{id}Autorisation: read:tasksRécupérer une tâche
Une tâche de votre compte.
- PATCH
/tasks/{id}Autorisation: write:tasksModifier une tâche
Passe le statut de la tâche à open, done ou dismissed, par exemple une fois que votre équipe a rappelé le client.
- POST
/calls/outboundAutorisation: write:callsCréer un appel sortant
Votre assistant appelle une personne depuis le numéro de votre entreprise avec l’objectif que vous indiquez, comme une étape d’une séquence d’onboarding. L’appel part maintenant ou à call_at, toujours pendant les horaires d’appel (lun–sam, 9 h–20 h dans le fuseau horaire de votre compte ; en dehors, il est reporté au prochain créneau autorisé et call_at indique quand). Sans réponse, il réessaie jusqu’à 3 fois, à 2 heures d’intervalle. Renvoie 202 avec l’appel au statut scheduled. Erreurs : 400 consent_missing, invalid_phone, number_not_callable, international ou invalid_call_at ; 409 opted_out (la personne ne souhaite pas être appelée), already_scheduled (avec existing_id), assistant_not_live, over_quota ou no_outbound_number ; 429 daily_outbound_limit avec limit (200 appels par 24 heures par défaut). Le résultat arrive dans les webhooks call.completed et outbound_call.finished avec votre external_id.
- GET
/calls/outbound/{id}Autorisation: write:callsRécupérer un appel sortant
Statut d’un appel sortant planifié : scheduled, dialing, done (avec le call_id de la conversation), failed (last_error, p. ex. no_answer après toutes les tentatives) ou canceled. Fonctionne aussi avec le callback_id des webhooks pour les appels d’onboarding et les rappels.
- DELETE
/calls/outbound/{id}Autorisation: write:callsAnnuler un appel sortant
Annule un appel sortant créé via l’API qui est encore planifié. Peut être répété sans risque (un appel déjà annulé renvoie 200). Renvoie 409 not_cancelable si l’appel est en cours de numérotation ou terminé, ou pour les appels d’onboarding (retirez plutôt la personne avec POST /api/outreach/unenroll).
- GET
/messagesAutorisation: read:messagesLister les SMS
SMS envoyés par votre compte et réponses des clients, du plus récent au plus ancien. phone est le numéro du client (destinataire ou expéditeur d’une réponse). generated_by : template, ai ou manual ; charged_from : plan ou credits.
- POST
/messagesAutorisation: write:messagesEnvoyer un SMS
Envoie un SMS à l’un de vos contacts ou appelants : votre propre texte, ou un modèle de votre compte avec vars (date, time, name, service, link, amount). Compte dans le forfait SMS de votre offre et les SMS supplémentaires. Erreurs : 400 invalid_request (consent_missing, invalid_phone, too_long, missing_vars) ; 409 conflict (opted_out — le client a répondu STOP, over_quota, recipient_not_allowed — créez d’abord le contact, blocked_destination) ; 429 rate_limited.
Autorisations
Chaque clé a les portées choisies lors de sa création. Les portées ne peuvent pas être modifiées ensuite : créez une nouvelle clé si vous avez besoin de plus. Si la clé n’a pas la portée requise, les endpoints répondent 403 insufficient_scope. GET /me, /assistants et /phone-numbers fonctionnent avec toute clé valide.
read:callsLire les appels, résumés et transcriptionsread:appointmentsLire les rendez-vouswrite:appointmentsAnnuler et déplacer des rendez-vousread:contactsLire les contactswrite:contactsCréer et modifier des contactsread:tasksLire les tâches et demandes de rappelwrite:tasksModifier le statut des tâcheswrite:callsLancer des appels sortants, les consulter et les annulerread:messagesLire les SMS et les réponses des clientswrite:messagesEnvoyer des SMS à vos contactsread:assistantsLire le prompt de l’assistant (instructions, accueil, profil de l’entreprise)write:assistantsModifier le prompt de l’assistant
Erreurs
400invalid_request — un paramètre est manquant ou invalide401unauthorized — clé API manquante, invalide ou révoquée403insufficient_scope — la clé n’a pas la portée requise par l’endpoint ; plan_required — le compte n’a pas de forfait actif ou l’enregistrement est plus ancien que l’historique d’enregistrements du forfait404not_found — l’objet n’existe pas dans votre compte409conflict — le créneau est déjà pris, le rendez-vous ne peut pas être modifié, un contact avec ce numéro existe déjà, ou un appel sortant ne peut pas être passé (code : opted_out, already_scheduled, assistant_not_live, over_quota, no_outbound_number, not_cancelable)429rate_limited — trop de requêtes ; réessayez après le délai indiqué par l’en-tête Retry-After500server_error — une erreur s’est produite de notre côté503service_unavailable — problème temporaire ; réessayez après le délai indiqué dans l’en-tête Retry-After
La référence complète de l’API, avec paramètres et exemples de réponses, se trouve dans le tableau de bord : Développeurs → Référence de l’API.
Webhooks
Des événements envoyés à votre serveur en temps réel
Ajoutez une adresse https dans le tableau de bord, choisissez les événements, et nous envoyons une enveloppe JSON signée (POST) dès que quelque chose se produit. « Envoyer un test » livre un exemple de votre premier événement, pratique pour mapper les champs dans Zapier ou Make.
Événements
call.completedAppel terminéRésumé, résultat, ressenti, transcription, contact et rendez-vous ; pour les appels sortants, également la séquence ou la requête API (callback_id, external_id, outreach).
call.startedAppel commencéUn appel a été décroché (entrant, sortant ou web).
appointment.bookedRendez-vous prisL’assistant a pris un rendez-vous.
appointment.canceledRendez-vous annuléUn rendez-vous a été annulé par téléphone ou via l’API.
appointment.rescheduledRendez-vous déplacéUn rendez-vous a été déplacé à un nouvel horaire (avec l’horaire précédent).
task.createdRappel / tâche crééUn appelant a demandé à être rappelé ou a laissé une tâche.
contact.createdNouveau contactUn nouvel appelant a été enregistré comme contact.
outbound_call.finishedAppel sortant terminéUn appel sortant planifié (API, séquence d’onboarding ou rappel) est terminé ou a échoué — y compris quand personne n’a répondu après toutes les tentatives.
En-têtes de chaque livraison
Telofia-SignatureSignature : t=<temps unix>,v1=<HMAC-SHA256 hex>Telofia-EventType d’événement, p. ex. appointment.bookedTelofia-DeliveryIdentifiant unique de la livraisonUser-AgentTelofia-Webhooks/1.0 · Identifie notre expéditeur de webhooks
Livraison et nouvelles tentatives
- Répondez avec n’importe quel statut 2xx en moins de 10 secondes. Les redirections ne sont pas suivies.
- Les livraisons échouées sont relancées après 1 min, 5 min, 30 min, 2 h, 6 h et 12 h (7 tentatives, environ 21 heures).
- Un même événement peut arriver plusieurs fois. Utilisez l’id de l’événement pour ignorer les doublons.
- Seules les adresses https publiques sont acceptées. Après 50 échecs consécutifs, le point de réception est mis en pause et le tableau de bord en indique la raison.
- Le tableau de bord conserve un journal des livraisons avec codes de statut et réponses, et permet de relancer une livraison à la main.
{
"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"
}
]
}
}Vérifier les signatures. Chaque envoi comporte un en-tête Telofia-Signature au format t=timestamp,v1=signature. Calculez le HMAC-SHA256 de « timestamp.raw_body » avec votre secret de signature et comparez-le à v1. Rejetez les horodatages de plus de 5 minutes.
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);Valeurs stables
Ces valeurs dans les appels (API et webhooks call.*) et dans les appels sortants (outbound_call.finished, /calls/outbound) constituent un contrat stable : nous pouvons ajouter de nouvelles valeurs, mais nous ne modifierons ni ne supprimerons celles-ci. Les tentatives sortantes sans réponse, occupées ou rejetées ne créent jamais d’appel, il n’y a donc pas de call.completed pour elles : vous recevez outbound_call.finished avec last_error no_answer après la dernière tentative. Un appel pris par une messagerie vocale compte comme décroché (généralement un appel court avec outcome other).
Statut de l’appel
in_progress- L’appel est en cours.
completed- La personne a parlé avec l’assistant.
missed- Personne n’a parlé, ou l’assistant n’a pas pu prendre l’appel (voir end_reason).
failed- L’appel n’a pas pu être traité à cause d’une erreur.
Résultat de l’appel
booked- Un rendez-vous a été pris.
transferred- L’appel a été transféré à une personne.
message- Un message, une demande de rappel, une commande ou un suivi a été enregistré.
info- La personne a obtenu des informations ; rien d’autre n’était nécessaire.
spam- Spam, démarchage ou numéro bloqué.
other- Tout autre cas, p. ex. un appel très court ou une messagerie vocale.
Motif de fin d’appel (end_reason)
caller_hangup- L’autre personne a raccroché.
caller_hangup_greeting- Appel sortant : la personne a raccroché pendant l’accueil ou juste après, sans dire un mot (appel de 45 s maximum). caller_spoke vaut alors false.
agent_hangup- L’assistant a mis fin à l’appel après avoir pris congé.
transferred- L’appel a été transféré à une personne.
silence- Terminé après un long silence.
max_duration- La durée maximale d’appel a été atteinte.
spam- Terminé comme spam.
blocked- Le numéro est bloqué dans les contacts.
busy- Toutes les lignes du compte étaient occupées.
over_quota- Plus de minutes d’appel.
trial_expired- L’essai gratuit est terminé.
inactive- Aucun forfait actif.
assistant_not_live- L’assistant est en pause.
no_assistant- Aucun assistant ne répond sur ce numéro.
ai_budget- Traité sans IA en raison d’une limite temporaire ; l’équipe a été invitée à rappeler.
error- Une erreur technique a mis fin à l’appel.
Statut de l’appel sortant
scheduled- En attente de son horaire (ou de la prochaine tentative).
dialing- Appel en cours de numérotation.
done- Décroché ; call_id correspond à la conversation.
failed- Sans réponse après toutes les tentatives, ou impossible à passer (voir last_error).
canceled- Annulé (API, personne retirée de la séquence ou séquence désactivée).
last_error de l’appel sortant
no_answer- Personne n’a répondu (y compris ligne occupée ou appel rejeté).
failed- L’assistant n’était pas disponible au moment de l’appel (forfait, minutes ou pause).
no_result- Aucun résultat de l’appel dans les 15 minutes.
expired- L’appel avait plus de 2 heures de retard, il n’a donc pas été passé.
outside_window- Reporté aux prochains horaires d’appel (le statut reste scheduled).
dial_error- Le réseau téléphonique a refusé l’appel (envoyé sous la forme dial_<reason>).
over_quota- Plus de minutes d’appel.
inactive- Aucun forfait actif.
assistant_not_live- L’assistant est en pause.
no_outbound_number- Aucun numéro d’entreprise pour appeler.
canceled_by_api- Annulé avec DELETE /calls/outbound/{id}.
unenrolled- La personne a été retirée de la séquence (POST /api/outreach/unenroll).
opt_out- La personne ne souhaite pas être appelée.
replaced- Remplacé par un rappel plus récent vers le même numéro.
Données en direct via MCP
L’assistant consulte votre système pendant l’appel
Connectez un serveur MCP distant (Model Context Protocol) : catalogue de votre boutique, stock, système de réservation ou de commandes. Vous choisissez précisément les outils et ressources (en lecture seule) que l’assistant peut utiliser.
Apprendre à l’avance
Pour les contenus qui changent peu : tarifs, descriptions de produits, conditions. Les ressources et outils en lecture seule choisis sont importés dans les connaissances de l’assistant toutes les 1 à 168 heures ou à la demande. Aucun délai pendant l’appel.
Vérifier en direct pendant l’appel
Pour ce qui change : stock, disponibilités, statut de commande. L’assistant appelle l’outil pendant la conversation avec un bref « un instant, je vérifie ». Si votre serveur ne répond pas en 2,5 secondes environ, il indique ne pas pouvoir confirmer pour l’instant et propose un rappel de votre équipe.
Ce qu’il vous faut
- Un serveur MCP accessible en https (Streamable HTTP, p. ex. https://mcp.example.com/mcp ; les anciens serveurs HTTP+SSE sont détectés automatiquement).
- Authentification : aucune, un jeton Bearer ou un en-tête personnalisé comme X-API-Key. Les secrets sont chiffrés (AES-256-GCM) et jamais envoyés au navigateur.
- Des outils en lecture seule. Les outils marqués comme destructifs sont bloqués ; pour ceux qui ne sont pas marqués en lecture seule, vous confirmez qu’ils ne font que lire des données.
- Jusqu’à 5 sources et 50 outils en direct par assistant. Les vérifications en direct doivent répondre en 2 secondes environ.
- En option pour le widget du site : sur un outil « Au début de l’appel », choisissez l’argument qui reçoit le jeton d’identité du visiteur connecté (voir Widget vocal pour votre site).
Les arguments sont validés selon le schéma de l’outil, les résultats sont raccourcis et traités strictement comme des données (jamais comme des instructions), et chaque vérification est journalisée sans données de l’appelant. Les adresses privées et internes sont refusées.
Widget vocal pour votre site
Votre assistant sur votre site, en une ligne de code
Les visiteurs cliquent sur un bouton et parlent, dans le navigateur, avec le même assistant qui répond à votre téléphone. Les appels web utilisent les minutes de votre forfait, sans frais de téléphonie.
Dès Office
- Environ 14 Ko, sans dépendances, isolé dans un Shadow DOM : les styles de votre site ne peuvent pas le casser.
- Parle la langue de votre page (<html lang>) ou celle définie avec data-lang="de".
- Sous-titres en direct ; si le micro est bloqué, le visiteur peut écrire et l’assistant répond à voix haute.
- Limitez le widget à vos domaines : il ne démarrera que sur ces sites.
<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 pageContent Security Policy stricte ? Autorisez script-src https://telofia.com https://cdn.jsdelivr.net, connect-src https://telofia.com wss://*.livekit.cloud https://*.livekit.cloud et media-src blob:.
Utilisateurs connectés (jeton d’identité)
Quand vos visiteurs sont connectés sur votre site, l’assistant peut savoir qui parle sans demander son e-mail.
- Votre serveur émet un jeton signé et de courte durée pour l’utilisateur connecté (p. ex. HMAC, valable 15 minutes). Ne placez jamais d’adresse e-mail ni d’identifiant utilisateur dans le navigateur : n’importe qui pourrait saisir celui d’un autre dans la console.
- Appelez TelofiaWidget.identify({ token }) à tout moment ; un appel ultérieur remplace le jeton et identify(null) l’efface. Avant le chargement de widget.js, définissez window.TelofiaIdentity = { token, expires_at } : il est lu au début de la conversation et un jeton expiré est ignoré.
- Dans le tableau de bord, choisissez l’argument du jeton d’identité de votre outil MCP « Au début de l’appel ». Telofia transmet le jeton tel quel uniquement à cet argument, ne le stocke ni ne l’affiche jamais et le tient à l’écart des transcriptions, résumés, webhooks et journaux ; l’assistant ne le voit jamais.
- De 8 à 400 caractères : lettres, chiffres et . _ ~ + / = - (p. ex. base64url). Renouvelez-le avant son expiration, par exemple toutes les 10 minutes. Votre serveur MCP le vérifie ; un jeton invalide ou expiré doit donner le même résultat qu’aucun jeton. Les appels téléphoniques et les conversations sans jeton fonctionnent comme avant.
// 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 téléphonique
Vos nouveaux clients reçoivent automatiquement un appel de bienvenue
Quand quelqu’un s’inscrit dans votre système, ajoutez-le à une séquence d’appels. L’assistant l’appelle depuis le numéro de votre entreprise, l’aide à démarrer et reprend contact quelques jours plus tard. Les appels ont lieu pendant les horaires d’appel de la séquence : par défaut du lundi au samedi, de 9 h à 20 h dans votre fuseau horaire, ou aux jours et heures que vous avez définis.
POST/api/outreach/enroll
Authentifiez-vous avec la clé de la séquence (tlo_…) du tableau de bord, en jeton Bearer ou dans l’en-tête X-Telofia-Key. Chaque séquence a sa propre clé.
Corps de la requête
- Numéro de téléphone, idéalement au format E.164. Les numéros nationaux sont lus avec l’indicatif du pays de votre compte.
phonestringobligatoire - Doit valoir true : la personne a accepté d’être contactée par téléphone, p. ex. dans votre formulaire d’inscription.
consenttrueobligatoire - Nom, 120 caractères maximum.
namestringfacultatif - Adresse e-mail.
emailstringfacultatif - Ce que l’assistant doit savoir sur cette personne, 1 000 caractères maximum (p. ex. le forfait choisi).
contextstringfacultatif - L’identifiant de la personne dans votre système (texte ou nombre). Un même identifiant n’est inscrit qu’une fois.
external_idstring | numberfacultatif
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
}
}Réponses
- 201 : inscrite. enrollment_id, external_id, status, next_call_at (heure du premier appel), intro_sms_at (heure d’envoi du SMS avant le premier appel, ou null) et limits { per_day, remaining_today }
- 200 : déjà inscrite (même external_id, ou ce numéro est déjà en cours dans la séquence), avec duplicate: true
- 400 : invalid_request, invalid_phone ou consent_required
- 401 : invalid_key
- 409 : sequence_disabled, consent_missing ou opted_out (la personne ne souhaite pas être appelée)
- 429 : limit, la limite quotidienne d’inscriptions de la séquence est atteinte (500 nouvelles personnes par 24 heures ; le corps contient limit). rate_limited : plus de 120 requêtes par minute avec cette clé (en-tête Retry-After)
Horaires d’appel : dans le tableau de bord, définissez pour chaque séquence les jours et une plage horaire entre 7 h et 21 h. Sans réponse, l’assistant réessaie jusqu’à 3 fois, à 2 heures d’intervalle, pendant ces horaires.
SMS avant l’appel : s’il est activé pour la séquence (tableau de bord), la personne reçoit un court message depuis le numéro qui servira à l’appeler, par défaut 20 minutes avant le premier appel (5–120 min). Si le premier appel devait avoir lieu plus tôt, il est décalé pour que le SMS parte toujours en premier, pendant les horaires d’appel. Un SMS en échec (la personne a répondu STOP, le quota SMS est épuisé) n’empêche jamais l’appel. Chaque SMS est décompté de votre quota SMS et apparaît dans le tableau de bord, rubrique SMS.
Accueil : dans le tableau de bord, vous définissez la première phrase de l’appel pour chaque étape (ou par défaut pour toute la séquence) — un texte fixe avec les variables {first_name}, {first_name_vocative} (vocatif polonais, p. ex. Krystianie), {assistant_name}, Telofia (nom de l’entreprise dans les appels, réglages de l’assistant) et {name}, avec une variante pour les inscriptions sans nom — ou un mode où l’assistant rédige la première phrase à partir de name, context, de l’objectif de l’étape et du résultat des outils « Au début de l’appel ». Le fait qu’un assistant IA appelle et que l’appel est enregistré est toujours ajouté à la première phrase si le texte ne le dit pas.
Retirer une personne de la séquence
POST/api/outreach/unenroll
Quand quelqu’un n’a plus besoin des appels (p. ex. après sa première vente, ou s’il a résilié), arrêtez sa séquence avec la même clé. Les appels planifiés sont annulés immédiatement. Un appel déjà en cours n’est pas interrompu, mais aucun autre appel ne suit.
- Exactement un parmi : external_id (tel qu’envoyé lors de l’inscription), enrollment_id (issu de la réponse d’inscription) ou phone.
external_id | enrollment_id | phoneobligatoire - Motif facultatif, 200 caractères maximum, conservé dans le journal d’audit de votre compte.
reasonfacultatif
- 200 : arrêtée (changed: true) ou déjà terminée : status stopped, completed ou failed (changed: false). Peut être répété sans risque.
- 400 : invalid_request (aucun identifiant ou plusieurs) ou invalid_phone
- 401 : invalid_key
- 404 : not_found, aucune inscription correspondante dans cette séquence
- 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
}Résultats des appels dans les webhooks
call.started et call.completed pour les appels d’une séquence contiennent callback_id, external_id et outreach { sequence_id, enrollment_id, external_id, step } (tous null pour les appels entrants). Les tentatives sans réponse ne créent pas d’appel, il n’y a donc pas de call.completed pour elles : après la dernière tentative, vous recevez outbound_call.finished avec status failed et last_error no_answer. Les nouvelles tentatives d’une même étape comptent pour un seul résultat. call.completed contient aussi caller_spoke et caller_words (nombre de mots prononcés par la personne). Si quelqu’un a décroché puis raccroché pendant l’accueil ou juste après sans un mot, end_reason vaut 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
}Agenda, CRM et automatisation
Des intégrations prêtes à l’emploi, sans code
Google Agenda
L’assistant vérifie les disponibilités réelles et prend, déplace et annule les rendez-vous dans votre agenda. Il ne lit que les créneaux occupés, jamais les titres des événements.
HubSpot
Chaque appel est consigné sur le contact, les réservations deviennent des réunions et les rappels des tâches. Création de contacts et de transactions en option.
Pipedrive
Appels en activités ou en notes, réservations en réunions, rappels en activités. Création de personnes, d’affaires ou de prospects en option.
Zapier, Make et n8n
Guides pas à pas dans le tableau de bord. Ils reposent sur les webhooks et l’API, inclus dans tous les forfaits.
Forfaits et limites
Quel forfait choisir
Limites par compte : requêtes par minute (aussi par clé, fenêtre glissante) et par jour (UTC). Au-delà d’une limite, vous recevez 429 rate_limited avec un en-tête Retry-After.
Widget vocal pour votre site : à partir du forfait Office.
Besoin de limites plus élevées ? Contactez-nous, nous pouvons les augmenter pour votre compte.
Accès anticipé : faites partie des premières entreprises à confier leur téléphone à l’IA.
Prêt à connecter ?
Lancez l’essai gratuit, créez une clé API de test et envoyez votre première requête en quelques minutes. L’API est incluse dans tous les forfaits, dès Line.