Canal API
El canal API es un canal genérico basado en webhooks que te permite integrar cualquier plataforma de mensajería o sistema externo con Zelta Chat. Es la opción ideal cuando necesitas conectar un canal que no tiene integración nativa o cuando quieres crear un flujo de comunicación personalizado.
Casos de uso
| Caso de uso | Descripción |
|---|---|
| Canal de mensajería propio | Integra tu propia app de chat o sistema de mensajería interno |
| Plataformas sin integración nativa | Conecta servicios de mensajería que no tienen canal dedicado |
| Sistemas de tickets | Recibe notificaciones de sistemas externos como conversaciones |
| Formularios web | Convierte envíos de formularios en conversaciones de soporte |
| Integraciones a medida | Cualquier sistema que pueda enviar y recibir HTTP |
Crear un canal API
- Ve a Ajustes > Canales > + Agregar canal.
- Selecciona API.
- Completa los campos:
| Campo | Descripción |
|---|---|
| Nombre del canal | Nombre descriptivo (ej: "Canal Personalizado - App Móvil") |
| URL de webhook (opcional) | URL donde Zelta Chat enviará los mensajes salientes |
- Haz clic en Crear canal.
En la configuración del canal encontrarás el Identificador de bandeja de entrada (inbox_identifier). Es el valor que autentica a tus clientes API y el que va en la URL de todas las peticiones.
Trata el identificador como un secreto
Cualquiera que tenga el inbox_identifier puede crear contactos y mensajes en esta bandeja. No lo publiques en código de cliente que no controles.
Autenticación
El canal API no usa el header api_access_token. La autenticación va en la propia URL: el inbox_identifier de la bandeja, y a partir de él el contact_identifier del contacto.
| Valor | Qué es | Dónde se obtiene |
|---|---|---|
inbox_identifier | Identifica la bandeja del canal API | Ajustes > Canales > [tu canal API] |
contact_identifier | Identifica al contacto en la bandeja (source_id) | Lo devuelve la creación del contacto |
conversation_id | Número de la conversación | Lo devuelve la creación de la conversación |
Enviar mensajes a Zelta Chat
El flujo tiene tres pasos: crear el contacto, crear la conversación y crear el mensaje. Cada uno es una llamada distinta.
Paso 1: Crear el contacto
curl -X POST https://chat.zelta.dev/public/api/v1/inboxes/{inbox_identifier}/contacts \
-H "Content-Type: application/json" \
-d '{
"identifier": "cliente_12345",
"name": "Juan Pérez",
"email": "juan@ejemplo.com",
"phone_number": "+50760000000",
"custom_attributes": {
"order_id": "ORD-2024-001",
"source": "app_movil"
}
}'La respuesta incluye el source_id del contacto, que es el contact_identifier de las siguientes llamadas.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
identifier | string | No | Identificador único del contacto en tu sistema |
identifier_hash | string | Depende | HMAC del identifier. Obligatorio si activaste la validación de identidad |
name | string | No | Nombre del contacto |
email | string | No | Correo electrónico del contacto |
phone_number | string | No | Teléfono en formato E.164 |
avatar_url | string | No | URL de la foto de perfil |
custom_attributes | object | No | Atributos personalizados en formato clave-valor |
Paso 2: Crear la conversación
curl -X POST https://chat.zelta.dev/public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversations \
-H "Content-Type: application/json" \
-d '{
"custom_attributes": {
"order_id": "ORD-2024-001"
}
}'La respuesta incluye el id de la conversación, que usarás para enviar mensajes.
Paso 3: Crear el mensaje
curl -X POST https://chat.zelta.dev/public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversations/{conversation_id}/messages \
-H "Content-Type: application/json" \
-d '{
"content": "Hola, necesito ayuda con mi pedido"
}'| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
content | string | Sí | Contenido del mensaje |
echo_id | string | No | Identificador temporal para reconciliar el mensaje en tu cliente |
Los mensajes creados por esta vía son siempre entrantes: se registran como mensajes del contacto.
Enviar archivos adjuntos
Usa multipart/form-data en la misma URL de mensajes:
curl -X POST https://chat.zelta.dev/public/api/v1/inboxes/{inbox_identifier}/contacts/{contact_identifier}/conversations/{conversation_id}/messages \
-F "content=Adjunto mi comprobante de pago" \
-F "attachments[]=@/ruta/al/archivo.pdf"Otras operaciones disponibles
| Operación | Método y ruta (relativa a /public/api/v1/inboxes/{inbox_identifier}) |
|---|---|
| Consultar un contacto | GET /contacts/{contact_identifier} |
| Actualizar un contacto | PATCH /contacts/{contact_identifier} |
| Listar conversaciones del contacto | GET /contacts/{contact_identifier}/conversations |
| Consultar una conversación | GET /contacts/{contact_identifier}/conversations/{conversation_id} |
| Resolver una conversación | POST .../conversations/{conversation_id}/toggle_status |
| Indicar que el contacto está escribiendo | POST .../conversations/{conversation_id}/toggle_typing con typing_status en on u off |
| Marcar como leído | POST .../conversations/{conversation_id}/update_last_seen |
| Listar mensajes | GET .../conversations/{conversation_id}/messages |
Validación de identidad (HMAC)
Si quieres garantizar que un cliente no puede suplantar el identifier de otro contacto, activa Forzar validación de identidad de usuario en la configuración del canal. Con esa opción, las peticiones que no incluyan identifier_hash se rechazan.
El identifier_hash es el HMAC-SHA256 del identifier, firmado con el token HMAC del canal:
const crypto = require('crypto');
const identifierHash = crypto
.createHmac('sha256', HMAC_TOKEN_DEL_CANAL)
.update(identifier)
.digest('hex');Seguridad
Calcula el identifier_hash en tu servidor. Si el token HMAC viaja al cliente, la validación deja de aportar seguridad.
Recibir mensajes de Zelta Chat
Cuando un agente responde a una conversación del canal API, Zelta Chat envía una petición POST a la URL de webhook que configuraste en el canal.
Formato del webhook saliente
El payload es plano: los datos del mensaje van en la raíz y los del contexto en objetos anidados. Este ejemplo está abreviado —la petición real incluye además los objetos account, inbox y contact—:
{
"event": "message_created",
"id": 5678,
"content": "Hola Juan, con gusto te ayudo. ¿Puedes compartirme tu número de pedido?",
"content_type": "text",
"message_type": "outgoing",
"private": false,
"created_at": "2024-03-15T10:30:00Z",
"source_id": null,
"conversation": {
"display_id": 567,
"status": "open"
},
"sender": {
"id": 12,
"name": "María López"
}
}Cuando el mensaje lleva adjuntos, el payload incluye además un array attachments.
Verificar la firma del webhook
Las peticiones firmadas incluyen tres encabezados:
| Encabezado | Contenido |
|---|---|
X-Zelta-Signature | sha256= seguido del HMAC-SHA256 de timestamp.cuerpo |
X-Zelta-Timestamp | Marca de tiempo Unix usada en la firma |
X-Zelta-Delivery | Identificador único de la entrega |
La firma se calcula sobre la concatenación del timestamp, un punto y el cuerpo de la petición:
const crypto = require('crypto');
function verificarFirma(cuerpo, timestamp, firma, claveSecreta) {
const hash = crypto
.createHmac('sha256', claveSecreta)
.update(`${timestamp}.${cuerpo}`)
.digest('hex');
return firma === `sha256=${hash}`;
}Seguridad
Verifica siempre la firma antes de procesar la petición, y rechaza los timestamps demasiado antiguos para evitar reenvíos.
Eventos del webhook
| Evento | Descripción |
|---|---|
message_created | Se creó un mensaje en la conversación |
message_updated | Se actualizó un mensaje |
conversation_created | Se creó una nueva conversación |
conversation_updated | Cambió algún dato de la conversación |
conversation_status_changed | El estado de la conversación cambió (abierta, pendiente, pospuesta, resuelta) |
Solución de problemas
| Problema | Solución |
|---|---|
| Error 404 | Revisa el inbox_identifier y el contact_identifier de la URL; son la vía de autenticación |
| Error 422 | Revisa que el cuerpo de la petición tenga los campos requeridos |
HMAC failed: Invalid Identifier Hash Provided | El identifier_hash no coincide. Recalcúlalo en tu servidor con el token HMAC del canal |
| Webhook no recibe eventos | Confirma que la URL de webhook sea accesible públicamente y responda con 2xx |
| Conversaciones duplicadas | Reutiliza el contact_identifier devuelto al crear el contacto en lugar de crear uno nuevo cada vez |
| Archivos no se envían | Usa multipart/form-data en lugar de application/json para adjuntos |
Consejo
Guarda en tu sistema el contact_identifier y el conversation_id que devuelven las dos primeras llamadas. Con ellos puedes seguir enviando mensajes a la misma conversación sin volver a crear nada.