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

✨ API RESTful
Endpoints modernos y bien documentados para todas las operaciones
🔐 Autenticación Segura
API Keys con permisos granulares y soporte para múltiples ambientes
⚡ Webhooks en Tiempo Real
Recibe notificaciones instantáneas de eventos en tu cuenta
📊 Rate Limiting Justo
Límites generosos con tiers escalables para cualquier tamaño de negocio
Nota: Esta documentación aplica a smsenlinea.com API v1. Mantenemos compatibilidad hacia atrás con versiones anteriores.

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:

ValorComportamiento
least_busyPor disponibilidad — el asesor con menos chats abiertos (prioriza en línea). Default.
round_robinSecuencial — uno tras otro en cola circular (1º, 2º, … y vuelve al primero).
rotate_availableCombinada — 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):

EndpointDescripción
GET /api/v1/widget/{public_key}/configConfig + departamentos + asesores (id, nombre, avatar — sin datos sensibles).
POST /api/v1/widget/{public_key}/leadLead con department_id y preferred_agent_id (el cliente elige depto/asesor).
POST /api/v1/widget/{public_key}/eventTracking (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.

Interruptor global del bot: 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.

¡Listo! Ya estás preparado para usar la API de smsenlinea.com.

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)

ScopePermite
messages:readListar y consultar mensajes; verificar números en WhatsApp
messages:writeEnviar mensajes (texto, media, audio, documento, botones, lista, encuesta, ubicación, contacto, reacción, forward, bulk)
messages:editEditar el contenido de un mensaje enviado
messages:deleteEliminar mensajes para todos (recall)

💬 Conversaciones (conversations)

ScopePermite
conversations:readListar y consultar conversaciones, notas y eventos
conversations:writeCrear/modificar conversaciones, archivar, marcar leído, etiquetar
conversations:assignAsignar y transferir conversaciones a asesores
conversations:update_statusCambiar estado (open / pending / resolved / archived)
conversations:noteAgregar notas internas a conversaciones

📱 Instancias de WhatsApp (instances)

ScopePermite
instances:readListar, ver y consultar estado / estadísticas de instancias
instances:writeCrear y eliminar instancias
instances:connectGenerar QR, conectar y reiniciar instancias
instances:disconnectDesconectar / cerrar sesión de WhatsApp

👥 Contactos & Asesores

ScopePermite
contacts:readListar contactos, listas, foto de perfil
contacts:writeCrear/editar/eliminar/bloquear contactos; importar CSV
agents:readListar asesores, ver su disponibilidad y estadísticas

🛒 Comercio (products / orders)

ScopePermite
products:readConsultar catálogo de productos y categorías
products:writeCrear/modificar productos, variantes, imágenes y categorías
orders:readListar órdenes y descargar recibos
orders:writeCrear órdenes, cambiar estado, refunds, enviar link de pago

📣 Marketing & Plantillas

ScopePermite
campaigns:readConsultar campañas masivas y sus destinatarios
campaigns:writeCrear, programar, iniciar/pausar campañas (requiere tier ≥ Starter)
templates:readLeer plantillas y respuestas rápidas
templates:writeCrear y modificar plantillas y respuestas rápidas

🏷️ Organización (labels)

ScopePermite
labels:readListar etiquetas del tenant
labels:writeCrear, editar y eliminar etiquetas

📦 Archivos (media)

ScopePermite
media:readDescargar archivos multimedia
media:writeSubir archivos para usar en envíos

🪝 Webhooks & Reportes

ScopePermite
webhooks:readListar webhooks y ver entregas
webhooks:writeCrear y editar webhooks; lanzar tests
webhooks:manageEliminar webhooks y reintentar entregas
analytics:readAcceder a métricas, reportes y dashboards
account:readInformación del tenant: plan, vencimiento, cuotas, rate-limit

🧾 Cotizaciones y Facturas (quotes / invoices)

ScopePermite
quotes:readConsultar cotizaciones: listado, detalle, timeline y estadísticas (enviadas/leídas/aceptadas)
invoices:readConsultar facturas: listado, detalle, pagos y estadísticas de cartera
tickets:readConsultar tickets, órdenes de trabajo, plantillas y estadísticas
tickets:writeCrear tickets/órdenes, responder, cambiar estado y asignar
reminders:readConsultar recordatorios recurrentes y su historial de envíos
reminders:writeCrear, 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.

ℹ️ Llaves sin scopes: las API Keys creadas desde el panel sin lista de scopes tienen acceso a todos los endpoints. Si tu llave fue creada con una lista explícita de scopes (antes de que existieran 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.

📌 Convención: los endpoints nuevos viven bajo /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

GET/api/v1/instances

Lista todas las instancias del tenant.

GET/api/v1/instances/{id}

Detalle completo de una instancia.

POST/api/v1/instances

Crea una nueva instancia y devuelve el QR de conexión.

GET/api/v1/instances/{id}/qr

Refresca el QR para conectar la instancia.

GET/api/v1/instances/{id}/status

Estado actual (open / connecting / disconnected) + teléfono.

POST/api/v1/instances/{id}/connect

Reconectar la instancia (genera QR fresco).

POST/api/v1/instances/{id}/disconnect

Cierra la sesión de WhatsApp.

POST/api/v1/instances/{id}/restart

Reinicia el proceso de Evolution para esa instancia.

DELETE/api/v1/instances/{id}

Elimina la instancia (también en Evolution).

GET/api/v1/instances/{id}/stats?period=24h

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

📱 ¿Desde qué número sale el mensaje? Todos los endpoints de envío aceptan 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.
POST/api/v1/messages/send

Envía un mensaje de texto. Body: {phone, message, instance_id?, instance_name?}.

POST/api/v1/messages/send-media

Envía imagen o video. Body: {phone, media_url, media_type, caption?, filename?}.

POST/api/v1/messages/send-audio

Envía un audio / nota de voz. Body: {phone, audio_url}.

POST/api/v1/messages/send-document

Envía un documento (PDF, DOC, XLSX, etc.).

POST/api/v1/messages/send-location

Envía ubicación geográfica. Body: {phone, latitude, longitude, name?, address?}.

POST/api/v1/messages/send-contact

Envía una tarjeta de contacto (vCard).

POST/api/v1/messages/send-template

Envía una plantilla local con variables {{var}}.

POST/api/v1/messages/send-buttons

Mensaje con botones de respuesta rápida.

POST/api/v1/messages/send-list

Lista interactiva con secciones.

POST/api/v1/messages/send-poll

Encuesta de WhatsApp. Body: {phone, question, options[], multiple_answers?}.

POST/api/v1/messages/send-reaction

Reacciona con emoji a un mensaje existente. Body: {evolution_msg_id, emoji}.

POST/api/v1/messages/forward

Reenvía un mensaje a múltiples destinatarios.

POST/api/v1/messages/send-bulk

Envío en lote (hasta 500 mensajes con delay configurable). Requiere tier ≥ Starter.

Lectura y gestión

GET/api/v1/messages

Lista mensajes con filtros: conversation_id, instance_id, direction, type, date_from, date_to, paginación.

GET/api/v1/messages/{id}

Detalle completo de un mensaje.

POST/api/v1/messages/edit

Edita un mensaje enviado. Body: {evolution_msg_id, content}.

POST/api/v1/messages/delete

Elimina un mensaje para todos (recall).

POST/api/v1/messages/{id}/read-receipt

Marca un mensaje recibido como leído.

Helpers WhatsApp

POST/api/v1/whatsapp/check

Verifica qué números tienen cuenta de WhatsApp. Body: {numbers: []}.

POST/api/v1/whatsapp/profile-picture

URL de foto de perfil de un contacto.

💬 Conversaciones

Scope base: conversations:read / conversations:write / conversations:assign / conversations:update_status / conversations:note

GET/api/v1/conversations

Lista conversaciones. Filtros: status, assigned_to (id o "unassigned"), instance_id, unread_only, search.

GET/api/v1/conversations/{id}

Detalle de una conversación con contact, instance, assigned_to.

GET/api/v1/conversations/{id}/messages

Mensajes paginados de una conversación.

POST/api/v1/conversations

Inicia una conversación nueva. Body: {phone, instance_id?, initial_message?}.

POST/api/v1/conversations/assign

Asigna a uno o varios asesores. Body: {conversation_id|phone, agent_id|agent_email|agent_ids[]}. Pasa null para desasignar.

POST/api/v1/conversations/status

Cambia estado: open, pending, resolved, archived.

POST/api/v1/conversations/notes

Agrega nota interna a una conversación.

GET/api/v1/conversations/{id}/notes

Lista todas las notas internas de la conversación.

POST/api/v1/conversations/{id}/labels

Agrega una etiqueta. Body: {label_id}.

DELETE/api/v1/conversations/{id}/labels/{labelId}

Quita una etiqueta.

POST/api/v1/conversations/{id}/archive

Archiva o desarchiva. Body: {archived: true|false}.

POST/api/v1/conversations/{id}/read

Marca todos los mensajes entrantes como leídos.

POST/api/v1/conversations/{id}/toggle-bot

Activa o pausa el chatbot en esta conversación.

DELETE/api/v1/conversations/{id}

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.

POST/api/v1/external/messages/send
POST/api/v1/external/messages/edit
POST/api/v1/external/messages/delete
POST/api/v1/external/whatsapp/check
GET/api/v1/external/agents
POST/api/v1/external/conversations/assign
POST/api/v1/external/conversations/status
POST/api/v1/external/conversations/notes
POST/api/v1/external/contacts/update

⏱️ Mensajes programados

Scope: messages:schedule o messages:write. Cola central con throttle anti-baneo por instancia.

POST/api/v1/messages/schedule

Encola un mensaje diferido. Body: {phone, message|media_url, instance_id?|instance_name?, send_after?, dedupe_key?}.

GET/api/v1/messages/scheduled/{id}

Estado del mensaje encolado.

POST/api/v1/messages/scheduled/{id}/cancel

Cancela un mensaje aún no enviado.

🧑‍💼 Asesores y Departamentos

Scope: agents:read / departments:read / departments:write

GET/api/v1/agents

Lista los asesores del tenant (nombre, email, rol, estado).

GET/api/v1/agents/{id}

Detalle de un asesor.

GET/api/v1/agents/{id}/metrics

Métricas del asesor: conversaciones atendidas, mensajes, tiempos de respuesta.

GET/api/v1/agents/{id}/availability

Disponibilidad actual del asesor.

GET/api/v1/agents/{id}/conversations

Conversaciones asignadas al asesor.

GET/api/v1/departments

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

GET/api/v1/contacts

Lista contactos con búsqueda y paginación.

GET/api/v1/contacts/search?phone=

Busca un contacto por teléfono.

POST/api/v1/contacts

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.

GET/api/v1/quotes

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.

GET/api/v1/quotes/{id}

Detalle completo: ítems, opciones (good/better/best), aceptación (quién y cuándo) y events — el timeline completo (created, sent_wa, viewed, accepted...).

GET/api/v1/quotes/stats?date_from=&date_to=

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.

GET/api/v1/invoices

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.

GET/api/v1/invoices/{id}

Detalle completo: ítems, retenciones y payments (cada pago registrado con fecha, monto y método).

GET/api/v1/invoices/stats?date_from=&date_to=

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).

GET/api/v1/ticket-templates

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.

GET/api/v1/tickets

Lista tickets. Filtros: status, service_status (scheduled, en_route, in_progress, completed), priority, assigned_to, date_from/date_to, search.

GET/api/v1/tickets/{id}

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.

GET/api/v1/tickets/stats

Totales por estado + resumen de órdenes de trabajo por estado de servicio.

POST/api/v1/tickets

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).

POST/api/v1/tickets/{id}/status

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).

POST/api/v1/tickets/{id}/reply

Responde al cliente (le notifica por WhatsApp/email) o registra nota interna con {private: true}.

POST/api/v1/tickets/{id}/assign

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).

GET/api/v1/reminders

Lista tus planes. Filtro status (active, paused, finished) + paginación. Cada uno incluye next_run_at (UTC) y occurrences_sent.

POST/api/v1/reminders

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?}.

GET/api/v1/reminders/{id}

Detalle del plan.

PUT/api/v1/reminders/{id}

Edita el plan (recalcula el próximo envío).

POST/api/v1/reminders/{id}/pause · POST/api/v1/reminders/{id}/resume

Pausar / reanudar (reanudar recalcula la próxima ocurrencia hacia el futuro).

GET/api/v1/reminders/{id}/runs

Historial de ocurrencias con el estado real del envío (queued/sent/failed).

DELETE/api/v1/reminders/{id}

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

GET/api/v1/account

Información del tenant (nombre, email, fecha de alta).

GET/api/v1/account/plan

Plan vigente: nombre, límites (instancias, mensajes/mes, asesores) y features incluidas.

GET/api/v1/account/subscription

Estado de la suscripción y fecha de renovación/vencimiento.

GET/api/v1/account/usage

Consumo del período: mensajes usados vs límite del plan, instancias activas.

GET/api/v1/account/api-key/info

Información de la API Key usada (nombre, scopes, último uso).

GET/api/v1/account/rate-limit

Límites de tasa vigentes y consumo actual.

📊 Analíticas

Scope: analytics:read. Todas aceptan date_from/date_to.

GET/api/v1/analytics/overview

Panorama general: mensajes, conversaciones, contactos nuevos, ventas.

GET/api/v1/analytics/messages

Mensajes enviados y recibidos por día, con totales del rango.

GET/api/v1/analytics/conversations

Conversaciones nuevas/resueltas y tiempos de atención.

GET/api/v1/analytics/instances

Actividad por instancia (útil con varias líneas de WhatsApp).

GET/api/v1/analytics/agents

Desempeño por asesor.

GET/api/v1/analytics/sales

Ventas del período (módulo e-commerce).

GET/api/v1/analytics/top-products

Productos más vendidos.

GET/api/v1/analytics/api-usage

Uso de la propia API (llamadas por endpoint y por día).

📣 Marketing

Plantillas, respuestas rápidas y campañas masivas.

GET/api/v1/templates

CRUD de plantillas de mensaje (POST/PUT/DELETE en /templates/{id}; categorías en /templates/categories).

GET/api/v1/quick-replies

CRUD de respuestas rápidas.

GET/api/v1/campaigns

CRUD de campañas + control: start, pause, resume, cancel, recipients, stats.

GET/api/v1/labels

CRUD de etiquetas para clasificar conversaciones.

🛒 E-commerce

Requiere el módulo e-commerce en tu plan.

GET/api/v1/products

CRUD de productos + POST /products/{id}/images + POST /products/{id}/send-to-chat.

GET/api/v1/categories

CRUD de categorías del catálogo.

GET/api/v1/orders

Órdenes: listar, crear, cambiar estado/pago, refund, send-payment-link.

POST/api/v1/coupons/validate

Valida un cupón; CRUD completo en /coupons.

📦 Media y 🪝 Webhooks (gestión)

POST/api/v1/media/upload

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.

GET/api/v1/webhooks

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 bodyTipoComportamiento
instance_idnúmeroEnvía por esa instancia. Debe ser tuya y estar connected.
instance_nametextoAlternativa 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."
  }
}
💡 Buena práctica: guarda el 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