Authorization: Bearer. Veja Autenticação e o Guia de API Key
para obter e configurar a chave. Base: https://api.nuvia.ai, prefixo /v1.
Cada caso indica os escopos de API Key necessários. Conceda apenas esses na criação da chave.
Caso 1: Enviar sua primeira mensagem
Escopos:inboxes:read, conversations:read, messages:read, messages:create.
Descubra seus canais (inboxes)
Obtenha uma conversa
conversationId (ou crie uma com POST /v1/conversations).Envie uma mensagem de texto
POST /v1/messages/send com o conversationId e o objeto message.contentType: "TEXT" para mensagens de texto.422 com
code: "CONTACT_DO_NOT_CONTACT" e a mensagem fica na conversa como falha. Pela API Key não há
como forçar o envio. O campo do_not_contact do contato mostra a marcação, e
GET /v1/contacts/:contactId/do-not-contact/history mostra quem marcou e por quê. Com
CONTACT_DO_NOT_CONTACT_CHECK_FAILED, não deu para verificar o contato: tente de novo mais tarde.Leia o histórico da conversa
GET /v1/messages/conversation/:id retorna as mensagens; anexos ficam em
GET /v1/messages/conversation/:id/attachments.Caso 2: Receber eventos via webhooks
Registre uma URL sua para a Nuvia notificar em tempo real (mensagens, conversas, contatos). Este caso mostra o fluxo ponta a ponta; o formato do payload, a lista completa de eventos e as garantias de entrega estão no guia de Webhooks. Escopos: para registrar e consultar,webhooks:create e webhooks:read; para gerenciar,
webhooks:update e webhooks:delete (+ messages:create se você responder automaticamente).
Registre um webhook
POST /v1/webhooks. São 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 e FIELD_UPDATED. Veja o que cada um entrega na
tabela de eventos.Sua empresa tem um webhook: se já houver um configurado, esta chamada devolve 409.
Atualize o existente em vez de criar outro.custom_headers (para você validar a origem) e status (ACTIVE/INACTIVE).Receba os callbacks
POST para a sua url, com o header
X-Webhook-Event e um corpo de três campos:data traz o recurso do evento: a mensagem, a conversa ou o contato, no mesmo formato dos
GET correspondentes. FIELD_UPDATED é a exceção e tem estrutura própria.Reaja ao evento
POST /v1/messages/send (Caso 1) ou baixe anexos com
GET /v1/messages/conversation/:id/attachments.Gerencie a configuração
GET /v1/webhooks devolve um objeto com a configuração da empresa (ou null). Não é uma
lista. Use o id desse objeto para atualizar com PUT /v1/webhooks/:id ou remover com
DELETE /v1/webhooks/:id. Para pausar sem perder a configuração, prefira PUT com
status: "INACTIVE".Caso 3: Campanhas e disparo em massa
Escopos:campaigns:create, campaigns:read, campaigns:update, campaigns:delete e
campaign-enrollments:create (+ messages:create para o atalho de template em massa).
Quem recebe a campanha é quem está inscrito nela. Cada inscrição liga um contato a uma
campanha e guarda em que ponto da cadência ele está. Pela API, criar a campanha não inscreve
ninguém, e incluir um contato numa lista também não: a inscrição é sempre um passo explícito.
Crie a campanha
POST /v1/campaigns. Campos obrigatórios: name, channel_type, trigger_type e
audience_config; opcionais incluem description, trigger_config, behavior_config,
sender_config e exclusion_lists. As estruturas internas desses objetos de configuração estão
na Referência da API. Siga o schema de lá.A campanha nasce como rascunho. audience_config descreve a audiência, mas não inscreve ninguém
quando a campanha é criada pela API. As inscrições vêm no passo seguinte.As listas de exclusão (exclusion_lists) só podem ser escolhidas enquanto a campanha é
rascunho. Depois da ativação, o que muda é o conteúdo delas (veja o
Caso 4).Inscreva a audiência
campaign-enrollments:create:Confira antes de disparar
POST /v1/campaigns/audience-preview conta os contatos da
audiência e POST /v1/campaigns/preview-message resolve as variáveis da mensagem.Ative e acompanhe
POST /v1/campaigns/:id/activate (pause com /pause). A campanha precisa ter ao menos
uma etapa ativa. A ativação coloca na fila os contatos já inscritos e devolve quantos foram em
enrollments_enqueued.GET /v1/campaigns/:id/analytics e GET /v1/campaigns/:id/step-analytics, e
exporte os contatos com GET /v1/campaigns/:id/enrollments/export.POST /v1/messages/send-bulk-template (escopo messages:create). O passo a passo, com os
parâmetros de template e os limites da Meta, está no guia
Template em massa no WhatsApp.Caso 4: Inscrever contatos a partir do seu CRM
Para integrações em que o seu sistema decide quem entra em qual cadência: a campanha já está ativa, e cada contato é inscrito no momento em que o CRM pede. A Nuvia faz os envios, encerra a cadência quando o lead responde e devolve os eventos para você atualizar o CRM. Escopos:campaign-enrollments:create, campaign-enrollments:read, campaigns:read e
contacts:read (+ messages:read para ler as conversas e webhooks:create para receber os
eventos).
Escolha a campanha
GET /v1/campaigns lista as campanhas com status e canal; GET /v1/campaigns/:id traz uma.
Guarde o id da campanha de cada cadência. A inscrição só é aceita em campanha com status
ACTIVE.O canal da campanha define o identificador obrigatório do contato: campanha de LinkedIn exige
linkedin_identifier; qualquer outra exige telefone. Use uma campanha por canal e deixe o CRM
decidir em qual inscrever.Inscreva o contato
POST /v1/campaigns/:id/enrollments/from-contact. A rota localiza o contato pelo telefone (ou,
sem telefone, pelo linkedin_identifier), cria o contato se ele não existir e o inscreve na
campanha.Leia o resultado
status igual a enrolled ou skipped:enroll_again, uma reinscrição vem com re_enrolled: true. Quando a inscrição é ignorada,
o motivo vem em reason, junto com o contactId quando o contato foi localizado:404 quando a campanha não existe ou é de outra empresa, 409 quando ela não está
ACTIVE e 400 quando o corpo é inválido (por exemplo, sem phone nem linkedin_identifier).Guarde os IDs no CRM
contactId, o enrollmentId e o id da campanha junto do registro do CRM. São eles que
ligam os eventos e as consultas da Nuvia ao seu negócio ou oportunidade.Na Nuvia, uma pessoa é um contato, com um vínculo de CRM:fieldsgrava no contato, não na inscrição. A inscrição não tem campo de negócio.external_idé um só por contato e vale o último enviado.- As variáveis das mensagens usam o valor atual do contato.
fields dado específico de um negócio: a inscrição do negócio B sobrescreve o valor
do negócio A no contato.Trate repetição e timeout
skipped com already_enrolled (ou already_in_progress, com enroll_again) como sucesso.Acompanhe as inscrições
status:completion_reason ausente, nulo ou com
valor novo sem quebrar.Quando o lead responde, a Nuvia encerra todas as inscrições ativas dele que já tiveram
atividade (envio, falha ou convite), em qualquer campanha, com completion_reason: REPLIED.
A cadência para sozinha: o seu sistema não precisa interrompê-la, só levar o lead para a próxima
ação comercial.Não existe webhook de inscrição criada, de mudança de status ou de conclusão. Para manter o CRM em
dia, consulte periodicamente:contactId nem por enrollmentId. Por isso o
enrollmentId guardado no CRM é a sua referência.Receba as respostas por webhook
- Resposta do lead:
MESSAGE_RECEIVEDcomsender_type: CONTACTemessage_type: INCOMING. Filtre pelos dois campos: o evento também dispara para mensagens que não são do lead, como as enviadas pelo app do WhatsApp Business em coexistência. Veja quem enviou a mensagem. - Falha de entrega:
MESSAGE_FAILED. Falhas anteriores à tentativa de envio não geram webhook e só aparecem nas execuções da campanha. - Mudança de etapa do funil:
CONVERSATION_STEP_CHANGEDnão indica resposta. Uma etapa de campanha pode mover a conversa para uma etapa do funil no próprio envio, antes de o lead responder.
external_id. Use o contactId para
achar o registro no CRM. O webhook faz uma única tentativa de entrega, então mantenha a consulta
periódica do passo anterior para reconciliar eventos perdidos.Evite cadências simultâneas
- No CRM: antes de inscrever, confira se o contato já tem inscrição em andamento pelos
enrollmentIdque você guardou. - Na Nuvia: use listas de exclusão. Elas são escolhidas na criação da campanha (só enquanto
ela é rascunho), mas o conteúdo de cada lista é consultado antes de cada envio. Incluir um
contato numa lista de exclusão depois da ativação já vale para os próximos envios, e a
inscrição dele encerra com
EXCLUSION_LIST.
Caso 5: Sincronizar contatos
Mantenha seu CRM externo e a Nuvia em sincronia. Escopos:contacts:read, contacts:create, contacts:update, contacts:delete.
Cheque duplicidade por telefone
POST /v1/contacts/find-by-phones.Crie os contatos que faltam
POST /v1/contacts. Obrigatórios: name e pelo menos um identificador entre telefone
(phone_number, só dígitos, DDD + número, sem o DDI, junto com country_code, ex.: 55),
email e linkedin_identifier. Opcionais: campos de perfil como job_title e city, e
additional_attributes ({ "slug": valor }) para campos personalizados.Se a empresa já tem um contato com algum dos identificadores, a rota reaproveita esse contato em
vez de duplicar. A procura segue a ordem e-mail, LinkedIn e telefone:201: contato criado, comcreated: true.200: contato existente reaproveitado, comcreated: falseematched_by(email,linkedinouphone). Achado pelo telefone, os campos enviados são atualizados. Achado por e-mail ou LinkedIn, só os campos vazios são preenchidos, eignored_fieldslista o que não foi gravado.409CONTACT_IDENTITY_CONFLICT: os identificadores pertencem a contatos diferentes. Nada é gravado, econflictstraz o contato de cada identificador.
name de um contato existente nunca muda: para trocá-lo, use PUT /v1/contacts/:id. Para
saber o que a rota faria sem gravar nada, use POST /v1/contacts/identity-check.Atualize e liste
PUT /v1/contacts/:id (ou só o nome com PUT /v1/contacts/:id/name) e
liste/pagine com GET /v1/contacts. Para remover o vínculo de um contato com um CRM externo,
use DELETE /v1/contacts/:id/crm-link: isso apenas desfaz a vinculação; o contato continua
existindo na Nuvia (não é exclusão de contato).Caso 6: Atribuir a conversa ao owner do HubSpot
Para automações que recebem um evento do HubSpot com um owner (por exemplo, o dono de uma reunião agendada) e precisam atribuir a conversa na Nuvia ao usuário correspondente. O mapeamento entre owners do HubSpot e usuários da Nuvia é configurado na tela de integração HubSpot. A API só o lê. Escopos:hubspot:read e conversations:update (+ conversations:read para localizar a
conversa). Uma chave existente não ganha o escopo: gere uma nova com ele marcado (veja o
Guia de API Key).
Leia o mapeamento de owners
GET /v1/hubspot/owner-mappings devolve os pares owner do HubSpot ↔ usuário da Nuvia da sua
empresa.nuvia_user_id é o id do usuário da Nuvia que você usa para atribuir a conversa. Se a
empresa não tem o HubSpot conectado, a lista vem vazia.Guarde o mapeamento em cache e encontre o usuário
owner-mappings uma vez, guarde por alguns minutos e procure
o owner do evento pelo hubspot_owner_id. Não use o e-mail: hubspot_owner_email é uma cópia
de quando o mapeamento foi salvo e não se atualiza se o e-mail mudar no HubSpot.Atribua a conversa
PUT /v1/conversations/:id/assign-owner com o nuvia_user_id em userId. A rota define o
dono da conversa e não muda quem está respondendo: se a IA atende, ela continua atendendo. Para
passar o atendimento a uma pessoa, use PUT /v1/conversations/:id/assign-user.