smsenlinea.com API
Bienvenido a la documentación de la API de smsenlinea.com. Con nuestra API RESTful, puedes integrar mensajería de WhatsApp en tu aplicación, gestionar conversaciones y automatizar flujos de comunicación.
Características Principales
Asignación y Ruteo de conversaciones
Cómo el sistema decide a qué asesor se asigna una conversación entrante, y cómo configurarlo desde el panel y la API.
Departamentos
Un departamento (ej. Ventas, Soporte) agrupa asesores y tiene palabras clave para detectar la intención del cliente. Un asesor puede pertenecer a varios departamentos. Se configuran en Asesor IA → editar, y cada asesor elige sus departamentos en /admin/agents.
Estrategias de asignación
Campo assignment_strategy del departamento. La rotación ocurre solo entre los asesores de ese departamento:
| Valor | Comportamiento |
|---|---|
least_busy | Por disponibilidad — el asesor con menos chats abiertos (prioriza en línea). Default. |
round_robin | Secuencial — uno tras otro en cola circular (1º, 2º, … y vuelve al primero). |
rotate_available | Combinada — rotación secuencial solo entre los asesores en línea (heartbeat < 3 min). |
Seleccionar la estrategia vía API
POST /api/v1/departments
PUT /api/v1/departments/{id}
Authorization: Bearer <API_KEY> (scope departments:write)
Content-Type: application/json
{
"name": "Ventas",
"keywords": ["comprar", "precio", "cotización"],
"assignment_strategy": "round_robin"
}
Asignar/quitar asesores de un departamento:
POST /api/v1/departments/{id}/agents { "user_id": 5, "is_primary": true }
DELETE /api/v1/departments/{id}/agents/{userId}
Ruteo por intención
Al escalar a humano, se elige departamento por: 1) palabra clave del mensaje, y 2) clasificación por IA (si handoff_rules_json.ai_routing = true). Resuelto el departamento, se aplica su estrategia de asignación.
Código de asesor directo + enlace wa.me
Cada asesor tiene un código único (users.direct_code). Si el primer mensaje del cliente empieza con asesor:CODE (también asesor: CODE o asesor#CODE), el chat se asigna directo a ese asesor y se pausa el bot.
https://wa.me/<NUMERO_DEL_NEGOCIO>?text=asesor:<CODE>
Cada asesor copia su enlace desde el menú del chat → "Mi enlace directo de contacto".
Widget público (burbuja de WhatsApp)
La burbuja usa la API pública (la public_key va en el path, auth widgetAuth):
| Endpoint | Descripción |
|---|---|
GET /api/v1/widget/{public_key}/config | Config + departamentos + asesores (id, nombre, avatar — sin datos sensibles). |
POST /api/v1/widget/{public_key}/lead | Lead con department_id y preferred_agent_id (el cliente elige depto/asesor). |
POST /api/v1/widget/{public_key}/event | Tracking (bubble_opened, form_submitted, …). |
Relación con el ruteo: departamento elegido → estrategia del departamento; preferred_agent_id o código asesor:CODE → asesor directo; sin elección → ruteo por intención. Las widget keys se gestionan en /admin/integrations/wordpress/widget-keys.
tenants.settings.bot_enabled. Si está en false, el Asesor IA no atiende ninguna conversación (solo humanos). Se controla desde el menú del chat → "Asesor IA (bot)".
Inicio Rápido
Comienza a usar la API de smsenlinea.com en 5 minutos.
1. Crear una Clave API
Dirígete a Configuración → Claves API y haz clic en "Nueva Clave". Selecciona los permisos que necesites.
2. Primer Llamado
Usa tu clave API para hacer un llamado HTTP simple:
curl -X GET "https://panel.smsenlinea.com/api/v1/external/conversations" \
-H "X-API-Key: whasaas_live_..." \
-H "Content-Type: application/json"
3. Manejar Respuestas
Todas las respuestas son JSON. Las respuestas exitosas retornan 200 OK:
{
"ok": true,
"data": {
"conversations": [
{
"id": "conv_123",
"phone": "573001234567",
"status": "active",
"created_at": "2026-05-22T14:30:00Z"
}
]
}
}
4. Configurar Webhooks
Para recibir notificaciones en tiempo real, configura un webhook en Integraciones → Webhooks.
Autenticación
smsenlinea.com soporta dos métodos de autenticación para la API:
Método 1: API Key Header
Envía tu clave API en el encabezado X-API-Key:
GET /api/v1/external/conversations HTTP/1.1
Host: panel.smsenlinea.comX-API-Key: whasaas_live_1a2b3c4d5e6f7g8h
Content-Type: application/json
Método 2: Bearer Token
Alternativamente, usa un Bearer token en el encabezado Authorization:
GET /api/v1/external/conversations HTTP/1.1
Host: panel.smsenlinea.comAuthorization: Bearer whasaas_live_1a2b3c4d5e6f7g8h
Content-Type: application/json
Permisos (Scopes)
Cada clave API tiene permisos específicos. Asigna sólo los que tu integración necesita — principio de menor privilegio. Hay 33 scopes disponibles, organizados por categoría:
📨 Mensajería (messages)
| Scope | Permite |
|---|---|
messages:read | Listar y consultar mensajes; verificar números en WhatsApp |
messages:write | Enviar mensajes (texto, media, audio, documento, botones, lista, encuesta, ubicación, contacto, reacción, forward, bulk) |
messages:edit | Editar el contenido de un mensaje enviado |
messages:delete | Eliminar mensajes para todos (recall) |
💬 Conversaciones (conversations)
| Scope | Permite |
|---|---|
conversations:read | Listar y consultar conversaciones, notas y eventos |
conversations:write | Crear/modificar conversaciones, archivar, marcar leído, etiquetar |
conversations:assign | Asignar y transferir conversaciones a asesores |
conversations:update_status | Cambiar estado (open / pending / resolved / archived) |
conversations:note | Agregar notas internas a conversaciones |
📱 Instancias de WhatsApp (instances)
| Scope | Permite |
|---|---|
instances:read | Listar, ver y consultar estado / estadísticas de instancias |
instances:write | Crear y eliminar instancias |
instances:connect | Generar QR, conectar y reiniciar instancias |
instances:disconnect | Desconectar / cerrar sesión de WhatsApp |
👥 Contactos & Asesores
| Scope | Permite |
|---|---|
contacts:read | Listar contactos, listas, foto de perfil |
contacts:write | Crear/editar/eliminar/bloquear contactos; importar CSV |
agents:read | Listar asesores, ver su disponibilidad y estadísticas |
🛒 Comercio (products / orders)
| Scope | Permite |
|---|---|
products:read | Consultar catálogo de productos y categorías |
products:write | Crear/modificar productos, variantes, imágenes y categorías |
orders:read | Listar órdenes y descargar recibos |
orders:write | Crear órdenes, cambiar estado, refunds, enviar link de pago |
📣 Marketing & Plantillas
| Scope | Permite |
|---|---|
campaigns:read | Consultar campañas masivas y sus destinatarios |
campaigns:write | Crear, programar, iniciar/pausar campañas (requiere tier ≥ Starter) |
templates:read | Leer plantillas y respuestas rápidas |
templates:write | Crear y modificar plantillas y respuestas rápidas |
🏷️ Organización (labels)
| Scope | Permite |
|---|---|
labels:read | Listar etiquetas del tenant |
labels:write | Crear, editar y eliminar etiquetas |
📦 Archivos (media)
| Scope | Permite |
|---|---|
media:read | Descargar archivos multimedia |
media:write | Subir archivos para usar en envíos |
🪝 Webhooks & Reportes
| Scope | Permite |
|---|---|
webhooks:read | Listar webhooks y ver entregas |
webhooks:write | Crear y editar webhooks; lanzar tests |
webhooks:manage | Eliminar webhooks y reintentar entregas |
analytics:read | Acceder a métricas, reportes y dashboards |
account:read | Información del tenant: plan, vencimiento, cuotas, rate-limit |
🧾 Cotizaciones y Facturas (quotes / invoices)
| Scope | Permite |
|---|---|
quotes:read | Consultar cotizaciones: listado, detalle, timeline y estadísticas (enviadas/leídas/aceptadas) |
invoices:read | Consultar facturas: listado, detalle, pagos y estadísticas de cartera |
tickets:read | Consultar tickets, órdenes de trabajo, plantillas y estadísticas |
tickets:write | Crear tickets/órdenes, responder, cambiar estado y asignar |
reminders:read | Consultar recordatorios recurrentes y su historial de envíos |
reminders:write | Crear, editar, pausar/reanudar y eliminar recordatorios recurrentes |
Ambos requieren además que el módulo correspondiente esté incluido en tu plan; de lo contrario la API responde 403 plan_feature_required.
quotes:read / invoices:read) y recibes 403 insufficient_scope, edita o rota la llave para incluirlos.
IP Whitelist
Para mayor seguridad, puedes restringir el acceso a IPs específicas. Configura esto desde la página de detalles de tu clave API.
Catálogo de Endpoints
smsenlinea.com API v2 expone más de 120 endpoints activos bajo el prefijo /api/v1, más los 9 endpoints legacy bajo /api/v1/external. Todos requieren autenticación con API Key.
/api/v1/... y devuelven el formato {ok, data, message}. Los legacy bajo /api/v1/external/... mantienen el formato {success, data, message} por compatibilidad.
📱 Instancias de WhatsApp
Scope base: instances:read / instances:write / instances:connect / instances:disconnect
Lista todas las instancias del tenant.
Detalle completo de una instancia.
Crea una nueva instancia y devuelve el QR de conexión.
Refresca el QR para conectar la instancia.
Estado actual (open / connecting / disconnected) + teléfono.
Reconectar la instancia (genera QR fresco).
Cierra la sesión de WhatsApp.
Reinicia el proceso de Evolution para esa instancia.
Elimina la instancia (también en Evolution).
Métricas: mensajes enviados/recibidos, conversaciones activas (periodos: 1h, 24h, 7d, 30d).
📨 Mensajes
Scope base: messages:read / messages:write / messages:edit / messages:delete
Envío
instance_id (número) o instance_name (texto) en el body para elegir la instancia de WhatsApp. Si no lo envías, se usa la primera instancia conectada de tu cuenta. Con más de una instancia, especifícala siempre. Ver la guía completa en Selección de instancia.
Envía un mensaje de texto. Body: {phone, message, instance_id?, instance_name?}.
Envía imagen o video. Body: {phone, media_url, media_type, caption?, filename?}.
Envía un audio / nota de voz. Body: {phone, audio_url}.
Envía un documento (PDF, DOC, XLSX, etc.).
Envía ubicación geográfica. Body: {phone, latitude, longitude, name?, address?}.
Envía una tarjeta de contacto (vCard).
Envía una plantilla local con variables {{var}}.
Mensaje con botones de respuesta rápida.
Lista interactiva con secciones.
Encuesta de WhatsApp. Body: {phone, question, options[], multiple_answers?}.
Reacciona con emoji a un mensaje existente. Body: {evolution_msg_id, emoji}.
Reenvía un mensaje a múltiples destinatarios.
Envío en lote (hasta 500 mensajes con delay configurable). Requiere tier ≥ Starter.
Lectura y gestión
Lista mensajes con filtros: conversation_id, instance_id, direction, type, date_from, date_to, paginación.
Detalle completo de un mensaje.
Edita un mensaje enviado. Body: {evolution_msg_id, content}.
Elimina un mensaje para todos (recall).
Marca un mensaje recibido como leído.
Helpers WhatsApp
Verifica qué números tienen cuenta de WhatsApp. Body: {numbers: []}.
URL de foto de perfil de un contacto.
💬 Conversaciones
Scope base: conversations:read / conversations:write / conversations:assign / conversations:update_status / conversations:note
Lista conversaciones. Filtros: status, assigned_to (id o "unassigned"), instance_id, unread_only, search.
Detalle de una conversación con contact, instance, assigned_to.
Mensajes paginados de una conversación.
Inicia una conversación nueva. Body: {phone, instance_id?, initial_message?}.
Asigna a uno o varios asesores. Body: {conversation_id|phone, agent_id|agent_email|agent_ids[]}. Pasa null para desasignar.
Cambia estado: open, pending, resolved, archived.
Agrega nota interna a una conversación.
Lista todas las notas internas de la conversación.
Agrega una etiqueta. Body: {label_id}.
Quita una etiqueta.
Archiva o desarchiva. Body: {archived: true|false}.
Marca todos los mensajes entrantes como leídos.
Activa o pausa el chatbot en esta conversación.
Elimina (soft-delete: archiva).
📜 API Legacy /api/v1/external/*
Estos endpoints siguen funcionando indefinidamente para no romper integraciones existentes. Para nuevas integraciones se recomienda usar los endpoints v2 de arriba.
⏱️ Mensajes programados
Scope: messages:schedule o messages:write. Cola central con throttle anti-baneo por instancia.
Encola un mensaje diferido. Body: {phone, message|media_url, instance_id?|instance_name?, send_after?, dedupe_key?}.
Estado del mensaje encolado.
Cancela un mensaje aún no enviado.
🧑💼 Asesores y Departamentos
Scope: agents:read / departments:read / departments:write
Lista los asesores del tenant (nombre, email, rol, estado).
Detalle de un asesor.
Métricas del asesor: conversaciones atendidas, mensajes, tiempos de respuesta.
Disponibilidad actual del asesor.
Conversaciones asignadas al asesor.
Lista departamentos. CRUD completo con POST/PUT/DELETE en /departments/{id} y gestión de miembros en /departments/{id}/agents.
👥 Contactos y Listas
Scope: contacts:read / contacts:write
Lista contactos con búsqueda y paginación.
Busca un contacto por teléfono.
Crea un contacto. También: POST /contacts/update (upsert por teléfono), POST /contacts/import, GET /contacts/export, block/unblock, y listas en /contact-lists.
🧾 Cotizaciones NUEVO
Scope: quotes:read · Requiere el módulo de Cotizaciones en tu plan (Pro/Enterprise). Solo lectura: consulta el funnel completo — enviadas, leídas, aceptadas, rechazadas, vencidas.
Lista cotizaciones. Filtros: status (draft, sent, viewed, accepted, rejected, expired, cancelled), date_from, date_to, search (número/cliente), paginación. Cada fila incluye views_count, first_viewed_at, acceptance y public_url.
Detalle completo: ítems, opciones (good/better/best), aceptación (quién y cuándo) y events — el timeline completo (created, sent_wa, viewed, accepted...).
Funnel agregado: by_status, sent_count, viewed_count, accepted_count, view_rate, acceptance_rate, accepted_amount.
// GET https://panel.smsenlinea.com/api/v1/quotes/stats
{
"ok": true,
"data": {
"total": 42,
"by_status": {"sent": 10, "viewed": 18, "accepted": 9, "rejected": 3, "draft": 2},
"sent_count": 40,
"viewed_count": 27,
"accepted_count": 9,
"view_rate": 0.675,
"acceptance_rate": 0.225,
"accepted_amount": 18500000
}
}
💵 Facturas NUEVO
Scope: invoices:read · Requiere el módulo de Facturación en tu plan. Solo lectura: ciclo de cobro completo — enviadas, leídas (apertura del correo/página), pagos parciales, pagadas, vencidas.
Lista facturas. Filtros: status (draft, sent, viewed, partial, paid, overdue, cancelled, void), date_from/date_to (fecha de emisión), search, overdue_only=1. Incluye amount_paid, balance_due, first_viewed_at y public_url.
Detalle completo: ítems, retenciones y payments (cada pago registrado con fecha, monto y método).
Resumen de cartera: by_status, viewed_count, overdue_count, total_invoiced, total_collected, total_outstanding.
🎫 Tickets y Órdenes de Trabajo NUEVO
Scopes: tickets:read / tickets:write · Requiere el módulo de Tickets en tu plan. Soporta plantillas con campos personalizados y órdenes de servicio en campo (dirección + horario + empleados + firma del cliente).
Plantillas activas con su definición de campos (fields: key, label, type, required, options). Consúltalas antes de crear para saber qué datos enviar en custom_fields.
Lista tickets. Filtros: status, service_status (scheduled, en_route, in_progress, completed), priority, assigned_to, date_from/date_to, search.
Detalle: mensajes públicos, eventos, asignados y bloque work_order (estado de servicio, dirección, campos custom, firmado por/cuándo, work_order_url). Las notas internas y la imagen de la firma nunca se exponen.
Totales por estado + resumen de órdenes de trabajo por estado de servicio.
Crea un ticket. Body: {subject, description?, priority?, phone?, contact_name?, contact_email?, template_id?, custom_fields?, service_address?, service_date?, service_time?, service_end_time?, assignee_ids?, notify_customer?}. Con plantilla field_service genera la orden de trabajo, notifica al cliente, envía a cada empleado su enlace de ejecución y programa recordatorios automáticos (1 día antes y 2 horas antes, ajustados al horario hábil configurado por el negocio).
Cambia el estado. Body: {status} (open, in_progress, waiting_customer, resolved, closed) o {service_status} para órdenes (solo la siguiente transición válida; completed requiere la firma del cliente en el portal del empleado).
Responde al cliente (le notifica por WhatsApp/email) o registra nota interna con {private: true}.
Asigna asesores. Body: {assignee_ids: []}. En órdenes de trabajo re-notifica los enlaces de ejecución.
🗓️ Recordatorios recurrentes NUEVO
Scopes: reminders:read / reminders:write. Programa mensajes de WhatsApp que se repiten (semanal, mensual, cada N días…) hacia un cliente — ideal para recordatorios de cobro de cuotas. El envío pasa por la cola anti-baneo y respeta el horario hábil (nunca de madrugada).
Lista tus planes. Filtro status (active, paused, finished) + paginación. Cada uno incluye next_run_at (UTC) y occurrences_sent.
Crea un plan. Body: {title, phone, display_name?, template_id?|body?, variables?, instance_id?, frequency, day_of_week?, day_of_month?, every_n_days?, send_time, timezone, skip_weekends?, starts_on, ends_on?, max_occurrences?}.
Detalle del plan.
Edita el plan (recalcula el próximo envío).
Pausar / reanudar (reanudar recalcula la próxima ocurrencia hacia el futuro).
Historial de ocurrencias con el estado real del envío (queued/sent/failed).
Elimina el plan.
Ejemplo — cobrar la cuota mensual el día 5 a las 9:00 (Bogotá):
curl -X POST "https://panel.smsenlinea.com/api/v1/reminders" \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Cuota mensual plan hosting",
"phone": "573001112233",
"display_name": "María Gómez",
"template_id": 12,
"variables": { "monto": "$50.000", "referencia": "CT-2024-11" },
"frequency": "monthly",
"day_of_month": 5,
"send_time": "09:00",
"timezone": "America/Bogota",
"skip_weekends": true,
"starts_on": "2026-08-01"
}'
// Respuesta
{ "ok": true, "data": { "id": 42, "next_run_at": "2026-08-05 14:00:00" } }
La plantilla puede usar {{nombre}} (del contacto) y tus variables ({{monto}}, {{referencia}}…). next_run_at viene en UTC; si la hora local cae fuera del horario hábil, se corre al inicio de la jornada. Para "día 31" en meses cortos se usa el último día del mes.
👤 Cuenta y Plan
Scope: account:read
Información del tenant (nombre, email, fecha de alta).
Plan vigente: nombre, límites (instancias, mensajes/mes, asesores) y features incluidas.
Estado de la suscripción y fecha de renovación/vencimiento.
Consumo del período: mensajes usados vs límite del plan, instancias activas.
Información de la API Key usada (nombre, scopes, último uso).
Límites de tasa vigentes y consumo actual.
📊 Analíticas
Scope: analytics:read. Todas aceptan date_from/date_to.
Panorama general: mensajes, conversaciones, contactos nuevos, ventas.
Mensajes enviados y recibidos por día, con totales del rango.
Conversaciones nuevas/resueltas y tiempos de atención.
Actividad por instancia (útil con varias líneas de WhatsApp).
Desempeño por asesor.
Ventas del período (módulo e-commerce).
Productos más vendidos.
Uso de la propia API (llamadas por endpoint y por día).
📣 Marketing
Plantillas, respuestas rápidas y campañas masivas.
CRUD de plantillas de mensaje (POST/PUT/DELETE en /templates/{id}; categorías en /templates/categories).
CRUD de respuestas rápidas.
CRUD de campañas + control: start, pause, resume, cancel, recipients, stats.
CRUD de etiquetas para clasificar conversaciones.
🛒 E-commerce
Requiere el módulo e-commerce en tu plan.
CRUD de productos + POST /products/{id}/images + POST /products/{id}/send-to-chat.
CRUD de categorías del catálogo.
Órdenes: listar, crear, cambiar estado/pago, refund, send-payment-link.
Valida un cupón; CRUD completo en /coupons.
📦 Media y 🪝 Webhooks (gestión)
Sube un archivo y devuelve la URL para usar en send-media/send-document. También GET /media/url, GET /media/download, GET /media/quota, DELETE /media.
CRUD de webhooks + POST /webhooks/{id}/test + GET /webhooks/{id}/deliveries + reintento de entregas. Catálogo de eventos en GET /webhooks/events.
Selección de instancia
Tu cuenta puede tener varias instancias de WhatsApp (varias líneas/números). Todos los endpoints de envío te permiten elegir desde cuál sale cada mensaje.
Cómo funciona
| Parámetro del body | Tipo | Comportamiento |
|---|---|---|
instance_id | número | Envía por esa instancia. Debe ser tuya y estar connected. |
instance_name | texto | Alternativa amigable: el nombre exacto de la instancia (como aparece en el panel). Se ignora si también envías instance_id. |
| (ninguno) | — | Se usa la primera instancia conectada de tu cuenta. Cómodo con una sola línea; impredecible con varias — especifícala siempre si tienes más de una. |
Paso 1 — Consulta tus instancias
curl -H "Authorization: Bearer TU_API_KEY" \
"https://panel.smsenlinea.com/api/v1/instances?status=connected"
// Respuesta (resumida)
{
"ok": true,
"data": [
{ "id": 12, "instance_name": "ventas-principal", "status": "connected", "phone_number": "573001112233" },
{ "id": 15, "instance_name": "soporte", "status": "connected", "phone_number": "573004445566" }
]
}
El filtro ?status=connected devuelve solo las instancias listas para enviar.
Paso 2 — Envía indicando la instancia
// Por ID
curl -X POST "https://panel.smsenlinea.com/api/v1/messages/send" \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "573009998877",
"message": "Hola, tu pedido está listo 🎉",
"instance_id": 15
}'
// O por nombre (equivalente)
curl -X POST "https://panel.smsenlinea.com/api/v1/messages/send" \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "573009998877",
"message": "Hola, tu pedido está listo 🎉",
"instance_name": "soporte"
}'
Aplica a todos los envíos
instance_id / instance_name funcionan igual en: send, send-media, send-audio, send-document, send-location, send-contact, send-template, send-buttons, send-list, send-poll, send-bulk, forward y messages/schedule. También en POST /conversations al iniciar una conversación nueva.
Si la instancia no está disponible
Cuando la instancia pedida no existe, no es tuya o está desconectada, la API responde 400 con el código no_connected_instance — e incluye tus instancias disponibles para que corrijas sin adivinar:
{
"ok": false,
"error": "no_connected_instance",
"message": "La instancia instance_id=99 no existe en tu cuenta o no está conectada.",
"details": {
"available_instances": [
{ "id": 12, "instance_name": "ventas-principal", "status": "connected", "phone_number": "573001112233" },
{ "id": 15, "instance_name": "soporte", "status": "disconnected", "phone_number": "573004445566" }
],
"hint": "Envía instance_id (número) o instance_name (texto) de una instancia con status \"connected\". Si tienes varias instancias, especifícala siempre."
}
}
instance_id en la configuración de tu integración (no lo resuelvas en cada envío) y refresca la lista solo si recibes no_connected_instance. Los IDs son estables; el nombre puede cambiar si lo renombras en el panel.
Webhooks
Los webhooks permiten que tu aplicación reciba notificaciones en tiempo real cuando ocurren eventos importantes.
Eventos Disponibles
| Evento | Descripción |
|---|---|
message.received |
Se recibió un mensaje nuevo |
message.sent |
Se envió un mensaje |
chat.assigned |
Una conversación fue asignada a un agente |
chat.created |
Se creó una nueva conversación |
contact.updated |
La información de un contacto fue actualizada |
instance.connected |
Una instancia de WhatsApp se conectó |
Verificar Webhooks
Cada webhook incluye una firma HMAC-SHA256 en el encabezado X-Webhook-Signature. Siempre verifica la firma para garantizar que el webhook proviene de smsenlinea.com:
Python
import hmac
import hashlib
def verify_webhook(request_body, signature, secret):
expected = hmac.new(
secret.encode(),
request_body.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
PHP
<?php
function verifyWebhook($payload, $signature, $secret) {
// Calcular la firma esperada
$expected = hash_hmac(
'sha256',
$payload,
$secret,
false // retornar como string hexadecimal
);
// Comparar de forma segura
return hash_equals($expected, $signature);
}
// Ejemplo de uso en un endpoint de webhook
$secret = 'wh_1a2b3c4d5e6f7g8h'; // Tu secret token del webhook
// Obtener el cuerpo de la solicitud
$payload = file_get_contents('php://input');
// Obtener la firma del encabezado
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
// Verificar la firma
if (!verifyWebhook($payload, $signature, $secret)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
// La firma es válida, procesar el webhook
$data = json_decode($payload, true);
if ($data['event'] === 'message.received') {
// Procesar mensaje recibido
$phone = $data['data']['phone'];
$message = $data['data']['message'];
// Tu lógica aquí
echo "Mensaje recibido de {$phone}: {$message}";
}
http_response_code(200);
echo json_encode(['success' => true]);
?>
Configurar un Webhook
Dirígete a Integraciones → Webhooks y crea un nuevo webhook con tu URL.
Rate Limiting
La API de smsenlinea.com aplica límites de velocidad basados en tu plan.
Límites por Plan
| Plan | Req/Minuto | Req/Hora | Req/Día |
|---|---|---|---|
| Free | 100 | 1,000 | 10,000 |
| Starter | 500 | 10,000 | 100,000 |
| Professional | 2,000 | 50,000 | 1,000,000 |
| Enterprise | Ilimitado | Ilimitado | Ilimitado |
Encabezados de Rate Limit
Cada respuesta incluye encabezados que indican tu uso:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1653225600
Manejar Límites Excedidos
Cuando excedes el límite, recibirás una respuesta 429 Too Many Requests:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"ok": false,
"error": "rate_limit_exceeded",
"message": "Too many requests. Please try again in 60 seconds."
}
Manejo de Errores
La API usa códigos de estado HTTP estándar para indicar el resultado de las solicitudes.
Códigos de Estado
| Código | Significado |
|---|---|
| 200 | Solicitud exitosa |
| 201 | Recurso creado |
| 400 | Solicitud inválida (parámetros incorrectos) |
| 401 | No autorizado (clave API inválida) |
| 403 | Prohibido (permisos insuficientes) |
| 404 | No encontrado |
| 429 | Demasiadas solicitudes (rate limit) |
| 500 | Error del servidor |
Respuesta de Error
Los errores incluyen más información útil:
{
"ok": false,
"error": "invalid_phone",
"message": "El número de teléfono proporcionado no es válido",
"code": "INVALID_INPUT"
}
Ejemplos de Código
JavaScript/Node.js
const fetch = require('node-fetch');
async function sendMessage() {
const response = await fetch('https://panel.smsenlinea.com/api/v1/external/messages/send', {
method: 'POST',
headers: {
'X-API-Key': 'whasaas_live_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone: '573001234567',
message: 'Hola desde smsenlinea.com'
})
});
const data = await response.json();
console.log(data);
}
sendMessage();
Python
import requests
def send_message():
response = requests.post(
'https://panel.smsenlinea.com/api/v1/external/messages/send',
headers={
'X-API-Key': 'whasaas_live_...',
'Content-Type': 'application/json'
},
json={
'phone': '573001234567',
'message': 'Hola desde smsenlinea.com'
}
)
print(response.json())
send_message()
PHP
<?php
function sendMessage() {
$apiKey = 'whasaas_live_...';
$url = 'https://panel.smsenlinea.com/api/v1/external/messages/send';
$data = [
'phone' => '573001234567',
'message' => 'Hola desde smsenlinea.com'
];
$options = [
'http' => [
'header' => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json'
],
'method' => 'POST',
'content' => json_encode($data),
'timeout' => 10
]
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
$result = json_decode($response, true);
print_r($result);
}
sendMessage();
// Alternativa usando cURL (recomendado):
function sendMessageWithCurl() {
$apiKey = 'whasaas_live_...';
$url = 'https://panel.smsenlinea.com/api/v1/external/messages/send';
$data = [
'phone' => '573001234567',
'message' => 'Hola desde smsenlinea.com'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result = json_decode($response, true);
echo "HTTP Status: " . $httpCode . "\n";
print_r($result);
}
sendMessageWithCurl();
?>
cURL
curl -X POST https://panel.smsenlinea.com/api/v1/external/messages/send \
-H "X-API-Key: whasaas_live_..." \
-H "Content-Type: application/json" \
-d '{
"phone": "573001234567",
"message": "Hola desde smsenlinea.com"
}'
Mejores Prácticas
🔐 Seguridad
- Nunca compartas tus claves API públicamente
- Usa diferentes claves para dev, staging y production
- Rota tus claves cada 90 días
- Usa IP whitelist para claves de producción
- Siempre verifica las firmas de webhooks
⚡ Rendimiento
- Usa batch operations cuando sea posible
- Implementa caché para reducir llamadas API
- Pagina los resultados grandes (limit, offset)
- Usa webhooks en lugar de polling
- Implementa reintentos exponenciales para resiliencia
📊 Monitoring
- Log todas las llamadas API importantes
- Monitora la tasa de errores 5xx
- Alerta cuando se acerque al límite de rate limit
- Rastrear latencia de webhooks
- Mantén métricas de tasa de entrega de webhooks