Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.waspytech.com/llms.txt

Use this file to discover all available pages before exploring further.

Cada MessagePublic incluye un campo origin que te dice exactamente quién generó ese mensaje. Es la señal canónica para implementar handoff humano sin que tu bot pise a un agente real.

Valores de origin

ValorSignificado
inboundMensaje recibido del contacto (no aplica handoff — vos respondés a estos)
panelLo mandó un agente humano desde el panel web de Waspy
external_apiLo mandó tu integración (esta API v2 con tu API key)
ai_agentLo mandó la AI nativa de Waspy (chatbot flows, AI agents)
campaignEs parte de una campaña / template scheduled
historyBackfill de history sync de Meta (no es reactivo, ignoralo en lógica de negocio)

Patrón de handoff

// Tu webhook handler
function shouldBotRespond(msg: MessagePublic): boolean {
  // Solo respondemos a mensajes entrantes del contacto
  if (msg.direction !== 'inbound') return false;
  // Si origin no es 'inbound', es algo que generamos nosotros — no entrar en loop
  if (msg.origin !== 'inbound') return false;
  return true;
}

function shouldPauseBot(conversation, recentMessages: MessagePublic[]): boolean {
  // Si el último mensaje saliente fue del panel, un humano está atendiendo
  const lastOutbound = recentMessages.findLast((m) => m.direction === 'outbound');
  return lastOutbound?.origin === 'panel';
}

Cómo lo aplicás en webhooks

Los eventos message.status_changed y message.received traen origin en el payload. Tu bot debería:
  1. message.received con origin: 'inbound' → procesar normalmente.
  2. message.status_changed con origin: 'panel' → marcar la conversación como “humano-controlada”, no responder.
  3. message.status_changed con origin: 'external_api' → confirmación de que tu propio mensaje fue entregado.

Estado por conversación

Si tu CRM mantiene estado por conversación (ej. “bot vs humano”), una buena heurística:
  • Cuando llega cualquier mensaje saliente con origin: 'panel', marcá la conversación como botPaused: true.
  • Cuando llega un mensaje entrante después de N minutos sin actividad humana, podés re-activar el bot (botPaused: false).

Origin para mensajes pre-abril 2026 (legacy fallback)

Los mensajes creados antes de que existiera metadata.origin tienen el campo derivado en orden de prioridad:
Si…Entonces origin =
direction === 'inbound'inbound
source === 'history'history
campaignId no es nullcampaign
sentByAi === trueai_agent
sentBy no es null (era un user UUID en panel)panel
ninguna de las anterioresexternal_api
La precisión es alta para los casos comunes. Casos borde:
  • Mensaje viejo enviado por API con sentBy poblado por error → se clasifica como panel. Workaround: si tu lógica depende del orden de eventos, considerá también metadata.apiKeyId cuando esté presente (mensajes nuevos sí lo setean).
  • Mensaje de history sync que ALSO tenía sentByAi: true → clasifica como history (ganaba precedencia). Esos mensajes no son reactivos, ignoralos.
Para mensajes nuevos (post-sprint integration-ready, abril 2026 en adelante) metadata.origin siempre se setea explícitamente y este fallback no aplica.

Notas adicionales

  • metadata.origin es la fuente de verdad en DB; el campo público origin es la versión canónica que vas a usar.