API de Chapp

Manual de integración: envío de mensajes, WebSocket de eventos, lectura de mensajes y alta de líneas.

Estás viendo el manual público: los ejemplos usan valores de muestra. Inicia sesión para que se rellenen con los datos reales de tus líneas.

Autenticación

La API usa un token de integración, que es por empresa. Un token da acceso a todas las líneas de tu empresa y a nada más: los datos de otras empresas son inaccesibles aunque conozcas sus identificadores.

No lo confundas con la clave de línea. Son credenciales de dos servidores distintos:
  • Token de integración — el de esta página. Autentica contra la API de Chapp. Es el que necesitas para todo lo que sigue.
  • Clave de línea — se genera sola al crear cada línea y autentica contra el servidor de mensajería. Solo sirve para el envío directo (ver Clave de línea).
Base: https://www.chapp.cl/api/v1

Envía el token en la cabecera Authorization. Si tu cliente no te deja controlar esa cabecera, también se acepta X-Api-Key.

Authorization: Bearer chapp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# alternativa
X-Api-Key: chapp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
El token lo genera el dueño de la cuenta Chapp. El chapp_xxxx… de arriba es relleno: cada empresa saca el suyo desde API → Mis tokens con la sesión iniciada, y te lo entrega para la integración. Se muestra una sola vez, porque en la base queda solo un hash.

Formato de las respuestas

Todas las respuestas son JSON y traen el campo ok. A diferencia del endpoint directo (ver Clave de línea), aquí sí puedes confiar en el código HTTP.

// Éxito
{ "ok": true, "lineas": [ ... ] }

// Error
{ "ok": false, "error": "linea_no_conectada",
  "mensaje": "La linea existe pero no esta conectada a WhatsApp." }
HTTPSignificado
200 / 201Todo bien.
401Token faltante, inválido o revocado.
404La línea no existe o no es de tu empresa.
409Conflicto: línea desconectada o número ya registrado.
422Faltan parámetros o son inválidos (detalle en errors).
429Superaste el límite de 120 requests por minuto.
502El servidor de mensajería rechazó la operación.
En los endpoints, {'{'}linea{'}'} acepta indistintamente el uuid o el número de la línea. Usa el que te resulte más cómodo.

1 Enviar mensajes

Envía texto, una imagen o un documento a un contacto o a un grupo.

POSThttps://www.chapp.cl/api/v1/mensajes

Parámetros

CampoDescripción
linearequeridoLínea emisora: uuid o número.
fonorequeridoDestino. Número del contacto, o JID del grupo si es_grupo=1.
mensajerequeridoTexto del mensaje. Si hay adjunto, va como leyenda.
es_grupoopcionaltrue si el destino es un grupo.
tipo_adjuntoopcionalPNG, PDF o vacio (por defecto).
url_adjuntoopcionalURL pública de la imagen cuando tipo_adjunto=PNG.
url_documentoopcionalURL pública del archivo cuando tipo_adjunto=PDF.

Ejemplo — texto

curl -X POST "https://www.chapp.cl/api/v1/mensajes" \
  -H "Authorization: Bearer $CHAPP_TOKEN" \
  -H "Accept: application/json" \
  -d "linea=__FONO__" \
  -d "fono=56911111111" \
  -d "mensaje=Hola desde la API de Chapp"

Ejemplo — imagen

curl -X POST "https://www.chapp.cl/api/v1/mensajes" \
  -H "Authorization: Bearer $CHAPP_TOKEN" \
  -d "linea=__FONO__" \
  -d "fono=56911111111" \
  -d "mensaje=Adjunto la cotización" \
  -d "tipo_adjunto=PNG" \
  -d "url_adjunto=https://midominio.cl/img/cotizacion.png"

Ejemplo — PHP

<?php
$ch = curl_init('https://www.chapp.cl/api/v1/mensajes');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer '.getenv('CHAPP_TOKEN'),
        'Accept: application/json',
    ],
    CURLOPT_POSTFIELDS     => http_build_query([
        'linea'   => '__FONO__',
        'fono'    => '56911111111',
        'mensaje' => 'Hola desde PHP',
    ]),
]);
$r = json_decode(curl_exec($ch), true);
curl_close($ch);

if (!$r['ok']) {
    error_log('Chapp: '.$r['mensaje']);
}

Ejemplo — Node.js

const r = await fetch('https://www.chapp.cl/api/v1/mensajes', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${'{'}process.env.CHAPP_TOKEN{'}'}`,
    'Accept': 'application/json',
  },
  body: new URLSearchParams({
    linea:   '__FONO__',
    fono:    '56911111111',
    mensaje: 'Hola desde Node',
  }),
});

const data = await r.json();
if (!data.ok) throw new Error(data.mensaje);
Formato de números. Formato internacional sin + ni espacios. Si envías 9 dígitos se antepone 56 automáticamente; con 8 dígitos, 569.
Si la línea no está conectada a WhatsApp, la respuesta es 409 con error: "linea_no_conectada". Conviene chequear el estado antes de una campaña masiva (ver sección 4).

2 WebSocket de eventos

Conexión en tiempo real para enterarte de mensajes nuevos, cambios de estado de una línea y códigos QR de vinculación. Es solo de lectura: el servidor emite eventos, el cliente no envía comandos.

WSSwss://api.chapp.cl/ws?token=__TOKEN_WS__
El token del WebSocket es global de la plataforma, no por empresa, y viaja como parámetro en la URL. Solicítalo a soporte y no lo publiques. Está pendiente migrarlo a tokens por empresa (ver Sin API todavía).

Eventos emitidos

Cada mensaje es un JSON. Discrimina por el campo evento.

EventoPayloadCuándo
nuevo_mensaje fono, fono_origen, fono_destino Llegó o se envió un mensaje en la línea fono.
estado_linea fono, estado: conectado · desconectado · esperando_qr La línea cambió de estado de sesión.
qr_linea fono, qr (string a renderizar como QR) Hay un QR nuevo disponible durante la vinculación.

Ejemplo — patrón recomendado

let ultimoId = 0;
const ws = new WebSocket('wss://api.chapp.cl/ws?token=__TOKEN_WS__');

ws.onmessage = async (e) => {
  const data = JSON.parse(e.data);

  if (data.evento === 'nuevo_mensaje') {
    // El evento avisa, no trae el contenido. Se va a buscar
    // con el endpoint del punto 3, desde el último id conocido.
    const r = await fetch(
      'https://www.chapp.cl/api/v1/mensajes/__FONO__/nuevos?desde=' + ultimoId,
      { headers: { 'Authorization': 'Bearer ' + TOKEN } }
    );
    const j = await r.json();
    ultimoId = j.ultimo_id;
    j.mensajes.forEach(procesar);
  }

  if (data.evento === 'estado_linea') console.log(data.fono, data.estado);
  if (data.evento === 'qr_linea')     renderizarQr(data.qr);
};

ws.onclose = (e) => {
  if (e.code === 4401) return console.error('Token inválido');
  setTimeout(reconectar, 5000);
};
nuevo_mensaje es una notificación, no el mensaje. Trae solo los números involucrados. Mantén un respaldo por polling cada 5 s con /nuevos?desde= por si la conexión se cae — es como opera el chat de la plataforma.

3 Leer mensajes

Dos endpoints: la conversación con un contacto, y todo lo posterior a un id (para sincronizar).

Conversación con un contacto

GEThttps://www.chapp.cl/api/v1/mensajes/__FONO__/{numero}
ParámetroDescripción
limiteopcionalCuántos mensajes traer, 1–200. Por defecto 50.
desdeopcionalSolo mensajes con id mayor a este.
curl "https://www.chapp.cl/api/v1/mensajes/__FONO__/56911111111?limite=20" \
  -H "Authorization: Bearer $CHAPP_TOKEN"

Sincronizar mensajes nuevos

GEThttps://www.chapp.cl/api/v1/mensajes/__FONO__/nuevos?desde={id}

Devuelve los mensajes posteriores a desde en orden ascendente, junto con ultimo_id para encadenar la siguiente consulta. Es el endpoint que va de la mano del WebSocket.

Respuesta

{
  "ok": true,
  "linea": "__FONO__",
  "ultimo_id": 1482,
  "mensajes": [
    {
      "id": 1482,
      "direccion": "recibido",
      "timestamp": 1753012800,
      "fecha": "2026-07-20T10:00:00-04:00",
      "fono_origen": "56911111111",
      "fono_destino": "__FONO__",
      "push_name": "Juan Pérez",
      "es_grupo": false,
      "grupo_jid": null,
      "tipo": "text",
      "mensaje": "Hola, ¿tienen stock?",
      "id_mensaje": "3EB0...",
      "visto": null
    }
  ]
}
CampoDescripción
idId interno. Es el que se usa para paginar con desde.
direccionenviado (saliente) o recibido (entrante).
timestampEpoch Unix en segundos.
fechaEl mismo instante en ISO 8601, por comodidad.
push_nameNombre que el contacto tiene puesto en WhatsApp.
es_grupo / grupo_jidSi el mensaje pertenece a un grupo, y cuál.
tipoTipo de contenido (text, imagen, documento).
mensajeContenido, o nombre del archivo si es adjunto.
id_mensajeIdentificador del mensaje en WhatsApp.

4 Registrar una línea

Listar tus líneas

GEThttps://www.chapp.cl/api/v1/lineas
{
  "ok": true,
  "lineas": [
    {
      "uuid": "__UUID__",
      "fono": "__FONO__",
      "alias": "Ventas",
      "puerto": __PUERTO__,
      "vinculada": true,
      "estado": "conectada"
    }
  ]
}

estado puede ser conectada, desconectada o desvinculada. Consulta una línea puntual con GET /api/v1/lineas/{'{'}linea{'}'}.

Crear una línea

POSThttps://www.chapp.cl/api/v1/lineas
CampoDescripción
fonorequeridoNúmero de la línea, formato internacional sin +.
aliasrequeridoNombre para identificarla en el panel.
guardar_mensajesopcionalGuardar el historial de mensajes.
guardar_adjuntosopcionalGuardar los archivos adjuntos.
curl -X POST "https://www.chapp.cl/api/v1/lineas" \
  -H "Authorization: Bearer $CHAPP_TOKEN" \
  -d "fono=56922222222" \
  -d "alias=Ventas" \
  -d "guardar_mensajes=1"

Responde 201. Si el número ya está registrado, 409 con error: "linea_duplicada".

Vincular: obtener el QR

GEThttps://www.chapp.cl/api/v1/lineas/__UUID__/qr

La línea nace sin vincular: hay que escanear un QR desde WhatsApp del teléfono para que pueda enviar. El QR tarda unos segundos en generarse y se renueva periódicamente.

// Todavía no hay QR — reintenta
{ "ok": true, "estado": "esperando_qr", "qr": null, "mensaje": "…" }

// QR listo: renderízalo como código QR en tu interfaz
{ "ok": true, "estado": "esperando_qr", "qr": "2@AbCd…" }

// Ya quedó vinculada: deja de consultar
{ "ok": true, "estado": "vinculada", "qr": null }
El campo qr es el string crudo de WhatsApp: renderízalo con cualquier librería de QR. También llega por el WebSocket como evento qr_linea, que evita el polling.

Flujo completo

#Paso
1POST /api/v1/lineas — crea la línea y devuelve su uuid.
2GET /api/v1/lineas/{'{'}uuid{'}'}/qr — consulta hasta que qr venga no nulo.
3Escanea el QR desde WhatsApp del teléfono.
4El estado pasa a vinculada / conectada. Ya puede enviar.
Eliminar, desvincular y reiniciar líneas siguen disponibles solo desde el panel web, no por API. Son operaciones destructivas y preferimos no exponerlas a un token hasta tener permisos por alcance.

Clave de línea (modo alternativo)

Cada línea tiene su propia clave, generada automáticamente al crearla, que le permite hablar directo con el servidor de mensajería. Es el mecanismo antiguo: solo sirve para enviar, no valida a qué empresa perteneces y responde texto plano. Para integraciones nuevas usa el token de integración y los endpoints de la API v1.

La clave de línea no es un secreto fuerte. Se deriva del número y el puerto de la línea, así que es predecible y no se puede revocar sin reinstalar esa línea. Úsala solo si ya tienes una integración antigua funcionando con ella; para todo lo nuevo, el token de integración.
La clave de cada línea se ve en esta misma sección con la sesión iniciada. Pídesela a la empresa dueña de la línea.
POSThttps://api.chapp.cl:__PUERTO__
curl -X POST "https://api.chapp.cl:__PUERTO__" \
  -d "apikey=__APIKEY__" \
  -d "fono=56911111111" \
  -d "mensaje=Hola"

# Responde texto plano, SIEMPRE con HTTP 200:
#   "OK MENSAJE ENVIADO CORRECTAMENTE"  → enviado
#   "ERROR AL AUTENTICAR"               → apikey incorrecta
En este endpoint el código HTTP siempre es 200, incluso en error. Tienes que mirar el prefijo del cuerpo (OK / ERROR). La API v1 no tiene este problema.

Funciones sin API todavía

Estas capacidades existen dentro de la plataforma pero aún no están expuestas por la API v1. Si necesitas alguna, avísanos para priorizarla.

FunciónEstado actual
Webhook de mensajes entrantesNo existe. Hay que mantener el WebSocket abierto o hacer polling con /nuevos?desde=. Un webhook HTTP sería bastante más simple de integrar.
Token del WebSocket por empresaHoy es un token global de plataforma, compartido y visible en el navegador. Debería emitirse por empresa, igual que los de la API v1.
Contactos (CRUD)Solo desde el panel: listar, crear, actualizar y bloquear.
Pipeline / CRMSolo desde el panel: etapas, tags, notas y mover contactos.
GruposCrear grupo, agregar participantes y cambiar imagen existen en el servidor de mensajería, pero no están expuestos en la API v1.
Eliminar / desvincular / reiniciar líneasSolo desde el panel. Son destructivas y conviene exponerlas recién con permisos por alcance.
Eliminar mensajesSolo desde el panel.
Descargar adjuntosLos mensajes traen el nombre del archivo, pero bajarlo requiere sesión del panel.
InstagramFunciona como canal en la plataforma, pero no tiene API de envío ni de lectura.
Confirmación de entregaEl envío confirma que se aceptó, pero no devuelve el id del mensaje ni informa entregado/leído.
Permisos por alcanceUn token da acceso a todo lo de la empresa. No se puede emitir uno de solo lectura, ni acotado a una línea.