Para desarrolladores
Conecta Telofia con los sistemas que ya usas
Consulta llamadas, transcripciones, citas y contactos con una REST API, recibe webhooks firmados en cuanto algo ocurre, deja que el asistente consulte datos en vivo de tu sistema durante la llamada y añade un asistente de voz a tu web con una sola línea de código.
La REST API y los webhooks están incluidos en todos los planes, desde Line; los planes superiores tienen límites más altos. Durante la prueba gratuita tienes acceso de prueba: 1 clave de API, 20 peticiones por 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
}
}Qué puedes conectar
Siete formas de integrar Telofia en tu negocio
Elige lo que encaje: automatizaciones sin código, unas pocas líneas de código o una integración completa en ambos sentidos.
- En todos los planes
REST API
Consulta llamadas con transcripción y grabación, citas, contactos y tareas. Crea y actualiza contactos, cancela o mueve citas y cierra tareas desde tu propio sistema.
- En todos los planes
Webhooks
Eventos JSON firmados en tiempo real: llamada iniciada o completada, cita reservada, cancelada o movida, nuevo contacto, tarea de devolución de llamada.
- En todos los planes
Datos en vivo vía MCP
Conecta tu servidor MCP y el asistente consulta stock, disponibilidad o estado de pedidos durante la llamada.
- Desde Office
Widget de voz para tu web
Una etiqueta script añade un botón “Habla con nosotros”. Los visitantes hablan con tu asistente en el navegador.
- En todos los planes
Onboarding telefónico
Envía los nuevos registros desde tu sistema y el asistente les llama para ayudarles a empezar.
- En todos los planes
Calendario y CRM
Google Calendar para reservas; HubSpot y Pipedrive para contactos, llamadas, reuniones y tareas.
- En todos los planes
Zapier, Make, n8n
Flujos sin código basados en webhooks y la API: Google Sheets, Slack, email, cualquier CRM.
Inicio rápido
Tu primera petición en dos minutos
- 1
Crea una clave de API
En el panel ve a Desarrolladores → Claves de API, ponle nombre a la clave y elige sus permisos. La clave (tf_live_…) solo se muestra una vez, así que guárdala en tu gestor de secretos.
- 2
Prueba la conexión
Llama a GET /me. Funciona con cualquier clave válida y devuelve tu cuenta, los permisos de la clave y los límites de tu plan.
- 3
Lee datos o suscríbete a eventos
Lista llamadas, citas y contactos, o añade un endpoint en Desarrolladores → Webhooks para recibir eventos al momento.
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
Llamadas, citas y contactos por HTTPS
JSON de entrada y de salida. Cada petición se autentica con una clave de API y tiene los límites de tu plan. Las peticiones aparecen en el panel (método, ruta, estado y tiempo; nunca el contenido de peticiones ni respuestas).
Autenticación
Crea una clave en Claves de API y envíala como token Bearer. Las claves empiezan por tf_live_ y pertenecen a una sola cuenta.
Authorization: Bearer tf_live_…Paginación
Los endpoints de listas devuelven hasta limit elementos (1–100, 25 por defecto) en un orden estable. Si has_more es true, pasa next_cursor sin cambios como cursor (con los mismos filtros) para obtener la página siguiente. Un cursor no válido devuelve 400 invalid_request.
Errores
Los errores usan códigos de estado HTTP estándar y un cuerpo JSON con un tipo y un mensaje legible.
{ "error": { "type": "…", "message": "…" } }Endpoints
- GET
/mePermiso: cualquier claveObtener la cuenta actual
Devuelve la cuenta a la que pertenece la clave de API. Útil como llamada para “probar la conexión”.
- GET
/assistantsPermiso: cualquier claveListar asistentes
Tus asistentes con su idioma, estado y números de teléfono asignados. Usa el id como assistant_id para filtrar llamadas.
- GET
/assistants/{id}Permiso: cualquier claveObtener un asistente
Un asistente con idioma, estado y números de teléfono. Con el scope read:assistants (o write:assistants) devuelve también el prompt: instructions, greeting, company_profile y updated_at.
- PATCH
/assistants/{id}Permiso: write:assistantsCambiar el prompt del asistente
Cambia las instrucciones, el saludo o el perfil de la empresa. Los campos omitidos no cambian. Mismos límites que en el panel: instrucciones hasta 20.000 caracteres, perfil hasta 10.000, saludo de 5 a 600 caracteres y debe indicar que quien llama habla con una IA (si no, 400 con code ai_disclosure). Cada cambio se guarda en el historial de versiones del asistente (origen API) y se aplica desde la siguiente llamada. Las normas de honestidad de la plataforma (aviso de IA y de grabación) se aplican siempre.
- GET
/phone-numbersPermiso: cualquier claveListar números de teléfono
Los números de teléfono de tu cuenta con país, tipo, estado y el asistente que los atiende.
- GET
/callsPermiso: read:callsListar llamadas
Llamadas de la más reciente a la más antigua, sin transcripciones. Nunca incluye las llamadas de demostración.
- GET
/calls/{id}Permiso: read:callsObtener una llamada
Una llamada con la transcripción completa y las citas reservadas durante ella.
- GET
/calls/{id}/recordingPermiso: read:callsObtener la grabación de una llamada
Enlaces firmados (válidos 1 hora) para escuchar y descargar la grabación MP3 (estéreo: quien llama a la izquierda, el asistente a la derecha). Una grabación más antigua que el historial de grabaciones de tu plan devuelve 403 plan_required con recording_history_days; una llamada sin grabación devuelve 404.
- GET
/appointmentsPermiso: read:appointmentsListar citas
Próximas citas ordenadas por hora de inicio (desde ahora por defecto).
- GET
/appointments/{id}Permiso: read:appointmentsObtener una cita
Una cita de tu cuenta.
- POST
/appointments/{id}/cancelPermiso: write:appointmentsCancelar una cita
Cancela una cita próxima, la elimina del calendario de Google conectado y envía el webhook appointment.canceled. calendar_sync indica si se actualizó el calendario.
- POST
/appointments/{id}/reschedulePermiso: write:appointmentsReprogramar una cita
Mueve una cita próxima a una nueva hora. Responde 409 si la hora coincide con otra cita o con un tiempo ocupado en el calendario conectado. Sin ends_at la duración se mantiene. Envía el webhook appointment.rescheduled.
- GET
/contactsPermiso: read:contactsListar contactos
Las personas que te han llamado, de la más reciente a la más antigua. El asistente las recuerda de una llamada a otra.
- GET
/contacts/{id}Permiso: read:contactsObtener un contacto
Un contacto con nombre, email, etiquetas, notas y el origen del nombre y del email (call, system o manual).
- POST
/contactsPermiso: write:contactsCrear un contacto
Añade un contacto, por ejemplo desde tu CRM, para que el asistente conozca el nombre de quien llama. El nombre y el email guardados por la API se marcan como manual y el asistente nunca los sobrescribe. Devuelve 409 con contact_id si el número ya existe. Envía el webhook contact.created.
- PATCH
/contacts/{id}Permiso: write:contactsActualizar un contacto
Cambia el nombre, el email, las notas o el bloqueo. Los campos omitidos no cambian y null vacía un campo. Un nombre o email modificado se marca como manual, así que el asistente no lo sobrescribirá. El número de teléfono no se puede cambiar.
- GET
/tasksPermiso: read:tasksListar tareas
Solicitudes de devolución de llamada, mensajes y otras tareas de las llamadas, de la más reciente a la más antigua.
- GET
/tasks/{id}Permiso: read:tasksObtener una tarea
Una tarea de tu cuenta.
- PATCH
/tasks/{id}Permiso: write:tasksActualizar una tarea
Cambia el estado de la tarea a open, done o dismissed, por ejemplo cuando tu equipo ya ha devuelto la llamada al cliente.
- POST
/calls/outboundPermiso: write:callsCrear una llamada saliente
Tu asistente llama a una persona desde el número de tu empresa con el objetivo que indiques, como un paso de una secuencia de onboarding. La llamada se hace ahora o en call_at, siempre dentro del horario de llamadas (lun–sáb, 9:00–20:00 en la zona horaria de tu cuenta; fuera de él, pasa al siguiente momento permitido y call_at indica cuándo). Si nadie contesta, lo intenta hasta 3 veces, con 2 horas de diferencia. Devuelve 202 con la llamada en estado scheduled. Errores: 400 consent_missing, invalid_phone, number_not_callable, international o invalid_call_at; 409 opted_out (la persona pidió no recibir llamadas), already_scheduled (con existing_id), assistant_not_live, over_quota o no_outbound_number; 429 daily_outbound_limit con limit (200 llamadas cada 24 horas por defecto). El resultado llega en los webhooks call.completed y outbound_call.finished con tu external_id.
- GET
/calls/outbound/{id}Permiso: write:callsObtener una llamada saliente
Estado de una llamada saliente programada: scheduled, dialing, done (con el call_id de la conversación), failed (last_error, p. ej. no_answer tras todos los intentos) o canceled. También funciona con el callback_id de los webhooks para las llamadas de onboarding y las devoluciones de llamada.
- DELETE
/calls/outbound/{id}Permiso: write:callsCancelar una llamada saliente
Cancela una llamada saliente creada a través de la API que todavía está programada. Se puede repetir sin riesgo (si ya está cancelada, devuelve 200). Devuelve 409 not_cancelable si la llamada se está marcando o ya ha terminado, o si es una llamada de onboarding (en ese caso, saca a la persona con POST /api/outreach/unenroll).
- GET
/messagesPermiso: read:messagesListar SMS
SMS enviados por tu cuenta y respuestas de clientes, los más recientes primero. phone es el número del cliente (destinatario o remitente de una respuesta). generated_by: template, ai o manual; charged_from: plan o credits.
- POST
/messagesPermiso: write:messagesEnviar un SMS
Envía un SMS a uno de tus contactos o llamantes: tu propio texto o una plantilla de tu cuenta con vars (date, time, name, service, link, amount). Cuenta para el límite de SMS de tu plan y los SMS adicionales. Errores: 400 invalid_request (consent_missing, invalid_phone, too_long, missing_vars); 409 conflict (opted_out — el cliente respondió STOP, over_quota, recipient_not_allowed — crea primero el contacto, blocked_destination); 429 rate_limited.
Permisos
Cada clave tiene los permisos elegidos al crearla. Los permisos no se pueden cambiar después: si necesitas más, crea una clave nueva. Si a la clave le falta el permiso necesario, los endpoints responden 403 insufficient_scope. GET /me, /assistants y /phone-numbers funcionan con cualquier clave válida.
read:callsLeer llamadas, resúmenes y transcripcionesread:appointmentsLeer citaswrite:appointmentsCancelar y reprogramar citasread:contactsLeer contactoswrite:contactsCrear y editar contactosread:tasksConsultar tareas y solicitudes de devolución de llamadawrite:tasksCambiar el estado de las tareaswrite:callsIniciar llamadas salientes, consultarlas y cancelarlasread:messagesLeer SMS y respuestas de clienteswrite:messagesEnviar SMS a tus contactosread:assistantsLeer el prompt del asistente (instrucciones, saludo, perfil de la empresa)write:assistantsCambiar el prompt del asistente
Errores
400invalid_request: falta un parámetro o no es válido401unauthorized: clave de API ausente, no válida o revocada403insufficient_scope: a la clave le falta el permiso del endpoint; plan_required: la cuenta no tiene un plan activo o la grabación es más antigua que el historial de grabaciones del plan404not_found: el objeto no existe en tu cuenta409conflict — la hora ya está ocupada, la cita no se puede modificar, ya existe un contacto con este número de teléfono o no se puede hacer una llamada saliente (code: opted_out, already_scheduled, assistant_not_live, over_quota, no_outbound_number, not_cancelable)429rate_limited — demasiadas solicitudes; reintenta tras el tiempo de la cabecera Retry-After500server_error: algo salió mal por nuestra parte503service_unavailable: problema temporal; reintenta tras el tiempo indicado en la cabecera Retry-After
La referencia completa de la API, con parámetros y respuestas de ejemplo, está en el panel en Desarrolladores → Referencia de la API.
Webhooks
Eventos enviados a tu servidor en tiempo real
Añade un endpoint https en el panel, elige los eventos y enviaremos un sobre JSON firmado (POST) en cuanto ocurra algo. “Enviar prueba” entrega un ejemplo de tu primer evento, útil para mapear campos en Zapier o Make.
Eventos
call.completedLlamada completadaResumen, resultado, sentimiento, transcripción, contacto y citas; en las llamadas salientes, también la secuencia o la solicitud de la API (callback_id, external_id, outreach).
call.startedLlamada iniciadaSe ha contestado una llamada (entrante, saliente o web).
appointment.bookedCita reservadaEl asistente ha reservado una cita.
appointment.canceledCita canceladaSe canceló una cita por teléfono o a través de la API.
appointment.rescheduledCita reprogramadaUna cita se movió a una nueva hora (incluye la hora anterior).
task.createdDevolución de llamada / tarea creadaAlguien pidió que le devolvieras la llamada o dejó una tarea.
contact.createdNuevo contactoUna persona que llamaba por primera vez se guardó como contacto.
outbound_call.finishedLlamada saliente finalizadaUna llamada saliente programada (API, secuencia de onboarding o devolución de llamada) ha terminado o ha fallado, también cuando nadie contestó tras todos los intentos.
Cabeceras de cada entrega
Telofia-SignatureFirma: t=<tiempo unix>,v1=<HMAC-SHA256 hex>Telofia-EventTipo de evento, p. ej. appointment.bookedTelofia-DeliveryID única de la entregaUser-AgentTelofia-Webhooks/1.0 · Identifica a nuestro emisor de webhooks
Entrega y reintentos
- Responde con cualquier estado 2xx en menos de 10 segundos. No se siguen redirecciones.
- Las entregas fallidas se reintentan tras 1 min, 5 min, 30 min, 2 h, 6 h y 12 h (7 intentos, unas 21 horas).
- El mismo evento puede llegar más de una vez. Usa el id del evento para descartar duplicados.
- Solo se aceptan direcciones https públicas. Tras 50 fallos seguidos, el endpoint se pausa y el panel te indica el motivo.
- El panel guarda un registro de entregas con códigos de estado y respuestas, y permite reintentar una entrega 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"
}
]
}
}Verificación de firmas. Cada envío incluye una cabecera Telofia-Signature con el formato t=timestamp,v1=signature. Calcula el HMAC-SHA256 de “timestamp.raw_body” con tu secreto de firma y compáralo con v1. Rechaza las marcas de tiempo con más de 5 minutos de antigüedad.
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);Valores estables
Estos valores en las llamadas (API y webhooks call.*) y en las llamadas salientes (outbound_call.finished, /calls/outbound) son un contrato estable: podemos añadir valores nuevos, pero no cambiaremos ni eliminaremos estos. Los intentos salientes sin respuesta, ocupados o rechazados nunca crean una llamada, así que no hay call.completed para ellos: tras el último intento recibes outbound_call.finished con last_error no_answer. Una llamada atendida por el buzón de voz cuenta como atendida (normalmente es una llamada corta con outcome other).
Estado de la llamada
in_progress- La llamada está en curso.
completed- La persona habló con el asistente.
missed- Nadie habló o el asistente no pudo atender la llamada (ver end_reason).
failed- No se pudo gestionar la llamada por un error.
Resultado de la llamada
booked- Se reservó una cita.
transferred- La llamada se transfirió a una persona.
message- Se tomó un mensaje, una solicitud de devolución de llamada, un pedido o un seguimiento.
info- La persona obtuvo información; no hizo falta nada más.
spam- Spam, telemarketing o un número bloqueado.
other- Cualquier otro caso, p. ej. una llamada muy corta o un buzón de voz.
Motivo de fin de la llamada (end_reason)
caller_hangup- La otra persona colgó.
caller_hangup_greeting- Llamada saliente: la persona colgó durante el saludo o justo después, sin decir nada (llamada de hasta 45 s). En ese caso caller_spoke es false.
agent_hangup- El asistente terminó la llamada tras despedirse.
transferred- La llamada se transfirió a una persona.
silence- Terminó tras un silencio prolongado.
max_duration- Se alcanzó la duración máxima de la llamada.
spam- Terminó como spam.
blocked- El número está bloqueado en contactos.
busy- Todas las líneas de la cuenta estaban ocupadas.
over_quota- No quedan minutos de llamada.
trial_expired- La prueba gratuita ha terminado.
inactive- No hay un plan activo.
assistant_not_live- El asistente está en pausa.
no_assistant- Ningún asistente atiende este número.
ai_budget- Atendida sin IA por un límite temporal; se pidió al equipo que devuelva la llamada.
error- Un error técnico terminó la llamada.
Estado de la llamada saliente
scheduled- Esperando su hora (o el siguiente intento).
dialing- Llamando ahora.
done- Atendida; call_id es la conversación.
failed- Sin respuesta tras todos los intentos, o no se pudo hacer (ver last_error).
canceled- Cancelada (API, la persona salió de la secuencia o la secuencia se desactivó).
last_error de la llamada saliente
no_answer- Nadie contestó (también si estaba ocupado o se rechazó).
failed- El asistente no estaba disponible a la hora de la llamada (plan, minutos o pausa).
no_result- Sin resultado de la llamada en 15 minutos.
expired- La llamada llevaba más de 2 horas de retraso, así que no se hizo.
outside_window- Movida al siguiente horario de llamadas (el estado sigue siendo scheduled).
dial_error- La red telefónica rechazó la llamada (se envía como dial_<reason>).
over_quota- No quedan minutos de llamada.
inactive- No hay un plan activo.
assistant_not_live- El asistente está en pausa.
no_outbound_number- No hay un número de empresa desde el que llamar.
canceled_by_api- Cancelada con DELETE /calls/outbound/{id}.
unenrolled- La persona salió de la secuencia (POST /api/outreach/unenroll).
opt_out- La persona pidió no recibir llamadas.
replaced- Sustituida por una devolución de llamada más reciente al mismo número.
Datos en vivo vía MCP
El asistente consulta tu sistema durante la llamada
Conecta un servidor MCP remoto (Model Context Protocol), como el catálogo de tu tienda, el stock o tu sistema de reservas o pedidos. Tú eliges exactamente qué herramientas y recursos (solo lectura) puede usar el asistente.
Aprender por adelantado
Para contenido que cambia poco, como tarifas, descripciones de productos o políticas. Los recursos y herramientas de solo lectura elegidos se importan al conocimiento del asistente cada 1 a 168 horas o cuando lo pidas. Sin retrasos en la llamada.
Consultar en vivo en la llamada
Para lo que cambia: stock, disponibilidad, estado de pedidos. El asistente usa la herramienta durante la conversación con un breve “un momento, lo compruebo”. Si tu servidor no responde en unos 2,5 segundos, dice que ahora no puede confirmarlo y ofrece que tu equipo vuelva a contactar.
Qué necesitas
- Un servidor MCP accesible por https (Streamable HTTP, p. ej. https://mcp.example.com/mcp; los servidores HTTP+SSE antiguos se detectan automáticamente).
- Autenticación: ninguna, un token Bearer o una cabecera propia como X-API-Key. Los secretos se cifran (AES-256-GCM) y nunca llegan al navegador.
- Herramientas de solo lectura. Las marcadas como destructivas se bloquean; para las que no están marcadas como de solo lectura, confirmas que solo leen datos.
- Hasta 5 fuentes y 50 herramientas en vivo por asistente. Las consultas en vivo deberían responder en unos 2 segundos.
- Opcional para el widget web: en una herramienta «Al inicio de la llamada», elige el argumento que recibe el token de identidad del visitante con sesión iniciada (ver Widget de voz para tu web).
Los argumentos se validan con el esquema de la herramienta, los resultados se acortan y se tratan estrictamente como datos (nunca como instrucciones), y cada consulta se registra sin datos de quien llama. Se rechazan las direcciones privadas e internas.
Widget de voz para tu web
Tu asistente en tu web, con una línea de código
Los visitantes pulsan un botón y hablan, desde el navegador, con el mismo asistente que atiende tu teléfono. Las llamadas web usan los minutos de tu plan, sin costes de telefonía.
Desde Office
- Unos 14 KB, sin dependencias, aislado en Shadow DOM para que los estilos de tu web no lo rompan.
- Habla el idioma de tu página (<html lang>) o el que indiques con data-lang="de".
- Subtítulos en vivo; si el micrófono está bloqueado, el visitante puede escribir y el asistente responde por voz.
- Limita el widget a tus dominios y solo se iniciará en esos sitios.
<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 page¿Tienes una Content Security Policy estricta? Permite script-src https://telofia.com https://cdn.jsdelivr.net, connect-src https://telofia.com wss://*.livekit.cloud https://*.livekit.cloud y media-src blob:.
Usuarios con sesión iniciada (token de identidad)
Si los visitantes han iniciado sesión en tu web, el asistente puede saber quién habla sin pedirle el e-mail.
- Tu servidor emite un token firmado y de corta duración para el usuario con sesión iniciada (p. ej. HMAC, válido 15 minutos). Nunca pongas un e-mail ni un ID de usuario en el navegador: cualquiera podría escribir el de otra persona en la consola.
- Llama a TelofiaWidget.identify({ token }) en cualquier momento; una llamada posterior sustituye el token e identify(null) lo borra. Antes de que se cargue widget.js, define window.TelofiaIdentity = { token, expires_at }: se lee al empezar la conversación y un token caducado se ignora.
- En el panel, elige el argumento del token de identidad en tu herramienta MCP «Al inicio de la llamada». Telofia pasa el token sin cambios solo a ese argumento, nunca lo guarda ni lo muestra y lo mantiene fuera de transcripciones, resúmenes, webhooks y registros; el asistente nunca lo ve.
- De 8 a 400 caracteres: letras, dígitos y . _ ~ + / = - (p. ej. base64url). Renuévalo antes de que caduque, por ejemplo cada 10 minutos. Lo verifica tu servidor MCP; un token no válido o caducado debería dar el mismo resultado que no tener token. Las llamadas telefónicas y las conversaciones sin token funcionan como hasta ahora.
// 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 telefónico
Tus nuevos clientes reciben una llamada de bienvenida automáticamente
Cuando alguien se registra en tu sistema, envíalo a una secuencia de llamadas. El asistente le llama desde el número de tu empresa, le ayuda a empezar y vuelve a llamar unos días después. Las llamadas se hacen dentro del horario de llamadas de la secuencia: por defecto, de lunes a sábado, de 9:00 a 20:00 en tu zona horaria, o en los días y horas que configures.
POST/api/outreach/enroll
Autentícate con la clave de la secuencia (tlo_…) del panel, como token Bearer o en la cabecera X-Telofia-Key. Cada secuencia tiene su propia clave.
Cuerpo de la petición
- Número de teléfono, idealmente en formato E.164. Los números nacionales se leen con el prefijo del país de tu cuenta.
phonestringobligatorio - Debe ser true: la persona aceptó ser contactada por teléfono, p. ej. en tu formulario de registro.
consenttrueobligatorio - Nombre, hasta 120 caracteres.
namestringopcional - Dirección de email.
emailstringopcional - Lo que el asistente debe saber de esta persona, hasta 1.000 caracteres (p. ej. el plan elegido).
contextstringopcional - La ID de la persona en tu sistema (texto o número). La misma ID se inscribe solo una vez.
external_idstring | numberopcional
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
}
}Respuestas
- 201: inscrita. enrollment_id, external_id, status, next_call_at (hora de la primera llamada), intro_sms_at (cuándo sale el SMS previo a la primera llamada, o null) y limits { per_day, remaining_today }
- 200: ya inscrita (mismo external_id, o este número ya está en curso en la secuencia), con duplicate: true
- 400: invalid_request, invalid_phone o consent_required
- 401: invalid_key
- 409: sequence_disabled, consent_missing u opted_out (la persona no quiere llamadas)
- 429: limit, se alcanzó el límite diario de inscripciones de la secuencia (500 personas nuevas cada 24 horas; el cuerpo incluye limit). rate_limited: más de 120 peticiones por minuto con esta clave (cabecera Retry-After)
Horario de llamadas: en el panel, elige para cada secuencia los días y una franja horaria entre las 7:00 y las 21:00. Si nadie contesta, el asistente lo intenta hasta 3 veces, con 2 horas de diferencia, dentro de ese horario.
SMS antes de la llamada: si está activado en la secuencia (panel), la persona recibe un mensaje breve desde el número desde el que llamará el asistente, por defecto 20 minutos antes de la primera llamada (5–120 min). Si la primera llamada fuera antes, se aplaza para que el SMS siempre salga primero, dentro del horario de llamadas. Un SMS fallido (la persona respondió STOP, se agotó el límite de SMS) nunca detiene la llamada. Cada SMS cuenta para tu límite de SMS y aparece en el panel, en SMS.
Saludo: en el panel defines la primera frase de la llamada para cada paso (o por defecto para toda la secuencia): un texto fijo con las variables {first_name}, {first_name_vocative} (vocativo polaco, p. ej. Krystianie), {assistant_name}, Telofia (nombre de la empresa en las llamadas, de los ajustes del asistente) y {name}, con una variante aparte para registros sin nombre, o un modo en el que el asistente redacta la primera frase a partir de name, context, el objetivo del paso y el resultado de las herramientas «Al inicio de la llamada». Que llama un asistente de IA y que la llamada se graba se añade siempre a la primera frase si el texto no lo dice.
Sacar a una persona de la secuencia
POST/api/outreach/unenroll
Cuando alguien ya no necesita las llamadas (p. ej., tras su primera venta o porque se dio de baja), detén su secuencia con la misma clave. Las llamadas programadas se cancelan al momento. Una llamada ya en curso no se interrumpe, pero después no habrá más llamadas.
- Exactamente uno de: external_id (el que enviaste al inscribir), enrollment_id (de la respuesta de inscripción) o phone.
external_id | enrollment_id | phoneobligatorio - Motivo opcional, hasta 200 caracteres, que se guarda en el registro de auditoría de tu cuenta.
reasonopcional
- 200: detenida (changed: true) o ya finalizada: status stopped, completed o failed (changed: false). Se puede repetir sin riesgo.
- 400: invalid_request (sin identificador o con más de uno) o invalid_phone
- 401: invalid_key
- 404: not_found, no existe esa inscripción en esta secuencia
- 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
}Resultados de las llamadas en los webhooks
call.started y call.completed de las llamadas de una secuencia incluyen callback_id, external_id y outreach { sequence_id, enrollment_id, external_id, step } (todos null en las llamadas entrantes). Los intentos sin respuesta no crean una llamada, así que no hay call.completed para ellos: tras el último intento recibes outbound_call.finished con status failed y last_error no_answer. Los reintentos de un mismo paso cuentan como un solo resultado. call.completed incluye también caller_spoke y caller_words (cuántas palabras dijo la persona). Si alguien contestó y colgó durante el saludo o justo después sin decir nada, end_reason es 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 y automatización
Integraciones listas para usar, sin código
Google Calendar
El asistente consulta la disponibilidad real y reserva, mueve y cancela citas en tu calendario. Solo lee las horas ocupadas, nunca los títulos de los eventos.
HubSpot
Cada llamada se registra en el contacto, las reservas se convierten en reuniones y las devoluciones de llamada en tareas. Opcionalmente crea contactos y negocios.
Pipedrive
Llamadas como actividades o notas, reservas como reuniones, devoluciones de llamada como actividades. Opcionalmente crea personas, tratos o leads.
Zapier, Make y n8n
Guías paso a paso en el panel. Funcionan con webhooks y la API, incluidos en todos los planes.
Planes y límites
Qué plan necesitas
Límites por cuenta: peticiones por minuto (también por clave, ventana deslizante) y por día (UTC). Por encima del límite recibes 429 rate_limited con la cabecera Retry-After.
Widget de voz para tu web: desde el plan Office.
¿Necesitas límites más altos? Escríbenos y podemos ampliarlos para tu cuenta.
Acceso anticipado: sé de los primeros negocios en dejar que la IA conteste el teléfono.
¿Listo para conectar?
Empieza la prueba gratuita, crea una clave de API de prueba y envía tu primera petición en minutos. La API está incluida en todos los planes, desde Line.