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/conversationsTodas 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/workspacesLos workspaces que esta credencial puede atender, con su rol en cada uno.

Conversaciones /conversations

GET/Listar conversaciones, filtrables por estado.
GET/{id}Una conversación con su estado, canal, contacto y asignación.
GET/{id}/messagesHistorial de mensajes (visitante, agente humano, IA, sistema).
POST/{id}/messagesEnviar un mensaje a la conversación como agente.
POST/{id}/assignAsignar la conversación a un agente humano o a un departamento.
POST/{id}/resolveCerrar 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-caseEstado 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}/readMarcar la conversación como leída por el equipo (contador de no leídos).
POST/{id}/reopenReabrir una conversación cerrada, conservando el historial. Sin esto, un cierre por error no tenía vuelta atrás.
POST/{id}/archiveArchivar o desarchivar. Sale de la bandeja sin cerrarse ni perder nada; el cuerpo es {valor:true|false}.
POST/{id}/pinFijar arriba o soltar. Las fijadas encabezan la primera página de la bandeja. Cuerpo: {valor:true|false}.
POST/{id}/muteSilenciar los avisos durante N horas, o {horas:null} para volver a oírla.
POST/{id}/unreadDejarla como no leída: retrocede la marca de lectura por detrás del último mensaje del cliente.

Contactos /contacts

GET/Listar contactos.
GET/{id}Un contacto con sus identidades y su historial de conversaciones.

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-sourcesFuentes de conocimiento asociadas a este agente.
POST/{id}/knowledge-sourcesAsociar 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/documentIndexar un documento como conocimiento fundamentado.
POST/urlIndexar una URL.
GET/{id}Estado y metadatos de la fuente.
DELETE/{id}Eliminar una fuente y sus vectores.
POST/{id}/reindexVolver 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.

Canales /channels

GET/Listar canales. Vivos hoy: chat web y API; más se conectan a medida que salgan.
PUT/{id}/credentialsDefinir las credenciales de un canal.
PUT/{id}/statusHabilitar o deshabilitar un canal.
POST/Crear un canal.
GET/{channelId}Un canal con su tipo, estado y ajustes.
GET/{channelId}/snippetLa línea que el cliente pega en su sitio. Es UNA sola: todo lo demás se configura aquí.
GET/{channelId}/configLa configuración del chat: lo publicado (`config`) y lo que este canal sobrescribe (`settings`). Son distintos y conviene no confundirlos.
PUT/{channelId}/configGuardar 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/publishVolver a publicar la configuración a la CDN sin cambiarla.
POST/{channelId}/avatarSubir la cara del asistente (≤512 KB). Va a R2 y la sirve la CDN.
POST/republicar-todosRepublicar todos los canales del workspace. Lo hace el cron cuando cambia el pack de cadenas; esto es para no esperar.

Agentes humanos y departamentos /agents · /departments

GET/agentsListar los agentes humanos del workspace.
POST/agents/{userId}/departmentsPoner un agente en un departamento.
GET/departmentsListar departamentos.
PUT/departments/{id}/routing-rulesDefinir reglas de enrutamiento de conversaciones entrantes.
POST/agentsInvitar a una persona al workspace, con su rol y departamentos.
GET/agents/{userId}Una persona del equipo.
POST/departmentsCrear un departamento con sus reglas de enrutado.
GET/departments/{id}Un departamento.

Webhooks, claves, facturación, analítica /webhooks · /api-keys · /billing · /analytics

POST/webhooksRegistrar un endpoint; recibís su secreto de firma una sola vez.
DELETE/webhooks/{id}Eliminar un endpoint.
POST/api-keysCrear una clave (solo lectura o lectura-escritura).
DELETE/api-keys/{id}Revocar una clave de inmediato.
GET/billing/subscriptionPlan, resoluciones de IA incluidas y uso del período.
GET/analyticsMétricas agregadas del workspace.
GET/webhooksListar los endpoints de webhook.
GET/webhooks/{id}/deliveriesHistorial de entregas de un webhook, con reintentos. Es lo que dice si el fallo es tuyo o nuestro.
GET/api-keysListar las claves. Nunca se devuelve el secreto: solo su prefijo.

Herramientas del agente /conversations/{id} · /canned-responses · /tags · /presence

GET/conversations/{id}/notesNotas internas de la conversación. NUNCA las ve el visitante.
POST/conversations/{id}/notesAñadir una nota interna.
DELETE/conversations/{id}/notes/{noteId}Borrar una nota interna.
GET/canned-responsesRespuestas predefinidas del workspace, con su atajo.
POST/canned-responsesCrear una respuesta predefinida.
PATCH/canned-responses/{cannedId}Editar una respuesta predefinida.
DELETE/canned-responses/{cannedId}Borrar una respuesta predefinida.
POST/presenceLatido 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-usageConsumo de inferencia del workspace por día y las conversaciones que más gastan.
GET/tagsEtiquetas del workspace.
GET/conversations/{id}/tagsEtiquetas de una conversación.
POST/conversations/{id}/tagsEtiquetar 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}/transferTransferir la conversación a un departamento. Manda sobre las reglas de enrutado: una transferencia hecha a mano no se deshace sola.
POST/contacts/{contactId}/blockBloquear un contacto. Se le responde 403 sin detalle: a quien abusa no se le explica cómo se le detecta.

Adjuntos, dispositivos y workspaces /conversations/{id}/attachments · /devices · /workspaces

POST/conversations/{id}/attachmentsSubir un adjunto como agente. Lista blanca estricta y 10 MB: no entra nada que un navegador pueda ejecutar.
GET/conversations/{id}/attachmentsAdjuntos 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/registerRegistrar el token push de un dispositivo, para avisar a una persona cuando la IA traspasa. Fuera del prefijo de workspace: `/v1/devices/register`.
POST/workspacesCrear un workspace. Fuera del prefijo: `/v1/workspaces`.

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.createdArrancó una conversación nueva en cualquier canal.
message.createdCayó un mensaje (visitante, humano, IA o sistema).
handoff.requestedLa IA decidió que necesita un humano — el momento exacto, con el resumen.
conversation.resolvedSe 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 confianza de la IA cae bajo el umbral del workspace, 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.