SDK Node.js — socialdesk-node
El SDK oficial de Socialdesk para Node.js simplifica la integración con la API. Incluye tipado completo en TypeScript y helpers para parsear eventos webhook.
Instalación
npm install socialdesk-node
Inicio rápido
import { WebhookHelper, EventType } from 'socialdesk-node';
// Tu handler de webhook (Express, Lambda, etc.)
async function handleWebhook(body: any) {
const webhook = new WebhookHelper(body);
const client = webhook.createClient();
if (webhook.isEventType(EventType.DirectMessage)) {
// Enviar un hint message al agente
await client.sendHintMessage({
text: 'El cliente preguntó por precios',
message_id: webhook.getMessageId(),
conversation_id: webhook.getConversationId(),
callbacks: [
{ id: 'cb_1', label: 'Enviar cotización', value: 'send_quote' },
],
quick_replies: [
{ text: 'El Plan Básico cuesta $79/mes + IVA.' },
],
});
}
}
WebhookHelper
Clase para parsear y extraer datos de los eventos webhook. Recibe el body completo del evento y expone métodos para acceder a los datos de forma segura sin importar el tipo de evento.
import { WebhookHelper } from 'socialdesk-node';
const webhook = new WebhookHelper(eventBody);
Métodos
| Método | Retorna | Descripción |
|---|---|---|
getEventType() | EventType | Tipo de evento recibido |
getPayload() | WebhookPayload | Payload crudo del evento |
getAccessToken() | string | Token para llamar la API (válido 2 horas) |
getChannelInstance() | string | ID del canal donde ocurrió el evento |
getInstanceId() | string | ID de tu app instance |
getSettings<T>() | T | Configuración de tu app (parsea el JSON de instance.settings automáticamente) |
getConversationId() | string | ID de la conversación (funciona con cualquier tipo de evento) |
getMessageId() | string | ID del mensaje (funciona con cualquier tipo de evento) |
getMessageText() | string | Texto del mensaje (funciona con cualquier tipo de evento) |
getConversationContext<T>() | T | Contexto completo de la conversación |
getApplicationContext<T>() | T | Contexto específico de tu app (context.assistants.{appInstanceId}) |
isEventType(type) | boolean | Verifica si el evento es de un tipo específico |
createClient(baseURL?) | SocialdeskClient | Crea un cliente pre-autenticado con el token del evento |
SocialdeskClient
Cliente HTTP para llamar los endpoints de la API. La forma recomendada es crearlo desde el WebhookHelper, que lo pre-autentica con el token del evento.
import { SocialdeskClient } from 'socialdesk-node';
// Opción 1: desde el webhook (recomendado)
const client = webhook.createClient();
// Opción 2: manual
const client = new SocialdeskClient('tu_access_token');
sendHintMessage
Envía un hint message visible solo para el agente. Útil para mostrar información contextual, sugerencias de respuesta y acciones rápidas.
await client.sendHintMessage({
text: 'El cliente quiere información de precios',
message_id: webhook.getMessageId(),
conversation_id: webhook.getConversationId(),
callbacks: [
{ id: 'cb_quote', label: 'Enviar cotización', value: 'send_quote' },
],
quick_replies: [
{ text: 'Nuestro plan básico cuesta $79/mes.' },
],
application_context: { intent: 'pricing', step: 1 },
});
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
text | string | No | Texto del hint message |
message_id | string | Sí | ID del mensaje al que se responde |
conversation_id | string | Sí | ID de la conversación |
attachments | Attachment[] | No | Archivos adjuntos |
interactions | Interaction[] | No | Interacciones (botones, listas) |
callbacks | Callback[] | No | Botones de acción para el agente |
quick_replies | QuickReply[] | No | Respuestas sugeridas para el agente |
application_context | object | No | Datos que se persisten en el contexto de la conversación |
sendDirectMessage
Envía un mensaje directo al participante (requiere permiso de respuestas automáticas).
await client.sendDirectMessage({
text: '¡Hola! Un asesor te atenderá en breve.',
message_id: webhook.getMessageId(),
conversation_id: webhook.getConversationId(),
interactions: [
{
label: 'whatsapp',
config: {
type: 'button',
action: {
buttons: [
{ type: 'reply', reply: { id: 'si', title: 'Sí, por favor' } },
{ type: 'reply', reply: { id: 'no', title: 'No, gracias' } },
],
},
},
},
],
});
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
text | string | No | Texto del mensaje |
message_id | string | Sí | ID del mensaje al que se responde |
conversation_id | string | Sí | ID de la conversación |
attachments | Attachment[] | No | Archivos adjuntos |
interactions | Interaction[] | No | Interacciones nativas del canal (botones de WhatsApp, etc.) |
application_context | object | No | Datos que se persisten en el contexto de la conversación |
sendHSMMessage
Envía un mensaje con plantilla (HSM). Puedes identificar al destinatario con account_contact_id (contacto existente) o contact (contacto nuevo), no ambos.
// Con contacto existente
await client.sendHSMMessage({
channel_id: webhook.getChannelInstance(),
account_contact_id: 'ac_123',
raw_text: 'Hola {{1}}, tu cita es el {{2}}',
parameters: ['María', '25 de marzo'],
external_template_id: 'appointment_v1',
});
// Con contacto nuevo
await client.sendHSMMessage({
channel_id: webhook.getChannelInstance(),
contact: {
account_id: 'acc_001',
first_name: 'María',
phone: '+50688881234',
},
raw_text: 'Hola {{1}}, bienvenida a nuestro servicio.',
parameters: ['María'],
external_template_id: 'welcome_v1',
});
// Envío programado
await client.sendHSMMessage({
channel_id: webhook.getChannelInstance(),
account_contact_id: 'ac_123',
raw_text: 'Recordatorio: tu cita es mañana a las {{1}}',
parameters: ['3:00 PM'],
external_template_id: 'reminder_v1',
send_at: '2026-03-25T08:00:00Z',
});
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
channel_id | string | Sí | ID del canal de WhatsApp |
account_contact_id | string | Condicional | ID del contacto existente (no usar junto con contact) |
contact | object | Condicional | Datos del contacto nuevo (no usar junto con account_contact_id) |
contact.account_id | string | Sí | ID de la cuenta |
contact.phone | string | Sí | Teléfono con código de país |
contact.first_name | string | No | Nombre |
contact.last_name | string | No | Apellido |
contact.email | string | No | |
contact.image_url | string | No | URL de imagen de perfil |
raw_text | string | Sí | Texto de la plantilla con placeholders {{N}} |
parameters | any[] | No | Valores para los placeholders |
external_template_id | string | No | ID de la plantilla en el proveedor |
assign_entity | 'USER' | 'TEAM' | No | Tipo de entidad a asignar |
assign_entity_id | string | No | ID de la entidad a asignar |
conversation_id | string | No | ID de conversación existente |
send_at | string | No | Fecha de envío programado (ISO 8601) |
assignConversation
Asigna una conversación a un agente o equipo.
await client.assignConversation({
conversation_id: webhook.getConversationId(),
entity: 'TEAM',
entity_id: 'team_sales',
});
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
conversation_id | string | Sí | ID de la conversación |
account_id | string | No | ID de la cuenta |
entity | 'USER' | 'TEAM' | Sí | Tipo de entidad: agente (USER) o equipo (TEAM) |
entity_id | string | Sí | ID del agente o equipo |
force_assign | boolean | No | Forzar asignación aunque ya esté asignada (default: false) |
addLabel
Agrega una etiqueta a una conversación para segmentarla.
await client.addLabel({
conversation_id: webhook.getConversationId(),
labelKey: 'lead_calificado',
});
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
conversation_id | string | Sí | ID de la conversación |
account_id | string | No | ID de la cuenta |
labelKey | string | Sí | Clave de la etiqueta |
Ejemplo completo: Bot con Express
import express from 'express';
import { WebhookHelper, EventType } from 'socialdesk-node';
const app = express();
app.use(express.json());
app.post('/webhook', async (req, res) => {
const webhook = new WebhookHelper(req.body);
const client = webhook.createClient();
if (webhook.isEventType(EventType.DirectMessage)) {
const text = webhook.getMessageText();
if (text.toLowerCase().includes('precio')) {
await client.sendHintMessage({
text: 'El cliente preguntó por precios',
message_id: webhook.getMessageId(),
conversation_id: webhook.getConversationId(),
quick_replies: [
{ text: 'El Plan Básico cuesta $79/mes + IVA e incluye 8 usuarios.' },
],
application_context: { step: 1, intent: 'pricing' },
});
await client.addLabel({
conversation_id: webhook.getConversationId(),
labelKey: 'consulta_precios',
});
}
}
if (webhook.isEventType(EventType.ConversationFinalized)) {
console.log('Conversación finalizada:', webhook.getConversationId());
}
res.json({ ok: true });
});
app.listen(3000);
Tenemos un proyecto listo para clonar con un ejemplo más completo que incluye manejo de todos los eventos, callbacks, direct messages, asignación y etiquetado de conversaciones:
github.com/godel-git/socialdesk-demo-app
git clone https://github.com/godel-git/socialdesk-demo-app.git
cd socialdesk-demo-app
npm install
npm run dev
Ejemplo: AWS Lambda
import { WebhookHelper, EventType } from 'socialdesk-node';
export const handler = async (event: any) => {
const body = JSON.parse(event.body);
const webhook = new WebhookHelper(body);
const client = webhook.createClient();
if (webhook.isEventType(EventType.DirectMessage)) {
await client.sendDirectMessage({
text: '¡Gracias por escribirnos! Un asesor te atenderá pronto.',
message_id: webhook.getMessageId(),
conversation_id: webhook.getConversationId(),
});
await client.assignConversation({
conversation_id: webhook.getConversationId(),
entity: 'TEAM',
entity_id: 'team_soporte',
});
}
return { statusCode: 200, body: JSON.stringify({ ok: true }) };
};
Tipos exportados
El SDK exporta todos los tipos necesarios para TypeScript:
import {
// Enums
EventType,
MessageDirection,
SenderType,
AttachmentType,
// Webhook
WebhookEvent,
WebhookPayload,
DirectMessagePayload,
ReplyMessagePayload,
ReplyMessageCallbackPayload,
HSMMessagePayload,
ConversationFinalizedPayload,
// Shared
MessageSender,
Participant,
Agent,
Attachment,
Interaction,
QuickReply,
Callback,
// API options
HintMessageOptions,
DirectMessageOptions,
HSMMessageOptions,
AssignConversationOptions,
AddLabelOptions,
} from 'socialdesk-node';