Documentation Index Fetch the complete documentation index at: https://docs.damascuss.io/llms.txt
Use this file to discover all available pages before exploring further.
¿Qué son los webhooks?
Los webhooks son notificaciones HTTP que NotMeta envía a tu aplicación cuando ocurren eventos específicos. Esto te permite reaccionar en tiempo real a cambios en conversaciones, mensajes y usuarios.
Eventos disponibles
Conversaciones
conversation.created - Nueva conversación creada
conversation.assigned - Conversación asignada a un usuario
conversation.unassigned - Conversación desasignada
conversation.closed - Conversación cerrada
conversation.reopened - Conversación reabierta
Mensajes
message.received - Nuevo mensaje recibido
message.sent - Mensaje enviado
message.delivered - Mensaje entregado
message.read - Mensaje leído
message.failed - Error al enviar mensaje
Usuarios
user.created - Nuevo usuario creado
user.updated - Usuario actualizado
user.deleted - Usuario eliminado
user.online - Usuario conectado
user.offline - Usuario desconectado
Sistema
webhook.verified - Webhook verificado
webhook.failed - Error en webhook
Configurar webhooks
Crear webhook
curl -X POST "https://api.notmeta.com/v1/webhooks" \
-H "Authorization: Bearer TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tu-dominio.com/webhook",
"events": ["message.received", "conversation.assigned"],
"secret": "tu_secret_webhook"
}'
Respuesta
{
"id" : "wh_123456789" ,
"url" : "https://tu-dominio.com/webhook" ,
"events" : [ "message.received" , "conversation.assigned" ],
"secret" : "whsec_abc123..." ,
"created_at" : "2024-01-01T00:00:00Z" ,
"status" : "active"
}
Estructura de eventos
Evento de mensaje recibido
{
"id" : "evt_123456789" ,
"type" : "message.received" ,
"created_at" : "2024-01-01T12:00:00Z" ,
"data" : {
"message" : {
"id" : "msg_123456789" ,
"conversation_id" : "conv_123456789" ,
"from" : "1234567890" ,
"to" : "0987654321" ,
"type" : "text" ,
"text" : "Hola, necesito ayuda" ,
"timestamp" : "2024-01-01T12:00:00Z"
},
"conversation" : {
"id" : "conv_123456789" ,
"status" : "open" ,
"assigned_to" : null ,
"created_at" : "2024-01-01T11:55:00Z"
}
}
}
Evento de conversación asignada
{
"id" : "evt_123456790" ,
"type" : "conversation.assigned" ,
"created_at" : "2024-01-01T12:05:00Z" ,
"data" : {
"conversation" : {
"id" : "conv_123456789" ,
"status" : "assigned" ,
"assigned_to" : "user_123456789" ,
"assigned_at" : "2024-01-01T12:05:00Z"
},
"user" : {
"id" : "user_123456789" ,
"name" : "Juan Pérez" ,
"email" : "juan@empresa.com" ,
"role" : "agent"
}
}
}
Implementar endpoint webhook
Node.js con Express
const express = require ( 'express' );
const crypto = require ( 'crypto' );
const app = express ();
app . use ( express . json ());
app . post ( '/webhook' , ( req , res ) => {
const signature = req . headers [ 'x-notmeta-signature' ];
const payload = JSON . stringify ( req . body );
// Verificar firma
if ( ! verifySignature ( payload , signature )) {
return res . status ( 400 ). send ( 'Invalid signature' );
}
// Procesar evento
const event = req . body ;
handleWebhookEvent ( event );
res . status ( 200 ). send ( 'OK' );
});
function verifySignature ( payload , signature ) {
const secret = process . env . NOTMETA_WEBHOOK_SECRET ;
const expectedSignature = crypto
. createHmac ( 'sha256' , secret )
. update ( payload )
. digest ( 'hex' );
return signature === `sha256= ${ expectedSignature } ` ;
}
function handleWebhookEvent ( event ) {
switch ( event . type ) {
case 'message.received' :
handleNewMessage ( event . data . message );
break ;
case 'conversation.assigned' :
handleConversationAssigned ( event . data . conversation );
break ;
default :
console . log ( `Evento no manejado: ${ event . type } ` );
}
}
function handleNewMessage ( message ) {
console . log ( `Nuevo mensaje de ${ message . from } : ${ message . text } ` );
// Tu lógica aquí
}
function handleConversationAssigned ( conversation ) {
console . log ( `Conversación ${ conversation . id } asignada a ${ conversation . assigned_to } ` );
// Tu lógica aquí
}
app . listen ( 3000 , () => {
console . log ( 'Webhook server running on port 3000' );
});
Python con Flask
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
app = Flask( __name__ )
@app.route ( '/webhook' , methods = [ 'POST' ])
def webhook ():
signature = request.headers.get( 'X-NotMeta-Signature' )
payload = request.get_data()
# Verificar firma
if not verify_signature(payload, signature):
return 'Invalid signature' , 400
# Procesar evento
event = request.json
handle_webhook_event(event)
return 'OK' , 200
def verify_signature ( payload , signature ):
secret = os.environ.get( 'NOTMETA_WEBHOOK_SECRET' )
expected_signature = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return signature == f 'sha256= { expected_signature } '
def handle_webhook_event ( event ):
event_type = event[ 'type' ]
if event_type == 'message.received' :
handle_new_message(event[ 'data' ][ 'message' ])
elif event_type == 'conversation.assigned' :
handle_conversation_assigned(event[ 'data' ][ 'conversation' ])
else :
print ( f 'Evento no manejado: { event_type } ' )
def handle_new_message ( message ):
print ( f 'Nuevo mensaje de { message[ "from" ] } : { message[ "text" ] } ' )
# Tu lógica aquí
def handle_conversation_assigned ( conversation ):
print ( f 'Conversación { conversation[ "id" ] } asignada' )
# Tu lógica aquí
if __name__ == '__main__' :
app.run( port = 3000 )
PHP
<? php
// webhook.php
$secret = $_ENV [ 'NOTMETA_WEBHOOK_SECRET' ];
$signature = $_SERVER [ 'HTTP_X_NOTMETA_SIGNATURE' ];
$payload = file_get_contents ( 'php://input' );
// Verificar firma
if ( ! verifySignature ( $payload , $signature , $secret )) {
http_response_code ( 400 );
echo 'Invalid signature' ;
exit ;
}
// Procesar evento
$event = json_decode ( $payload , true );
handleWebhookEvent ( $event );
echo 'OK' ;
function verifySignature ( $payload , $signature , $secret ) {
$expectedSignature = 'sha256=' . hash_hmac ( 'sha256' , $payload , $secret );
return hash_equals ( $expectedSignature , $signature );
}
function handleWebhookEvent ( $event ) {
$eventType = $event [ 'type' ];
switch ( $eventType ) {
case 'message.received' :
handleNewMessage ( $event [ 'data' ][ 'message' ]);
break ;
case 'conversation.assigned' :
handleConversationAssigned ( $event [ 'data' ][ 'conversation' ]);
break ;
default :
error_log ( "Evento no manejado: $eventType " );
}
}
function handleNewMessage ( $message ) {
error_log ( "Nuevo mensaje de { $message ['from']}: { $message ['text']}" );
// Tu lógica aquí
}
function handleConversationAssigned ( $conversation ) {
error_log ( "Conversación { $conversation ['id']} asignada" );
// Tu lógica aquí
}
?>
Verificación de webhooks
Verificación automática
Cuando creas un webhook, NotMeta envía un evento de verificación:
{
"id" : "evt_verify_123" ,
"type" : "webhook.verified" ,
"created_at" : "2024-01-01T00:00:00Z" ,
"data" : {
"webhook_id" : "wh_123456789" ,
"challenge" : "challenge_string_123"
}
}
Responder al desafío
app . post ( '/webhook' , ( req , res ) => {
if ( req . body . type === 'webhook.verified' ) {
// Responder al desafío de verificación
return res . status ( 200 ). send ( req . body . data . challenge );
}
// Procesar otros eventos...
});
Manejo de errores
Reintentos automáticos
NotMeta reintenta automáticamente webhooks que fallan:
Primer reintento : 1 minuto
Segundo reintento : 5 minutos
Tercer reintento : 15 minutos
Cuarto reintento : 1 hora
Máximo : 4 reintentos
Manejo de errores en tu endpoint
app . post ( '/webhook' , async ( req , res ) => {
try {
// Procesar evento
await handleWebhookEvent ( req . body );
res . status ( 200 ). send ( 'OK' );
} catch ( error ) {
console . error ( 'Error procesando webhook:' , error );
// Para errores temporales, devolver 5xx
if ( isTemporaryError ( error )) {
res . status ( 503 ). send ( 'Service Unavailable' );
} else {
// Para errores permanentes, devolver 4xx
res . status ( 400 ). send ( 'Bad Request' );
}
}
});
Mejores prácticas
Idempotencia
const processedEvents = new Set ();
function handleWebhookEvent ( event ) {
// Evitar procesar el mismo evento dos veces
if ( processedEvents . has ( event . id )) {
console . log ( `Evento ${ event . id } ya procesado` );
return ;
}
// Procesar evento
processEvent ( event );
// Marcar como procesado
processedEvents . add ( event . id );
}
Procesamiento asíncrono
const Queue = require ( 'bull' );
const webhookQueue = new Queue ( 'webhook processing' );
app . post ( '/webhook' , ( req , res ) => {
// Verificar firma
if ( ! verifySignature ( req . body , req . headers [ 'x-notmeta-signature' ])) {
return res . status ( 400 ). send ( 'Invalid signature' );
}
// Agregar a cola para procesamiento asíncrono
webhookQueue . add ( 'process-event' , req . body );
res . status ( 200 ). send ( 'OK' );
});
webhookQueue . process ( 'process-event' , async ( job ) => {
const event = job . data ;
await handleWebhookEvent ( event );
});
Logging
function logWebhookEvent ( event ) {
console . log ( JSON . stringify ({
timestamp: new Date (). toISOString (),
event_id: event . id ,
event_type: event . type ,
webhook_url: req . url
}));
}
Monitoreo y debugging
Estado de webhooks
curl -X GET "https://api.notmeta.com/v1/webhooks" \
-H "Authorization: Bearer TU_TOKEN"
Logs de webhook
curl -X GET "https://api.notmeta.com/v1/webhooks/wh_123456789/logs" \
-H "Authorization: Bearer TU_TOKEN"
Estadísticas de webhooks
curl -X GET "https://api.notmeta.com/v1/webhooks/wh_123456789/stats" \
-H "Authorization: Bearer TU_TOKEN"
Solución de problemas
Webhook no recibe eventos
Verifica que la URL sea accesible desde internet
Confirma que uses HTTPS en producción
Revisa los logs del webhook en NotMeta
Verifica que los eventos estén configurados correctamente
Errores de firma
Confirma que el secret sea correcto
Verifica que uses el payload completo
Revisa la codificación (UTF-8)
Timeouts
Asegúrate de responder rápidamente (máximo 30 segundos)
Usa procesamiento asíncrono para tareas pesadas
Implementa circuit breakers para servicios externos
Recursos adicionales
Configuración inicial Configura tu entorno de desarrollo
Mejores prácticas Aprende las mejores prácticas para integrar con NotMeta