Construí sobre la misma API sobre la que construimos nosotros
Todo lo que hace la plataforma — conversaciones, contactos, agentes de IA, conocimiento, analítica — corre sobre esta API REST. No hay una API privada mejor detrás: esta es la única. URL base: `https://api.inteligenciaviva.com/v1`.
Quickstart: tu primera petición en 60 segundos
Creá una clave de API en tu workspace, exportala, y listá tus conversaciones. Las claves tienen alcance por workspace y pueden ser de solo lectura o de lectura-escritura.
curl https://api.inteligenciaviva.com/v1/workspaces/WORKSPACE_ID/conversations \
-H "Authorization: Bearer sk_live_..."
Toda respuesta es JSON. Los endpoints de colección devuelven arreglos `data`; los errores devuelven un objeto `error` con `code` y `message` y el estado HTTP correspondiente.
La API gratuita — sin cuenta, sin clave
La capa gratuita también habla API. `POST /v1/free/widget-snippet` recibe exactamente la misma configuración que arma el generador visual de la página Gratis y devuelve el snippet HTML listo para pegar — sin autenticación, sin registro. Usala para generar widgets por lote para sitios de clientes, regenerar embeds desde CI cuando cambian horarios, o simplemente para tocar la API antes de pagar un centavo.
curl -X POST https://api.inteligenciaviva.com/v1/free/widget-snippet \
-H "Content-Type: application/json" \
-d @widget-config.json
# → { "snippet": "<link rel=\"stylesheet\" ..." }
Autenticación
Toda petición lleva una clave de API en la cabecera `Authorization` como token Bearer. Las claves se crean y revocan desde la propia API o desde el panel, por workspace — revocar una clave corta su acceso de inmediato.
Los endpoints de sesión a nivel de cuenta (registro, login, acceso con Google, canje de ticket, perfil y eliminación de cuenta bajo `/v1/auth`) alimentan nuestras propias apps; para integraciones servidor-a-servidor preferí siempre claves de API de workspace sobre sesiones de usuario.
Authorization: Bearer sk_live_...
Referencia de recursos
Todas las rutas de abajo cuelgan de `https://api.inteligenciaviva.com/v1/workspaces/{workspaceId}` salvo que se indique. Esta es la superficie real montada del backend actual — no aspiracional.
Bandeja cruzada /inbox
| GET | /conversations | Todas las conversaciones de TODOS los workspaces que atiende la credencial, en una sola lista ordenada por actividad. Es la única familia de rutas que no cuelga de /workspaces/{id}. |
| GET | /conversations/{id} | Una conversación buscada entre todos tus workspaces, sin saber en cuál está. Devuelve su workspace_id. |
| GET | /workspaces | Los workspaces que esta credencial puede atender, con su rol en cada uno. |
| GET | /visitantes | Quién está navegando AHORA en todos tus workspaces, con la página que lee y si ya conversa. Es una foto del momento, no un historial: no se pagina. Un workspace que no contesta no tumba la lista: va en `casas_sin_responder`. |
Conversaciones /conversations
| GET | / | Listar conversaciones, filtrables por estado. |
| GET | /{id} | Una conversación con su estado, canal, contacto y asignación. |
| GET | /{id}/messages | Historial de mensajes (visitante, agente humano, IA, sistema). |
| POST | /{id}/messages | Enviar un mensaje a la conversación como agente. |
| POST | /{id}/assign | Asignar la conversación a un agente humano o a un departamento. |
| POST | /{id}/resolve | Cerrar la conversación. Si la IA la cerró sola, cuenta como resolución facturable. |
| POST | / | Abrir una conversación desde fuera del widget (por ejemplo, para migrar un hilo existente). |
| GET | /{id}/ai-turns | «¿De dónde sacó eso?» — la bitácora de cada turno de IA: en qué se apoyó, con qué modelo, cuánto tardó y por qué se traspasó. |
| GET | /{id}/portal-case | Estado del caso que esta conversación abrió en el tablero de soporte del Portal, con sus respuestas. Se consulta en vivo: el estado cambia en el otro tablero. |
| POST | /{id}/read | Marcar la conversación como leída por el equipo (contador de no leídos). |
| POST | /{id}/reopen | Reabrir una conversación cerrada, conservando el historial. Sin esto, un cierre por error no tenía vuelta atrás. |
| POST | /{id}/archive | Archivar o desarchivar. Sale de la bandeja sin cerrarse ni perder nada; el cuerpo es {valor:true|false}. |
| POST | /{id}/pin | Fijar arriba o soltar. Las fijadas encabezan la primera página de la bandeja. Cuerpo: {valor:true|false}. |
| POST | /{id}/mute | Silenciar los avisos durante N horas, o {horas:null} para volver a oírla. |
| POST | /{id}/unread | Dejarla como no leída: retrocede la marca de lectura por detrás del último mensaje del cliente. |
| POST | /{id}/typing | «Escribiendo…» hacia el cliente: en WhatsApp lo recibe Meta y en el chat web, el widget del visitante. Sin cuerpo; 204 siempre (en los canales que no lo admiten no hace nada) y 404 si la conversación no existe. |
| POST | /{id}/messages/{messageId}/forward | Reenviar un mensaje a otra conversación del mismo workspace, con su adjunto (se copia, no se comparte). Cuerpo: `{to_conversation_id}`. Sale como mensaje del agente. |
| PUT | /{id}/messages/{messageId}/reaction | Reaccionar con un emoji a un mensaje de WhatsApp; sustituye la reacción anterior del negocio y `{emoji:null}` la quita. Solo WhatsApp (API de Meta) y solo sobre un mensaje que Meta ya confirmó: si no, 400. |
| POST | /{id}/location | Enviar una ubicación por WhatsApp: `{lat, lon, name?, address?, reply_to_message_id?}`. Se manda a Meta primero: si Meta la rechaza, no queda en el hilo. Solo WhatsApp. |
| POST | /{id}/contact-card | Enviar una tarjeta de contacto por WhatsApp: `{name:{formatted_name}, phones?, emails?, reply_to_message_id?}`. Igual que la ubicación: primero Meta, después el hilo. Solo WhatsApp. |
| GET | /{id}/copiloto | El copiloto del agente: lo que la IA ha sugerido para esta conversación y lo hablado con ella. Es privado del equipo: el cliente no lo ve. |
| POST | /{id}/copiloto | Preguntarle algo a la IA en privado sobre esta conversación (`{content}`, hasta 4.000 caracteres). Responde AL AGENTE, no al cliente: nada sale por el canal. 503 `copilot_unavailable` si no puede responder. |
| POST | /{id}/copiloto/{sugerenciaId}/enviar | Mandar al cliente una sugerencia del copiloto, tal cual o editada (`{content}` opcional). Sale como mensaje del agente, con su autor humano. Una sugerencia se envía una sola vez: la segunda da 409 `ya_enviada`. |
| POST | /{id}/resumen | Pedir el resumen de la conversación (abierta o cerrada) y actualizar con él la ficha del contacto. Cuesta una tarea del KIT; pedirlo otra vez sin mensajes nuevos no vuelve a cobrar. Si no hay resumen, devuelve por qué (`motivo`, `codigo`). |
Contactos /contacts
| GET | / | Listar contactos. |
| GET | /{id} | Un contacto con sus identidades y su historial de conversaciones. |
| GET | /{id}/historial | De qué fueron sus últimas consultas: las últimas conversaciones con su resumen (`?limit=`, hasta 25), los totales y la ficha del contacto. Abrirla no genera la ficha si falta, porque cuesta dinero: se pide aparte con `?generar=1`. |
Agentes de IA /ai-agents
| GET | / | Listar los agentes de IA del workspace. |
| POST | / | Crear un agente de IA: instrucciones, departamento, umbral de confianza. |
| PATCH | /{id} | Actualizar instrucciones, umbral o departamento. |
| GET | /{id}/knowledge-sources | Fuentes de conocimiento asociadas a este agente. |
| POST | /{id}/knowledge-sources | Asociar una fuente de conocimiento a este agente. |
| GET | /{aiAgentId} | Un agente de IA: instrucciones, umbral de confianza, herramientas y departamento. |
Conocimiento (RAG) /knowledge-sources
| POST | /document | Indexar un documento como conocimiento fundamentado. |
| POST | /url | Indexar una URL. |
| GET | /{id} | Estado y metadatos de la fuente. |
| DELETE | /{id} | Eliminar una fuente y sus vectores. |
| POST | /{id}/reindex | Volver a leer una fuente de URL sin borrarla: si la descarga falla, no se toca nada. |
| GET | / | Listar las fuentes de conocimiento con su estado de indexación. |
Ficha del negocio /ficha
| GET | / | Listar las unidades (filtros ?estado= y ?tipo=) con los umbrales de las franjas. |
| POST | / | Crear una unidad: pregunta, variantes, respuesta aprobada, URL e idioma. Un administrador o una clave la publica; un agente la propone. La IA nunca publica. |
| GET | /{id} | Ver una unidad. |
| PATCH | /{id} | Editar una unidad; cambiar la pregunta o las variantes recalcula su embedding. |
| DELETE | /{id} | Borrar una unidad (administrador). |
| POST | /{id}/aprobar | Aprobar una propuesta: pasa a activa y queda quién la aprobó (administrador). |
| POST | /{id}/rechazar | Rechazar una propuesta (administrador). |
| POST | /probar | Vista previa: qué contestaría la ficha a una pregunta, con su nota y su franja (opcional: incluir las propuestas). |
| POST | /recalcular | Recalcular los embeddings que falten o no casen con el texto (administrador). |
Canales /channels
| GET | / | Listar canales. Vivos hoy: chat web y API; más se conectan a medida que salgan. |
| PUT | /{id}/credentials | Definir las credenciales de un canal. |
| PUT | /{id}/status | Habilitar o deshabilitar un canal. |
| POST | / | Crear un canal. |
| GET | /{channelId} | Un canal con su tipo, estado y ajustes. |
| GET | /{channelId}/snippet | La línea que el cliente pega en su sitio. Es UNA sola: todo lo demás se configura aquí. |
| GET | /{channelId}/config | La configuración del chat: lo publicado (`config`) y lo que este canal sobrescribe (`settings`). Son distintos y conviene no confundirlos. |
| PUT | /{channelId}/config | Guardar la configuración. Guardar y publicar son el mismo paso: si la CDN falla, el PUT falla — no se responde «guardado» a medias. |
| POST | /{channelId}/config/publish | Volver a publicar la configuración a la CDN sin cambiarla. |
| POST | /{channelId}/avatar | Subir la cara del asistente (≤512 KB). Va a R2 y la sirve la CDN. |
| POST | /republicar-todos | Republicar todos los canales del workspace. Lo hace el cron cuando cambia el pack de cadenas; esto es para no esperar. |
| PUT | /{channelId}/modo | El modo de atención del canal: `{modo:"humano"|"hibrido"|"ia"}`. Decide si la IA le habla al cliente. Vale para cualquier tipo de canal (WhatsApp, Telegram, correo, widget). Requiere ser administrador. |
| PUT | /{channelId}/auto | Los mensajes automáticos del canal: `{bienvenida, fueraDeHorario}` (hasta 1.000 caracteres cada uno; `null` borra). El de fuera de horario usa el horario del canal. Requiere ser administrador. |
| PUT | /{channelId}/tarjeta | La tarjeta de contacto que el agente puede enviar desde este canal: `{tarjetaContacto:{name:{formatted_name}, phones?, emails?}}`, con al menos un teléfono o un correo; `null` la quita. Solo WhatsApp. Requiere ser administrador. |
| PUT | /{channelId}/horario | El horario de atención: `{officeHours:{tz, dias:{lun:[["09:00","17:00"]], …}, festivos:["MM-DD" o "YYYY-MM-DD"]}}`; `null` lo quita (24/7). Lo que no se entiende se rechaza con 400 diciendo qué está mal. Devuelve `abiertoAhora`, calculado por el servidor. Requiere ser administrador. |
Agentes humanos y departamentos /agents · /departments
| GET | /agents | Listar los agentes humanos del workspace. |
| POST | /agents/{userId}/departments | Poner un agente en un departamento. |
| GET | /departments | Listar departamentos. |
| PUT | /departments/{id}/routing-rules | Definir reglas de enrutamiento de conversaciones entrantes. |
| POST | /agents | Invitar a una persona al workspace, con su rol y departamentos. |
| GET | /agents/{userId} | Una persona del equipo. |
| POST | /departments | Crear un departamento con sus reglas de enrutado. |
| GET | /departments/{id} | Un departamento. |
Webhooks, claves, facturación, analítica /webhooks · /api-keys · /billing · /analytics
| POST | /webhooks | Registrar un endpoint; recibís su secreto de firma una sola vez. |
| DELETE | /webhooks/{id} | Eliminar un endpoint. |
| POST | /api-keys | Crear una clave (solo lectura o lectura-escritura). |
| DELETE | /api-keys/{id} | Revocar una clave de inmediato. |
| GET | /billing/subscription | Plan, resoluciones de IA incluidas y uso del período. |
| GET | /analytics | Métricas agregadas del workspace. |
| GET | /webhooks | Listar los endpoints de webhook. |
| GET | /webhooks/{id}/deliveries | Historial de entregas de un webhook, con reintentos. Es lo que dice si el fallo es tuyo o nuestro. |
| GET | /api-keys | Listar las claves. Nunca se devuelve el secreto: solo su prefijo. |
Herramientas del agente /conversations/{id} · /canned-responses · /tags · /presence
| GET | /conversations/{id}/notes | Notas internas de la conversación. NUNCA las ve el visitante. |
| POST | /conversations/{id}/notes | Añadir una nota interna. |
| DELETE | /conversations/{id}/notes/{noteId} | Borrar una nota interna. |
| GET | /canned-responses | Respuestas predefinidas del workspace, con su atajo. |
| POST | /canned-responses | Crear una respuesta predefinida. |
| PATCH | /canned-responses/{cannedId} | Editar una respuesta predefinida. |
| DELETE | /canned-responses/{cannedId} | Borrar una respuesta predefinida. |
| POST | /presence | Latido de presencia: declara que hay una persona atendiendo. Solo con sesión — una clave de API que late no es alguien mirando la pantalla, y se rechaza con 400. |
| GET | /presence | ¿Hay alguien en línea ahora mismo? Es lo que decide si un traspaso espera o se deriva. |
| GET | /ai-usage | Consumo de inferencia del workspace por día y las conversaciones que más gastan. |
| GET | /tags | Etiquetas del workspace. |
| GET | /conversations/{id}/tags | Etiquetas de una conversación. |
| POST | /conversations/{id}/tags | Etiquetar una conversación. Crea la etiqueta si no existía. |
| DELETE | /conversations/{id}/tags/{tagId} | Quitar una etiqueta de la conversación. |
| POST | /conversations/{id}/transfer | Transferir la conversación a un departamento. Manda sobre las reglas de enrutado: una transferencia hecha a mano no se deshace sola. |
| POST | /contacts/{contactId}/block | Bloquear un contacto. Se le responde 403 sin detalle: a quien abusa no se le explica cómo se le detecta. |
| GET | /canned-responses/categories | Las categorías ya usadas en las respuestas predefinidas (texto libre), para autocompletar. |
| POST | /canned-responses/{cannedId}/use | Anotar que se usó una respuesta predefinida (contador y última vez). Siempre 204, exista o no: es telemetría de uso, no una acción. |
Adjuntos, dispositivos y workspaces /conversations/{id}/attachments · /devices · /workspaces
| POST | /conversations/{id}/attachments | Subir un adjunto como agente. Lista blanca estricta y 10 MB: no entra nada que un navegador pueda ejecutar. |
| GET | /conversations/{id}/attachments | Adjuntos de una conversación. |
| GET | /attachments/{attachmentId} | Descargar un adjunto. Se sirve con cabeceras duras y `nosniff`; solo imágenes y audio se muestran en línea. |
| POST | /devices/register | Registrar el token push de un dispositivo, para avisar a una persona cuando la IA traspasa. Fuera del prefijo de workspace: `/v1/devices/register`. |
| POST | /workspaces | Crear un workspace. Fuera del prefijo: `/v1/workspaces`. |
| GET | /workspaces/{workspaceId}/retencion/ensayo | El ensayo de la purga: cuántas conversaciones y adjuntos (y bytes) se llevaría la retención, sin borrar nada. `?days=` pregunta por un plazo que aún no está guardado. Requiere ser administrador y `analytics:read`. Ruta completa: `/v1/workspaces/{workspaceId}/retencion/ensayo`. |
Visitantes en vivo y tiempo real /visitantes · /stream-ticket
| GET | /visitantes | Quién está navegando ahora en los sitios de este workspace: página, idioma, desde cuándo y si ya tiene el chat abierto o una conversación. |
| POST | /visitantes/{visitorId}/invitar | Invitar a un visitante a abrir el chat, con `{mensaje}` opcional (sin él, el saludo del widget en su idioma). No crea conversación ni gasta IA: la conversación nace cuando el visitante contesta. 404 `no_esta` si ya se fue; 409 `ya_conversa` si ya está conversando. |
| POST | /stream-ticket | Un ticket para abrir el WebSocket del stream con `?ticket=` sin poner el token en la URL. Dura 60 s y sirve una sola vez. Vale con sesión o con clave de API. |
Capacidades del KIT /conversations/{id}/kit
| GET | / | Las tareas del KIT lanzadas en esta conversación, con su estado. Al listarlas se repasan las pendientes. |
| GET | /catalogo | Qué capacidades del KIT se pueden lanzar sobre un adjunto (`?attachment_id=`) o sobre el hilo, con buscador (`?q=`, `?lang=`). Solo lectura: no cuesta nada. |
| POST | / | Lanzar una capacidad del KIT (`{action, attachment_id?, params?}`) sobre un adjunto o sobre el hilo. El resultado vuelve como NOTA INTERNA, nunca al cliente. Cuesta dinero del monedero del KIT, y la misma petición no se cobra dos veces. 202 con la tarea en cola. |
Teléfono (VOICE) /voice
| GET | /llamadas | El registro de llamadas de la central del workspace (`?limite=` hasta 200, `?antes_de=` para paginar). Alcance `voice:read`; 404 si el workspace no tiene central. |
| GET | /llamadas-en-curso | Las llamadas que están ocurriendo ahora. |
| GET | /aparcadas | Las llamadas aparcadas, en espera de que alguien las retome. |
| GET | /grabaciones/{id}/audio | El audio de una grabación, servido a través del API (sin enlace público) y sin caché. La central registra quién la escuchó. |
| GET | /extensiones | Las extensiones que el panel puede usar como teléfono (las reservadas no salen). |
| POST | /webphone-sesion | Registrar el navegador como teléfono de una extensión (`{extension_id}`): devuelve una credencial SIP efímera, que la central rota en cada canje. Alcance `voice:write`. La clave de la central nunca sale del servidor. |
Ejemplos reales
Enviar un mensaje de agente (curl)
curl -X POST \
https://api.inteligenciaviva.com/v1/workspaces/$WS/conversations/$CONV/messages \
-H "Authorization: Bearer $IV_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Hi! I checked your order — it ships tomorrow."}'Listar conversaciones (JavaScript)
const res = await fetch(
`https://api.inteligenciaviva.com/v1/workspaces/${WS}/conversations`,
{ headers: { Authorization: `Bearer ${process.env.IV_KEY}` } }
);
const { data } = await res.json();Verificar la firma de un webhook (Node)
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(secret, rawBody, header, toleranceSec = 300) {
const { t, v1 } = Object.fromEntries(
header.split(",").map((p) => p.split("="))
);
if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSec) return false;
const expected = createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
return timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
Webhooks
Registrá un endpoint HTTPS y te enviamos cada evento por POST, firmado. La cabecera es `iv-signature: t=<unix>,v1=<hex>`, donde `v1` es el HMAC-SHA256 de `<timestamp>.<cuerpo crudo>` con el secreto de tu endpoint — rechazá todo lo que tenga más de 5 minutos (protección contra replay). Las entregas fallidas se reintentan automáticamente con firma fresca, hasta 5 intentos.
| conversation.created | Arrancó una conversación nueva en cualquier canal. |
| message.created | Cayó un mensaje (visitante, humano, IA o sistema). |
| handoff.requested | La IA decidió que necesita un humano — el momento exacto, con el resumen. |
| conversation.resolved | Se cerró una conversación; te dice si la IA la cerró sola. |
Cada entrega y su estado quedan registrados — un webhook en el que no podés confiar es peor que ninguno.
Streaming en tiempo real
Para interfaces en vivo, abrí un WebSocket contra el stream del workspace y recibí los eventos de conversación según ocurren — el mismo canal que usan nuestras propias apps de agente.
wss://api.inteligenciaviva.com/v1/workspaces/{workspaceId}/stream
Errores y límites
Los errores son HTTP convencional: `400` petición malformada, `401` clave ausente o inválida, `403` clave sin alcance, `404` recurso que no está en este workspace, `429` límite de tasa (esperá y reintentá con jitter), `5xx` culpa nuestra — reintentá las peticiones idempotentes. El cuerpo siempre trae un `error.code` y un `error.message` humano. Los límites de tasa son por clave y generosos para integraciones reales.
Preguntas frecuentes
¿Esta documentación es aspiracional o la superficie real?
Real. Está escrita contra las rutas montadas del backend actual. Cuando algo aquí dice "en camino", es que todavía no existe — no documentamos humo.
¿Necesito un plan de pago para usar la API?
Sí — la API es parte de la plataforma de pago (Pro la incluye). El Widget gratuito y el plugin de WordPress son client-side y no necesitan API.
¿Cuál es la diferencia entre claves de solo lectura y de lectura-escritura?
Las de solo lectura pueden listar y consultar pero nunca mutar — ideales para dashboards y BI. Las de lectura-escritura pueden crear mensajes, contactos, agentes de IA y configuración.
¿Cómo me entero de mensajes nuevos — polling o webhooks?
Webhooks (`message.created`) para servidores, el stream por WebSocket para interfaces en vivo. El polling funciona, pero vas a chocar con los límites de tasa antes de lograr tiempo real.
¿Cómo verifico exactamente que un webhook vino de ustedes?
Recalculá el HMAC-SHA256 de `<t>.<cuerpo crudo>` con el secreto de tu endpoint y comparalo en tiempo constante con el valor `v1` de la cabecera `iv-signature`; rechazá si `t` tiene más de 300 segundos. El código funcional está en esta página.
¿Qué pasa si mi endpoint de webhooks está caído?
Registramos la entrega fallida y reintentamos automáticamente con timestamp y firma frescos, hasta 5 intentos. Si el endpoint fue eliminado o deshabilitado mientras tanto, los reintentos paran limpiamente.
¿Puede la IA escalar hacia mi propio sistema?
Sí — para eso existe `handoff.requested`. Se dispara en el momento en que la conversación pasa a una persona (el visitante lo pidió, hubo señales de crisis o de frustración, o la respuesta no se apoyaba en el conocimiento), con el resumen de la conversación, para que avisés a una persona o abrás un ticket en otro sistema.
¿Qué canales puedo manejar por la API hoy?
El chat web está vivo de punta a punta, y todo lo de esta referencia funciona hoy. Telegram y más canales de mensajería se conectan al mismo modelo de conversación a medida que salgan — tu integración no cambia.
¿Hay SDK?
Un SDK de Flutter alimenta nuestra propia app de agente y es la base del SDK white-label de Enterprise. Para servidores, la superficie REST es deliberadamente simple — cualquier cliente HTTP funciona sin wrapper.
¿Dónde reporto un bug de la API o un hueco en esta documentación?
Escribí a l@inteligenciaviva.com. Una documentación que miente también es un bug — la tratamos con la misma severidad.