API y webhooks

Conecta tu sistema con tu asistente, sin pedirle nada a nadie

Una API REST para leer y escribir los datos de tu negocio y webhooks firmados que avisan a tu sistema cuando llega un contacto, se agenda una cita o el asistente deriva a una persona. Las llaves y los webhooks se administran desde tu panel, en Integraciones.

/api/v1Dirección base
6Eventos por webhook
120/minSolicitudes por llave
1. Autenticación

Una llave por sistema

Entra a tu panel, menú Integraciones, y crea una llave con un nombre (por ejemplo, el sistema que la va a usar). La llave completa se muestra una sola vez: guárdala en tu sistema. Si la pierdes, revócala y crea otra.

Cada solicitud lleva la llave en la cabecera Authorization:

curl -H "Authorization: Bearer ap_k7f3m2x9q1_a1b2c3..." https://asistentepro.cl/api/v1/cuenta
  • Solo lectura: consulta contactos, conversaciones, citas y catálogo.
  • Lectura y escritura: además cambia estados, crea citas, reemplaza el catálogo y envía mensajes.
  • Una llave solo ve los datos de su propio negocio. Los ids de otra cuenta responden 404.
2. Formato

Siempre JSON, siempre la misma forma

Las respuestas correctas traen ok: true y los datos en data; las listas agregan paginacion. Los errores traen ok: false, un código estable en error y una explicación en message.

{
  "ok": true,
  "data": [
    {
      "id": "clx1...",
      "nombre": "Ana Pérez",
      "contacto": "56912345678",
      "correo": "[email protected]",
      "canal": "whatsapp",
      "estado": "calificado",
      "etapa": "seguimiento",
      "notas": "Quiere cotizar 3 servicios para noviembre.",
      "conversacionId": "clx9...",
      "creadoEl": "2026-10-20T14:03:11.000Z",
      "actualizadoEl": "2026-10-20T14:09:40.000Z"
    }
  ],
  "paginacion": { "pagina": 1, "porPagina": 50, "total": 1 }
}

Las fechas van en ISO 8601 (UTC). Los teléfonos, con código de país y sin signos: 56912345678.

3. Rutas

Lo que un sistema externo necesita de verdad

Dirección base: https://asistentepro.cl/api/v1

GET/v1/cuentalectura

Devuelve el negocio y la llave con la que entraste. Sirve para probar la conexión.

curl -H "Authorization: Bearer TU_LLAVE" https://asistentepro.cl/api/v1/cuenta
GET/v1/leadslectura

Lista los contactos (leads) del negocio, del más nuevo al más antiguo. Filtros: desde, hasta (fecha de creación, ISO 8601), estado (nuevo, calificado, contacto_comercial, ganado, perdido), canal (whatsapp, instagram, facebook, web). Paginado con pagina y porPagina (máximo 100).

curl -H "Authorization: Bearer TU_LLAVE" "https://asistentepro.cl/api/v1/leads?estado=nuevo&desde=2026-10-01&porPagina=50"
GET/v1/leads/:idlectura

Un contacto con su ficha completa y el id de su última conversación.

curl -H "Authorization: Bearer TU_LLAVE" https://asistentepro.cl/api/v1/leads/ID_DEL_LEAD
PATCH/v1/leads/:idescritura

Cambia el estado y/o las notas (la ficha) de un contacto. Dispara el evento lead.actualizado.

curl -X PATCH -H "Authorization: Bearer TU_LLAVE" -H "Content-Type: application/json" \
  -d '{"estado":"ganado","notas":"Cerró plan anual, factura 1234"}' https://asistentepro.cl/api/v1/leads/ID_DEL_LEAD
GET/v1/conversaciones/:id/mensajeslectura

Los mensajes de una conversación en orden cronológico. Cada mensaje dice si lo escribió el cliente, el asistente o una persona del equipo. Paginado (porPagina hasta 200).

curl -H "Authorization: Bearer TU_LLAVE" https://asistentepro.cl/api/v1/conversaciones/ID_CONVERSACION/mensajes
GET/v1/citaslectura

Citas en un rango de fechas (desde, hasta; por defecto los próximos 30 días; máximo 92 días). Filtro estado: agendada, hecha, cancelada.

curl -H "Authorization: Bearer TU_LLAVE" "https://asistentepro.cl/api/v1/citas?desde=2026-10-20&hasta=2026-11-20"
POST/v1/citasescritura

Crea una cita del negocio con la misma validación que el panel: titulo e inicio obligatorios, correo válido si viene, y 409 horario_ocupado si choca con otra cita. Manda la invitación de calendario (si hay correo) y programa los recordatorios por WhatsApp (si hay contacto). Dispara cita.creada.

curl -X POST -H "Authorization: Bearer TU_LLAVE" -H "Content-Type: application/json" \
  -d '{"titulo":"Visita técnica","inicio":"2026-10-22T15:00:00-03:00","duracionMin":45,"contacto":"56912345678","nombre":"Ana Pérez","correo":"[email protected]","notas":"Revisión anual"}' \
  https://asistentepro.cl/api/v1/citas
GET/v1/catalogolectura

Todos los productos o servicios del catálogo, con precio, stock y categoría. El costo interno nunca sale.

curl -H "Authorization: Bearer TU_LLAVE" https://asistentepro.cl/api/v1/catalogo
PUT/v1/catalogoescritura

Reemplaza el catálogo con la lista que mandas (hasta 500 productos). Empareja por nombre: los que existen se actualizan, los nuevos se crean y los que no vienen quedan inactivos (no se borran: conservan foto, orden y destacado). Campos: nombre (obligatorio), precio, stock, categoria, descripcion, precioTexto, activo.

curl -X PUT -H "Authorization: Bearer TU_LLAVE" -H "Content-Type: application/json" \
  -d '{"productos":[{"nombre":"Queso mantecoso 1 kg","precio":8990,"stock":24,"categoria":"Quesos"},{"nombre":"Jamón serrano 250 g","precio":6490,"stock":0,"categoria":"Cecinas"}]}' \
  https://asistentepro.cl/api/v1/catalogo
POST/v1/mensajesescritura

Envía un texto por WhatsApp a un contacto, SOLO si la ventana de 24 horas está abierta (el cliente escribió hace menos de 24 h). Si está cerrada responde 409 ventana_cerrada y no envía nada: WhatsApp no acepta texto libre fuera de esa ventana. Con pausarAsistente: true el asistente deja de responder en ese hilo hasta que alguien lo libere desde el panel.

curl -X POST -H "Authorization: Bearer TU_LLAVE" -H "Content-Type: application/json" \
  -d '{"contacto":"56912345678","texto":"Tu pedido #482 ya está listo para retiro."}' https://asistentepro.cl/api/v1/mensajes
4. Webhooks

Te avisamos cuando pasa algo

En Integraciones agrega la dirección https de tu sistema y elige los eventos. Cada vez que ocurra uno, hacemos un POST con JSON a esa dirección. Tu servidor debe responder un código 2xx en menos de 8 segundos; haz el trabajo pesado después de responder.

EventoCuándo se envía
lead.creadoUn contacto nuevo escribió por primera vez, o lo creó el panel o la API.
lead.actualizadoCambió el estado o la ficha de un contacto (por el asistente, el panel o la API).
cita.creadaSe agendó una cita (por el asistente, el panel o la API).
cita.canceladaSe canceló o eliminó una cita.
derivacion.creadaEl asistente derivó una conversación a una persona: pidió hablar con alguien, reclamo, duda que no pudo resolver, o el servicio de IA no pudo responder.
mensaje.recibidoLlegó un mensaje de un cliente por WhatsApp o Instagram.

El cuerpo lleva id (único por aviso, se repite en los reintentos: úsalo para no procesar dos veces), evento, fecha, negocioId y datos con la misma forma que devuelve la API.

POST https://misistema.cl/webhooks/asistentepro
Content-Type: application/json
X-AsistentePro-Evento: cita.creada
X-AsistentePro-Entrega: wh_8f2c...
X-AsistentePro-Timestamp: 1760990000
X-AsistentePro-Firma: 3b1f9c...   (HMAC-SHA256 en hexadecimal)

{
  "id": "wh_8f2c...",
  "evento": "cita.creada",
  "fecha": "2026-10-20T18:00:00.000Z",
  "negocioId": "clorg...",
  "datos": {
    "id": "clx5...",
    "titulo": "Visita técnica",
    "contacto": "56912345678",
    "inicio": "2026-10-22T18:00:00.000Z",
    "duracionMin": 45,
    "estado": "agendada"
  }
}
  • Reintentos: si tu servidor no responde 2xx, reintentamos hasta 3 veces en total (de inmediato, 1 minuto después y 5 minutos después). Una redirección (3xx) cuenta como fallo.
  • Direcciones: solo https públicas. Direcciones locales o de redes privadas se rechazan al guardarlas y al enviar.
  • Probar: el botón "Probar" del panel manda un evento prueba y te muestra qué respondió tu servidor. Las últimas 20 entregas y su estado quedan a la vista.
5. Firma

Comprueba que el aviso viene de AsistentePro

Al crear el webhook te damos un secreto (una sola vez). Cada aviso trae X-AsistentePro-Timestamp (segundos unix) y X-AsistentePro-Firma: el HMAC-SHA256, con tu secreto, del texto <timestamp>.<cuerpo>, en hexadecimal. Calcula lo mismo sobre el cuerpo crudo que recibiste y compara. Descarta avisos con más de 5 minutos.

import crypto from 'node:crypto'

// cuerpoCrudo: el cuerpo EXACTO que llegó (string o Buffer), no el JSON ya parseado y vuelto a serializar.
function firmaValida(secreto, cabeceras, cuerpoCrudo) {
  const ts = Number(cabeceras['x-asistentepro-timestamp'])
  const firma = String(cabeceras['x-asistentepro-firma'] || '')
  if (!ts || Math.abs(Date.now() / 1000 - ts) > 300) return false // más de 5 minutos: se descarta
  const esperada = crypto.createHmac('sha256', secreto).update(`${ts}.${cuerpoCrudo}`).digest('hex')
  const a = Buffer.from(esperada, 'hex'); const b = Buffer.from(firma, 'hex')
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}
6. Errores y límites

Códigos que vas a ver

RespuestaQué significa
401 llave_invalidaLa llave no existe, está mal escrita o fue revocada.
403 permiso_insuficienteLa llave es de solo lectura y la ruta modifica datos.
403 cuenta_pausadaLa cuenta del negocio está en pausa.
404 no_encontradoEl id no existe en esta cuenta (los ids de otros negocios siempre dan 404).
400 fecha_invalida / estado_invalido / faltan_datos / correo_invalidoRevisa el cuerpo o los filtros; el campo message explica qué falta.
409 horario_ocupadoYa hay una cita en ese horario (viene citaId).
409 ventana_cerradaNo se puede enviar texto libre a ese contacto hasta que vuelva a escribir.
429 rate_limitedMás de 120 solicitudes por minuto con la misma llave. Espera lo que dice Retry-After.

Límite: 120 solicitudes por minuto por llave (cabeceras X-RateLimit-Limit y X-RateLimit-Remaining). Hasta 10 llaves activas y 10 webhooks por negocio.

¿Necesitas una ruta que no está? Escríbenos desde tu panel: esta primera versión cubre lo que un sistema externo usa de verdad y crece con lo que los negocios piden.