API REST y webhooks de WhatsApp para conectar tu sistema.

La API REST y los webhooks de WhatsApp de Omniia conectan tu sistema con tus conversaciones: envías plantillas y mensajes, creas o actualizas contactos y recibes cada evento firmado con HMAC-SHA256. Esta página es la referencia práctica para desarrolladores, con ejemplos en curl y Node.js que coinciden con lo que hoy responde la API.

  • Sin tarjeta de crédito
  • Sin permanencia
  • Soporte en español
  • Una clave por integración, que se revoca al instante sin tocar las demás
  • Plantillas, textos y archivos con un solo POST /messages
  • Encabezado Idempotency-Key para que un reintento no envíe el WhatsApp dos veces
  • Webhooks firmados con HMAC-SHA256, con reintentos y registro de entregas
  • Errores con nombre propio, como meta_window_expired o template_variables_mismatch
  • La misma API para canales por QR y por la API oficial de Meta

Autenticación sin vueltas

Creas una clave en Ajustes → API y la envías como Authorization: Bearer. Se muestra una sola vez y puedes revocarla cuando quieras sin afectar las otras integraciones.

Plantillas validadas antes de salir

Omniia compara el nombre, el idioma, la cantidad de variables y el archivo del encabezado con tu copia local de plantillas. Si algo no cuadra, responde con un error claro antes de gastar la llamada a Meta.

Eventos firmados

Cada webhook trae X-Omniia-Signature y X-Omniia-Timestamp. Con el secreto de la suscripción compruebas que viene de Omniia y descartas reenvíos viejos.

Reintentos y registro

Si tu servidor no responde 2xx, Omniia reintenta a 1 minuto, 5 minutos, 30 minutos y 2 horas. En Ajustes → API ves cada entrega y la puedes reintentar a mano.

Actualizado el 15 de octubre de 2026

Qué incluyen la API y los webhooks de WhatsApp de Omniia

Son tres piezas. La API REST recibe lo que tu sistema le pide a Omniia: enviar, crear, consultar, cerrar. Los webhooks le avisan a tu sistema lo que pasa en Omniia. Y la URL de una automatización arranca una secuencia sin clave de API. Para qué sirve cada una en un negocio está en integrar WhatsApp con tu CRM o sistema; aquí vamos al detalle técnico.

La base es https://crm.omniia.app/api/v1 y todo va en JSON. Los errores traen un campo error con el código y, a veces, un detail. Los teléfonos van solo con dígitos e indicativo (573001234567), las fechas en ISO 8601 y UTC, y los ids son UUID que entrega la misma API. La documentación completa está dentro de la app, en Ajustes → API, y se descarga en PDF.

RutaPara qué sirve
GET /meProbar la clave
GET /channelsCanales con su id, tipo (oficial o QR) y estado
GET /agentsAsesores, para asignar el chat al enviar
GET /templatesPlantillas con categoría, variables y tipo de encabezado
POST /messagesEnviar texto, archivo o plantilla
GET /messagesLo que entró o salió desde una fecha
GET y POST /contacts, GET /contacts/:idBuscar, crear y leer contactos
PATCH /contacts/:id y /contacts/by-phone/:phoneActualizar datos y campos personalizados
GET /contact-fieldsLista de campos personalizados
GET /contacts/:id/documentsArchivos del contacto
GET /conversations y /conversations/:id/messagesChats y su historial
POST /conversations/:id/close y /reopenCerrar o reabrir

Autenticación con clave de API

Solo el dueño o un administrador crea claves, en Ajustes → API. La clave empieza por omn_live_ y se muestra una sola vez: Omniia guarda solo su huella. Usa una por integración (“n8n producción”, “ERP”, “sitio web”): si una se filtra, la revocas y las demás siguen andando. Va en cada petición con Authorization: Bearer; una clave inválida responde 401 con invalid_api_key.

Probar la clave y listar los canales
curl https://crm.omniia.app/api/v1/me \
  -H "Authorization: Bearer omn_live_TU_CLAVE"

# -> { "workspace": { "id": "<uuid>", "name": "Mi empresa", "slug": "mi-empresa" } }

curl https://crm.omniia.app/api/v1/channels \
  -H "Authorization: Bearer omn_live_TU_CLAVE"

# -> [{ "id": "<uuid>", "name": "Ventas", "type": "meta", "status": "connected", "enabled": true }]

Enviar una plantilla de WhatsApp por API

Para escribirle primero a un cliente por un canal de la API oficial necesitas una plantilla aprobada por Meta. El orden es este:

  1. 1Consulta GET /channels y guarda el id del canal oficial (type meta).
  2. 2Consulta GET /templates con ese channelId y mira tres datos: variableCount (cuántos valores enviar), headerFormat (si lleva imagen, video o documento) y category. Si acabas de crear la plantilla en WhatsApp Manager, agrega refresh=1 una vez para sincronizarla.
  3. 3Envía con POST /messages: type template, el nombre, el idioma y las variables en el orden de la plantilla.
Factura con PDF en el encabezado, asignada a un asesor
curl -X POST https://crm.omniia.app/api/v1/messages \
  -H "Authorization: Bearer omn_live_TU_CLAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: FE-20931" \
  -d '{
    "channelId": "<id-del-canal-oficial>",
    "to": "573001234567",
    "type": "template",
    "template": {
      "name": "factura_emitida",
      "language": "es_CO",
      "variables": ["Laura", "FE-20931", "$184.900"],
      "headerMedia": {
        "type": "document",
        "mediaUrl": "https://tu-servidor.com/facturas/FE-20931.pdf",
        "filename": "Factura-FE-20931.pdf"
      }
    },
    "assignedUserId": "<id-del-asesor>"
  }'

# -> {
#      "messageId": "<uuid>",
#      "conversationId": "<uuid>",
#      "contactId": "<uuid>",
#      "status": "sent",
#      "externalId": "wamid.HBgM...",
#      "assignedUserId": "<id-del-asesor>"
#    }

Omniia crea el contacto si no existe y reutiliza la conversación de ese canal, reabriéndola si estaba cerrada. Con assignedUserId el chat queda fijado a ese asesor y la respuesta del cliente le llega a él. Ojo con el estado: sent quiere decir que Meta aceptó el envío, no que llegó; la entrega, la lectura o el fallo llegan después con el webhook message.status. Si el documento del encabezado es siempre el mismo, no hace falta repetirlo: Omniia usa el que quedó ligado a la plantilla.

La ventana de 24 horas y los canales por QR

Por un canal oficial, un texto libre solo sale si el cliente escribió en las últimas 24 horas; si no, la API responde 403 con meta_window_expired (la regla completa, en la ventana de 24 horas de WhatsApp). Por QR no hay plantillas (template_not_supported_by_channel) y el texto sale en cualquier momento, con los riesgos que explicamos en WhatsApp por QR vs. API oficial.

Idempotency-Key: un reintento no es un segundo mensaje

Si tu sistema repite un POST /messages porque se cortó la red, el cliente no debería recibir dos facturas. Envía Idempotency-Key con un identificador tuyo, único por envío: el número de factura, de radicado o de pedido. Si la clave llega otra vez, Omniia no envía nada y devuelve la respuesta original con Idempotent-Replay: true; si la primera sigue en curso, responde 409. Si el envío falló, la clave se libera. Se recuerdan siete días.

Errores comunes y cómo resolverlos

RespuestaQué pasóQué hacer
401 invalid_api_keyClave inexistente, revocada o mal escritaRevisa el encabezado Authorization
403 meta_window_expiredTexto libre fuera de la ventana de 24 horasEnvía una plantilla
404 template_not_foundEse nombre e idioma no existen en el canalCompara con GET /templates (refresh=1)
400 template_not_approvedMeta no la ha aprobado o la rechazóRevisa su estado con status=all
400 template_variables_mismatchOtra cantidad de variablesMira expected y received
400 template_header_media_requiredFalta el archivo del encabezadoEnvía template.headerMedia
429 rate_limitedSuperaste el límite por minuto de la claveEspera lo que diga Retry-After
502 send_failedEl canal rechazó el envíoLee el campo detail

El límite se cuenta por clave, con un presupuesto para consultas y otro para escrituras, y cada respuesta trae X-RateLimit-Remaining para frenar antes de chocar. Si consultas en ciclos, usa GET /messages con after y el nextAfter de la respuesta anterior: una llamada trae todo lo nuevo.

Webhooks de WhatsApp: eventos disponibles

Un webhook es un aviso que Omniia le envía a tu servidor cuando algo pasa. En Ajustes → API registras una URL, eliges los eventos y, si quieres, un solo canal. Cada evento llega como un POST JSON con event, timestamp, workspaceId y data.

EventoCuándo llega
message.receivedUn cliente escribió (con el botón de plantilla que tocó, si lo hizo)
message.sentSalió un mensaje desde la bandeja o la API
message.statusUn envío por la API oficial pasó a entregado, leído o fallido
conversation.createdNació una conversación, entrante o por API
conversation.assignedEl chat se asignó a un asesor
conversation.closedSe cerró por cualquier vía, con el motivo
contact.createdSe creó un contacto en el CRM o por la API
csat.respondedEl cliente calificó la atención del 1 al 5

Un detalle que confunde al principio: cuando una persona nueva escribe por WhatsApp, el evento que te sirve es conversation.created con source inbound. contact.created cubre los contactos que se crean en el CRM o por la API.

Así llega un message.received
POST /webhooks/omniia HTTP/1.1
Content-Type: application/json
X-Omniia-Event: message.received
X-Omniia-Delivery: 6f1c2a9e-1b7d-4c3e-9a51-0d2b7c8e4f10
X-Omniia-Timestamp: 1792073052318
X-Omniia-Signature: sha256=<hmac-en-hexadecimal>

{
  "event": "message.received",
  "timestamp": 1792073052318,
  "workspaceId": "<uuid>",
  "data": {
    "messageId": "<uuid>",
    "conversationId": "<uuid>",
    "channelId": "<uuid>",
    "channelName": "Ventas",
    "from": "573001234567",
    "to": "573209876543",
    "name": "Laura Gómez",
    "type": "text",
    "body": "¿La factura FE-20931 ya incluye el IVA?",
    "caption": null,
    "mediaUrl": null,
    "timestamp": "2026-10-15T14:04:11.000Z",
    "externalMessageId": "wamid.HBgM...",
    "button": null,
    "replyTo": null
  }
}

Verificar la firma HMAC en Node.js

La firma es un HMAC-SHA256 calculado con el secreto de la suscripción (empieza por whsec_ y lo ves en Ajustes → API) sobre la marca de tiempo, un punto y el cuerpo exacto que llegó. Por eso hay que leer el cuerpo crudo antes de convertirlo en JSON: si lo conviertes y lo vuelves a serializar, la firma deja de cuadrar.

Express: firma, antigüedad y respuesta rápida
const crypto = require('crypto');
const express = require('express');
const app = express();

// Cuerpo crudo: la firma se calcula sobre el texto exacto que envió Omniia.
app.post('/webhooks/omniia', express.raw({ type: 'application/json' }), (req, res) => {
  const timestamp = req.get('X-Omniia-Timestamp') || '';
  const firma = req.get('X-Omniia-Signature') || '';
  const cuerpo = req.body.toString('utf8');

  const esperada = 'sha256=' + crypto
    .createHmac('sha256', process.env.OMNIIA_WEBHOOK_SECRET) // whsec_...
    .update(timestamp + '.' + cuerpo)
    .digest('hex');

  const a = Buffer.from(firma);
  const b = Buffer.from(esperada);
  const firmaValida = a.length === b.length && crypto.timingSafeEqual(a, b);
  const reciente = Math.abs(Date.now() - Number(timestamp)) < 5 * 60 * 1000;
  if (!firmaValida || !reciente) return res.sendStatus(401);

  res.sendStatus(200); // responde ya; el trabajo pesado va después
  const evento = JSON.parse(cuerpo);
  procesarEvento(evento, req.get('X-Omniia-Delivery')); // el id de entrega evita procesar dos veces
});

app.listen(3000);

La marca de tiempo va en milisegundos y se renueva en cada intento, así que una ventana de cinco minutos no rechaza los reintentos legítimos y sí los reenvíos viejos.

Reintentos, duplicados y pruebas

  • Responde 2xx en menos de 10 segundos. Otro código, una redirección o un tiempo de espera cuentan como fallo.
  • Reintentos: a 1 minuto, 5 minutos, 30 minutos y 2 horas, cinco intentos en total. Después la entrega queda fallida y la reintentas a mano desde el registro.
  • Duplicados: X-Omniia-Delivery es el mismo en todos los intentos de una entrega. Guárdalo y descarta los repetidos.
  • Pruebas: el botón de evento de prueba manda un evento test firmado, sin esperar un mensaje real.
  • Varias suscripciones: una para n8n y otra para tu ERP, cada una con su secreto.

Arrancar una automatización sin clave de API

No todo necesita la API. Una automatización con el disparador Otro sistema lo pide tiene su propia URL secreta, de la forma https://crm.omniia.app/api/automations/hook/ seguida de un token. Tu formulario, tu tienda o n8n hacen un POST con el teléfono, y Omniia crea o actualiza el contacto y corre los pasos: esperar, enviar una plantilla o un texto, poner o quitar etiquetas, mover de etapa, asignar, crear una tarea o avisar a otro sistema.

Inscribir a un contacto en la automatización
curl -X POST https://crm.omniia.app/api/automations/hook/<token> \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "573001234567",
    "name": "Laura Gómez",
    "email": "laura@correo.com",
    "fields": { "ciudad": "Bogotá" },
    "vars": { "factura": "FE-20931", "valor": "$184.900" }
  }'

# -> { "ok": true, "enrolled": true, "contactId": "<uuid>" }

Solo phone es obligatorio. Lo de fields se guarda en el contacto y lo de vars se usa en los mensajes como {{vars.factura}}. Si la automatización está apagada, responde 409. Activa “Puede volver a entrar” si el mismo cliente debe pasar varias veces, una por factura. Y el paso “Avisar a otro sistema” envía un JSON sin firma: protege esa URL con un token largo.

  • 1

    bandeja para todos tus canales

  • 24/7

    tu agente de IA responde

  • 1 link

    para que tus clientes agenden solos

  • 0

    cláusulas de permanencia

Preguntas frecuentes

¿Tienes otra duda? Escríbenos por WhatsApp y te ayudamos.

¿Dónde está la documentación de la API de Omniia?

Dentro de la app, en Ajustes → API, con todos los campos, ejemplos y errores; también se descarga en PDF. No hay una documentación pública en la web: la ve quien tiene cuenta, y puedes abrirla durante la semana de prueba gratis.

¿La API funciona con WhatsApp conectado por QR?

Sí. La misma clave y las mismas rutas sirven para canales por QR y por la API oficial. La diferencia es que por QR no hay plantillas, y por la API oficial un texto libre solo sale dentro de la ventana de 24 horas.

¿Cómo sé si una plantilla le llegó al cliente?

La respuesta de POST /messages con status sent solo indica que Meta aceptó el envío. Suscribe el evento message.status: te avisa cuando el mensaje pasa a entregado, leído o fallido, con el motivo del fallo.

¿Qué pasa si supero el límite de peticiones?

La API responde 429 con el encabezado Retry-After, que dice cuántos segundos esperar. Los límites se cuentan por clave y por minuto, con un presupuesto para consultas y otro para escrituras. Si tu caso necesita más cuota, se pide por soporte.

¿Puedo hacer envíos masivos con la API?

La API está pensada para envíos uno a uno que dispara tu sistema: una factura, un aviso, un código. Para escribirle a miles de contactos a la vez usa las campañas de Omniia con plantillas aprobadas, que controlan el ritmo y la ventana horaria.

¿Sirve para enviar códigos de verificación (OTP)?

Sí, con una plantilla de categoría autenticación. Se envía una sola variable, el código, y Omniia lo repite en el botón de copiar que exige Meta.

Pruébalo gratis durante 1 semana

Creas tu cuenta en minutos, conectas tu WhatsApp y nuestro equipo te acompaña para dejarlo funcionando.

  • Sin tarjeta de crédito
  • Implementación rápida
  • Cancela cuando quieras