Authorization: Bearer. Consulte Autenticación y la
Guía de API key para obtener y configurar la clave. Base: https://api.nuvia.ai,
prefijo /v1.
Cada caso indica los scopes de API key necesarios. Otorgue solo esos al crear la clave.
Caso 1: Enviar su primer mensaje
Scopes:inboxes:read, conversations:read, messages:read, messages:create.
Descubra sus canales (inboxes)
Obtenga una conversación
conversationId (o cree una con POST /v1/conversations).Envíe un mensaje de texto
POST /v1/messages/send con el conversationId y el objeto message.contentType: "TEXT" para mensajes de texto.Lea el historial de la conversación
GET /v1/messages/conversation/:id devuelve los mensajes; los adjuntos están en
GET /v1/messages/conversation/:id/attachments.Caso 2: Recibir eventos vía webhooks
Registre una URL propia para que Nuvia le notifique en tiempo real (mensajes, conversaciones, contactos). Este caso muestra el flujo de principio a fin; el formato del payload, la lista completa de eventos y las garantías de entrega están en la guía de Webhooks. Scopes: para registrar y consultar,webhooks:create y webhooks:read; para gestionar,
webhooks:update y webhooks:delete (+ messages:create si responde automáticamente).
Registre un webhook
POST /v1/webhooks. Son 12 eventos válidos: MESSAGE_SENT, MESSAGE_RECEIVED,
MESSAGE_DELIVERED, MESSAGE_READ, MESSAGE_FAILED, CONVERSATION_CREATED,
CONVERSATION_UPDATED, CONVERSATION_STEP_CHANGED, CONTACT_CREATED, CONTACT_UPDATED,
FOLLOWUP_SENT y FIELD_UPDATED. Consulte lo que cada uno entrega en la
tabla de eventos.Su empresa tiene un webhook: si ya hay uno configurado, esta llamada devuelve 409.
Actualice el existente en lugar de crear otro.custom_headers (para que usted valide el origen) y status
(ACTIVE/INACTIVE).Reciba los callbacks
POST a su url, con el header X-Webhook-Event y un
cuerpo de tres campos:data trae el recurso del evento: el mensaje, la conversación o el contacto, en el mismo
formato de los GET correspondientes. FIELD_UPDATED es la excepción y tiene estructura
propia.Reaccione al evento
POST /v1/messages/send (Caso 1) o descargue adjuntos con
GET /v1/messages/conversation/:id/attachments.Gestione la configuración
GET /v1/webhooks devuelve un objeto con la configuración de la empresa (o null). No es
una lista. Use el id de ese objeto para actualizar con PUT /v1/webhooks/:id o eliminar con
DELETE /v1/webhooks/:id. Para pausar sin perder la configuración, prefiera PUT con
status: "INACTIVE".Caso 3: Campañas y envío masivo
Scopes:campaigns:create, campaigns:read, campaigns:update, campaigns:delete y
campaign-enrollments:create (+ messages:create para el atajo de plantilla en masa).
La campaña llega a los contactos inscritos en ella. Cada inscripción vincula un contacto a una
campaña y registra en qué punto de la cadencia está. Por la API, crear la campaña no inscribe a
nadie, y agregar un contacto a una lista tampoco: la inscripción es siempre un paso explícito.
Cree la campaña
POST /v1/campaigns. Campos obligatorios: name, channel_type, trigger_type y
audience_config; los opcionales incluyen description, trigger_config, behavior_config,
sender_config y exclusion_lists. Las estructuras internas de estos objetos de configuración
están en la Referencia de la API. Siga el schema de allí.La campaña nace como borrador. audience_config describe la audiencia, pero crear la campaña
por la API no inscribe a nadie. Las inscripciones vienen en el paso siguiente.Las listas de exclusión (exclusion_lists) solo se pueden elegir mientras la campaña es
borrador. Después de la activación, lo que cambia es su contenido (consulte el
Caso 4).Inscriba la audiencia
campaign-enrollments:create:Revise antes de enviar
POST /v1/campaigns/audience-preview cuenta los
contactos de la audiencia y POST /v1/campaigns/preview-message resuelve las variables del
mensaje.Active y haga el seguimiento
POST /v1/campaigns/:id/activate (pause con /pause). La campaña necesita al menos
una etapa activa. La activación pone en cola a los contactos ya inscritos y devuelve cuántos en
enrollments_enqueued.GET /v1/campaigns/:id/analytics y
GET /v1/campaigns/:id/step-analytics, y exporte los contactos con
GET /v1/campaigns/:id/enrollments/export.POST /v1/messages/send-bulk-template (scope messages:create). El paso a paso, con los
parámetros de plantilla y los límites de Meta, está en la guía
Envío masivo de plantillas en WhatsApp.Caso 4: Inscribir contactos desde su CRM
Para integraciones en las que su sistema decide quién entra en cuál cadencia: la campaña ya está activa, y cada contacto se inscribe en el momento en que el CRM lo pide. Nuvia hace los envíos, termina la cadencia cuando el lead responde y devuelve los eventos para actualizar el CRM. Scopes:campaign-enrollments:create, campaign-enrollments:read, campaigns:read y
contacts:read (+ messages:read para leer las conversaciones y webhooks:create para recibir
los eventos).
Elija la campaña
GET /v1/campaigns lista las campañas con estado y canal; GET /v1/campaigns/:id devuelve una.
Guarde el id de la campaña de cada cadencia. La inscripción solo se acepta en una campaña con
estado ACTIVE.El canal de la campaña define el identificador obligatorio del contacto: una campaña de LinkedIn
exige linkedin_identifier; cualquier otra exige teléfono. Use una campaña por canal y deje que
el CRM decida en cuál inscribir.Inscriba el contacto
POST /v1/campaigns/:id/enrollments/from-contact. La ruta localiza el contacto por el teléfono
(o, sin teléfono, por el linkedin_identifier), crea el contacto si no existe y lo inscribe en
la campaña.Lea el resultado
status igual a enrolled o skipped:enroll_again, una nueva inscripción viene con re_enrolled: true. Cuando la inscripción
se omite, el motivo viene en reason, junto con el contactId cuando el contacto fue
localizado:404 cuando la campaña no existe o es de otra empresa, 409 cuando no está ACTIVE y
400 cuando el cuerpo es inválido (por ejemplo, sin phone ni linkedin_identifier).Guarde los IDs en el CRM
contactId, el enrollmentId y el id de la campaña junto al registro del CRM. Son
los que vinculan los eventos y las consultas de Nuvia con su negocio u oportunidad.En Nuvia, una persona es un contacto, con un vínculo de CRM:fieldsse graba en el contacto, no en la inscripción. La inscripción no tiene campo de negocio.external_ides uno solo por contacto y vale el último enviado.- Las variables de los mensajes usan el valor actual del contacto.
fields datos específicos de un negocio: la inscripción del negocio B
sobrescribe el valor del negocio A en el contacto.Maneje reintentos y timeouts
skipped con already_enrolled (o already_in_progress, con enroll_again) como éxito.Haga el seguimiento de las inscripciones
status:completion_reason ausente, nulo o con
un valor nuevo sin romper la integración.Cuando el lead responde, Nuvia termina todas sus inscripciones activas que ya tuvieron
actividad (envío, falla o invitación), en cualquier campaña, con completion_reason: REPLIED.
La cadencia se detiene sola: su sistema no necesita interrumpirla, solo llevar al lead a la
siguiente acción comercial.No existe webhook de inscripción creada, de cambio de estado ni de inscripción terminada. Para
mantener el CRM al día, consulte periódicamente:contactId ni por enrollmentId. Por eso el
enrollmentId guardado en el CRM es su referencia.Reciba las respuestas por webhook
- Respuesta del lead:
MESSAGE_RECEIVEDconsender_type: CONTACTymessage_type: INCOMING. Filtre por los dos campos: el evento también se dispara para mensajes que no son del lead, como los enviados desde la app de WhatsApp Business en coexistencia. Consulte el remitente del mensaje. - Falla de entrega:
MESSAGE_FAILED. Las fallas anteriores al intento de envío no generan webhook y solo aparecen en las ejecuciones de la campaña. - Cambio de etapa del embudo:
CONVERSATION_STEP_CHANGEDno indica respuesta. Una etapa de campaña puede mover la conversación a una etapa del embudo en el propio envío, antes de que el lead responda.
external_id. Use el contactId para
encontrar el registro en el CRM. El webhook hace un único intento de entrega, así que mantenga la
consulta periódica del paso anterior para conciliar eventos perdidos.Evite cadencias simultáneas
- En el CRM: antes de inscribir, verifique si el contacto ya tiene una inscripción en curso
con los
enrollmentIdque guardó. - En Nuvia: use listas de exclusión. Se eligen al crear la campaña (solo mientras es
borrador), pero el contenido de cada lista se consulta antes de cada envío. Agregar un
contacto a una lista de exclusión después de la activación ya vale para los próximos envíos, y
su inscripción termina con
EXCLUSION_LIST.
Caso 5: Sincronizar contactos
Mantenga su CRM externo y Nuvia sincronizados. Scopes:contacts:read, contacts:create, contacts:update, contacts:delete.
Verifique duplicados por teléfono
POST /v1/contacts/find-by-phones.Cree los contactos que faltan
POST /v1/contacts. Obligatorios: name y al menos un identificador entre teléfono
(phone_number, solo dígitos, código de área + número, sin el código de país, junto con
country_code, ej.: 55), email y linkedin_identifier. Opcionales: campos de perfil como
job_title y city, y additional_attributes ({ "slug": valor }) para campos personalizados.Si la empresa ya tiene un contacto con alguno de los identificadores, la ruta reutiliza ese
contacto en lugar de duplicarlo. La búsqueda sigue el orden e-mail, LinkedIn y teléfono:201: contacto creado, concreated: true.200: contacto existente reutilizado, concreated: falseymatched_by(email,linkedinophone). Encontrado por teléfono, los campos enviados se actualizan. Encontrado por e-mail o LinkedIn, solo se completan los campos vacíos, eignored_fieldsindica lo que no se guardó.409CONTACT_IDENTITY_CONFLICT: los identificadores pertenecen a contactos diferentes. No se guarda nada, yconflictsdevuelve el contacto de cada identificador.
name de un contacto existente nunca cambia: para cambiarlo, use PUT /v1/contacts/:id. Para
saber qué haría la ruta sin guardar nada, use POST /v1/contacts/identity-check.Actualice y liste
PUT /v1/contacts/:id (o solo el nombre con
PUT /v1/contacts/:id/name) y liste/pagine con GET /v1/contacts. Para quitar el vínculo
de un contacto con un CRM externo, use DELETE /v1/contacts/:id/crm-link: esto solo deshace
la vinculación; el contacto sigue existiendo en Nuvia (no es una eliminación de contacto).Caso 6: Asignar la conversación al owner de HubSpot
Para automatizaciones que reciben un evento de HubSpot con un owner (por ejemplo, el propietario de una reunión agendada) y necesitan asignar la conversación en Nuvia al usuario correspondiente. El mapeo entre owners de HubSpot y usuarios de Nuvia se configura en la pantalla de integración de HubSpot. La API solo lo lee. Scopes:hubspot:read y conversations:update (+ conversations:read para localizar la
conversación). Una clave existente no obtiene el scope: genere una nueva con ese scope marcado
(consulte la Guía de API key).
Lea el mapeo de owners
GET /v1/hubspot/owner-mappings devuelve los pares owner de HubSpot ↔ usuario de Nuvia de su
empresa.nuvia_user_id es el id del usuario de Nuvia que se usa para asignar la conversación. Si la
empresa no tiene HubSpot conectado, la lista viene vacía.Guarde el mapeo en caché y encuentre el usuario
owner-mappings una vez, guárdelo por algunos minutos y busque
el owner del evento por hubspot_owner_id. No use el correo electrónico: hubspot_owner_email
es una copia de cuando se guardó el mapeo y no se actualiza si el correo cambia en HubSpot.Asigne la conversación
PUT /v1/conversations/:id/assign-owner con el nuvia_user_id en userId. La ruta define el
propietario de la conversación y no cambia quién está respondiendo: si la IA atiende, sigue
atendiendo. Para pasar la atención a una persona, use PUT /v1/conversations/:id/assign-user.