Integração com a API do Nexchat

O Nexchat expõe 149 operações HTTP divididas em três APIs com públicos e poderes diferentes, mais um canal de inbox que entrega eventos por webhook assinado. Esta página é o contrato de integração: o que chamar, com qual credencial, e o que o seu lado precisa garantir para que a conta de um cliente nosso não vire porta de entrada no seu produto — nem o contrário.

Leia a seção Requisitos de segurança antes de escrever código. Três itens dela não são recomendação: sem eles a integração não é liberada em produção.

Qual API usar

A escolha errada aqui é a causa mais comum de integração insegura, porque a API mais fácil de usar é também a mais poderosa. Comece pela coluna da direita.

Se você quer…UseCredencialAlcance
Ler e responder conversas, sincronizar contatos, puxar relatóriosApplication APIapi_access_token de agent botUma conta, ações de atendimento
Embutir o chat no seu produto, para o seu usuário final falar com o suporteClient APINenhuma — rota pública, identidade via HMACUm contato, as conversas dele
Criar contas e usuários (revenda, provisionamento white-label)Platform APIapi_access_token de platform appInstalação inteira
Trazer um canal de mensagens próprio seu para dentro do NexchatCanal APIApplication API + webhook assinadoUma inbox
O token de usuário não entra nesta tabela de propósito

Existe um terceiro tipo de credencial — o api_access_token de um usuário humano. Ele abre as 110 operações da Application API com a permissão daquela pessoa, não expira, não tem escopo e não tem como ser revogado individualmente. Nós não emitimos esse token para parceiros, e você não deve pedi-lo. Para integração de backend, o token de agent bot faz o mesmo trabalho com uma fração do poder.

Base e versões

ItemValor
Base URLhttps://chat.nexxchat.com.br
ProtocoloHTTPS obrigatório. Chamada em HTTP é redirecionada e o token vaza no caminho — trate redirect 301 como erro de configuração sua.
FormatoJSON nos dois sentidos. Envie Content-Type: application/json.
VersionamentoNo caminho: /api/v1/…, /api/v2/… (só relatórios), /public/api/v1/…, /platform/api/v1/…. Não há negociação por header.
FusoTimestamps em UTC, ISO 8601. Campos *_at de relatório vêm em epoch seconds.

Autenticação

As três APIs usam o mesmo header, com significados diferentes. O que define o poder do chamador é o tipo do dono do token, não a rota.

api_access_token: <seu-token>
TipoDonoAbrePara parceiro
agentBotApiKeyAgent bot7 operações, lista fechadarecomendado
userApiKeyUsuário humano110 operações, conforme a permissão da pessoanão emitimos
platformAppApiKeyPlatform app17 operações sobre a instalação todanunca compartilhado

Por que o token de agent bot é o certo

O servidor mantém uma lista fechada do que um bot pode fazer. Qualquer rota fora dela responde 401 com Access to this endpoint is not authorized for bots, independentemente do que a conta permita. Esta é a lista inteira, como está no servidor:

RecursoAções liberadas
Conversasshow · create · update · toggle_status · toggle_priority · toggle_typing_status · custom_attributes
Mensagens da conversacreate
Atribuição da conversacreate
Etiquetas da conversaindex · create

Se a sua integração precisa de algo fora dessa lista — ler contatos em massa, puxar relatório, criar inbox — peça isso explicitamente. Nós avaliamos caso a caso e, quando faz sentido, a conta recebe um usuário de integração dedicado com permissão mínima, nunca o token de um atendente real.

Como o token chega até você

  1. Você nos envia o nome da integração, a URL do seu webhook e os IPs de saída do seu backend.
  2. Nós criamos o agent bot na conta do cliente e devolvemos o token por canal cifrado, uma vez.
  3. Você guarda o token em cofre de segredos — nunca em repositório, variável de build, log ou código de frontend.
  4. Rotação: você pede, nós regeramos. A regeração invalida o token anterior na hora, porque cada dono tem um único token. Planeje a troca como uma janela, não como sobreposição.
O token é um segredo de servidor

Nenhum dos tokens acima pode aparecer em código que roda no navegador ou em app móvel. O header api_access_token não tem escopo de origem: quem o lê, usa. Para falar com o Nexchat a partir do navegador existe exatamente um caminho desenhado para isso, a Client API, e ela não usa token.

Application API

A API de atendimento, sob /api/v1/accounts/{account_id}. É onde vive a operação: conversas, mensagens, contatos, etiquetas, times, relatórios. O account_id é o número da conta do cliente e é fixo por integração — nós informamos.

Criar uma conversa e responder

# 1. achar ou criar o contato
curl -X POST https://chat.nexxchat.com.br/api/v1/accounts/1/contacts \
  -H "api_access_token: $NEXCHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "inbox_id": 7,
    "name": "Maria Andrade",
    "phone_number": "+554933402026",
    "custom_attributes": { "contrato": "ISP-99120" }
  }'

# 2. abrir a conversa nessa inbox
curl -X POST https://chat.nexxchat.com.br/api/v1/accounts/1/conversations \
  -H "api_access_token: $NEXCHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "source_id": "ISP-99120", "inbox_id": 7, "contact_id": 4821 }'

# 3. mandar a mensagem
curl -X POST https://chat.nexxchat.com.br/api/v1/accounts/1/conversations/312/messages \
  -H "api_access_token: $NEXCHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "content": "Sua visita técnica está confirmada para amanhã, 14h.", "message_type": "outgoing" }'
source_id é a sua chave de idempotência

Mande sempre o identificador do cliente no seu sistema como source_id. Ele amarra o contato do Nexchat ao registro do seu lado e evita duplicata quando a sua fila reprocessa. Use um identificador que já seja opaco no seu domínio, como o id interno do contrato. Não use CPF, e-mail ou telefone: além da exposição em log, isso torna a chave adivinhável — ver Client API, onde isso vira problema de verdade.

Paginação e filtro

As listagens paginam por ?page=N, 25 itens por página, e devolvem a contagem em meta. Para busca estruturada existe POST .../contacts/filter e POST .../conversations/filter, que aceitam um array de condições — preferíveis a varrer páginas.

curl -X POST https://chat.nexxchat.com.br/api/v1/accounts/1/conversations/filter \
  -H "api_access_token: $NEXCHAT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "payload": [
        { "attribute_key": "status", "filter_operator": "equal_to",
          "values": ["open"], "query_operator": "AND" },
        { "attribute_key": "inbox_id", "filter_operator": "equal_to", "values": [7] }
      ] }'

Client API

Sob /public/api/v1/inboxes/{inbox_identifier}. É a única API que roda no navegador do seu usuário final: sem token, liberada para qualquer origem por CORS. Ela existe para você embutir o chat no seu produto.

O preço de não ter token é que a identidade do chamador vem do caminho da URL. Dois valores:

ValorO que éQuem gera
inbox_identifierIdentificador da inbox do canal API. Público por natureza — vai no seu frontend.Nexchat
contact_identifierO source_id do contato. É o que dá acesso à conversa daquela pessoa.Você
Requisito 1: ative a validação de identidade (HMAC)

Por padrão, a inbox do canal API aceita qualquer contact_identifier que exista, sem provar que o chamador é aquela pessoa. Se o seu source_id for derivado de algo que outra pessoa pode descobrir — e-mail, CPF, telefone, id sequencial — quem adivinhar o valor lê e escreve na conversa daquele cliente a partir de qualquer navegador do mundo.

Não desenhe em volta disso: peça a ativação do identity validation na inbox. Com ela ligada, toda chamada precisa de um identifier_hash válido, e o servidor rejeita o resto.

Como assinar o identificador

Nós entregamos um hmac_token por inbox. Ele é segredo de servidor: o hash é calculado no seu backend e entregue ao frontend já pronto. O frontend nunca vê o token.

// Node 18+, no SEU backend
import { createHmac } from "node:crypto";

export function identifierHash(identifier) {
  return createHmac("sha256", process.env.NEXCHAT_HMAC_TOKEN)
    .update(String(identifier))
    .digest("hex");
}

O servidor recalcula HMAC-SHA256(hmac_token, identifier) e compara em tempo constante. O hash cobre o identifier e nada mais — então ele prova quem é o contato, não o que a requisição pede.

Fluxo completo

# 1. registrar/identificar o contato — backend chama, com o hash
curl -X POST https://chat.nexxchat.com.br/public/api/v1/inboxes/$INBOX_ID/contacts \
  -H "Content-Type: application/json" \
  -d '{
    "identifier": "ISP-99120",
    "identifier_hash": "4f0c…",
    "name": "Maria Andrade",
    "email": "maria@exemplo.com.br"
  }'
# → devolve source_id, que é o contact_identifier das chamadas seguintes

# 2. abrir conversa
curl -X POST ".../public/api/v1/inboxes/$INBOX_ID/contacts/$CONTACT_ID/conversations" \
  -H "Content-Type: application/json" -d '{}'

# 3. mandar mensagem do usuário final
curl -X POST ".../public/api/v1/inboxes/$INBOX_ID/contacts/$CONTACT_ID/conversations/$CONV/messages" \
  -H "Content-Type: application/json" \
  -d '{ "content": "Minha internet caiu desde ontem à noite." }'

# 4. ler o histórico (paginado por ?before=)
curl ".../public/api/v1/inboxes/$INBOX_ID/contacts/$CONTACT_ID/conversations/$CONV/messages"
Requisito 2: não mande e-mail nem telefone de outra pessoa no update

PATCH .../contacts/{contact_identifier} roda o fluxo de identificação do Nexchat, que unifica contatos quando o e-mail ou o telefone enviado já pertence a outro contato da mesma conta. Isso é útil quando é a mesma pessoa chegando por dois canais, e é um vazamento quando não é.

Mande nesse endpoint apenas dados que o próprio usuário autenticado no seu produto acabou de confirmar. Nunca repasse um e-mail digitado em formulário aberto, nem preencha o campo a partir de uma base sua sem checar de quem é a sessão.

Escopo de leitura

Vale entender porque muda o que o seu usuário vê:

O segundo é o comportamento desejado num portal do cliente: a pessoa vê o histórico dela inteiro, não só o pedaço que passou pelo seu widget. Mas ele também eleva o identifier a credencial de verdade. Trate o hmac_token com o mesmo cuidado de uma chave de assinatura de sessão.

Platform API

Sob /platform/api/v1. Cria contas, usuários e agent bots na instalação. São 17 operações e todas valem para a instalação inteira, não para uma conta.

Esta API não é compartilhada com parceiros

Entre as 17 operações está GET /platform/api/v1/users/{id}/login, que devolve uma URL de login pronta para qualquer usuário da instalação, sem senha e sem segundo fator. Um token de platform app é, na prática, acesso administrativo a todos os clientes do Nexchat ao mesmo tempo.

Se o seu produto precisa criar contas — revenda, onboarding self-service — o provisionamento roda do nosso lado, atrás de um endpoint nosso que valida o seu pedido. Documentamos esse endpoint junto com o contrato de revenda. A Platform API está listada aqui para você saber que ela existe e que o token dela nunca deve ser pedido nem aceito.

Canal API (inbox)

Se o seu produto já tem um canal de mensagens próprio — um app, um portal, um PABX — o canal API o pluga no Nexchat. Mensagem que entra vai pela Application API; mensagem que o atendente responde chega no seu webhook_url configurado na inbox.

DireçãoComo
Seu canal → NexchatPOST /api/v1/accounts/{id}/conversations/{id}/messages com message_type: "incoming"
Nexchat → seu canalPOST no webhook_url da inbox, assinado (abaixo)

A inbox tem um parâmetro agent_reply_time_window que limita por quanto tempo depois da última mensagem do contato o atendente pode responder — espelha a janela de 24h do WhatsApp. Se o seu canal não tem essa restrição, deixe-o em branco.

Webhooks

O Nexchat entrega eventos por POST JSON. Há dois lugares para registrar: POST /api/v1/accounts/{id}/webhooks (eventos da conta, com assinatura de inscrições) e o webhook_url da inbox do canal API.

Eventos disponíveis

Estes treze, e nenhum outro — a inscrição é validada e um nome fora da lista derruba a criação do webhook:

ConversaMensagemContato / Inbox
conversation_created
conversation_updated
conversation_status_changed
conversation_typing_on
conversation_typing_off
message_created
message_updated
webwidget_triggered
contact_created
contact_updated
inbox_created
inbox_updated

Verificar a assinatura

Quando o webhook tem segredo, cada entrega traz estes headers:

HeaderConteúdo
X-Chatwoot-Signaturesha256= + HMAC-SHA256 hex de "{timestamp}.{corpo bruto}"
X-Chatwoot-TimestampUnix epoch em segundos, o mesmo usado no cálculo
X-Chatwoot-DeliveryId da entrega, quando presente. Use para idempotência.
Os headers têm prefixo X-Chatwoot-

O Nexchat é construído sobre o Chatwoot e os nomes dos headers preservam o prefixo de origem. Não é erro de configuração e não vai mudar sem aviso — trate os nomes como literais.

// Express — verificação com corpo BRUTO e defesa de replay
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";

const app = express();
app.post("/webhooks/nexchat",
  express.raw({ type: "application/json" }),   // o corpo cru, não o parseado
  (req, res) => {
    const ts  = req.get("X-Chatwoot-Timestamp") ?? "";
    const sig = req.get("X-Chatwoot-Signature") ?? "";

    // 1. rejeita entrega velha: o timestamp é assinado, mas quem decide a
    //    janela é você. Sem isto, uma entrega capturada vale para sempre.
    const idade = Math.abs(Date.now() / 1000 - Number(ts));
    if (!ts || Number.isNaN(idade) || idade > 300) return res.sendStatus(401);

    // 2. recalcula sobre "{ts}.{corpo bruto}"
    const esperado = "sha256=" + createHmac("sha256", process.env.NEXCHAT_WEBHOOK_SECRET)
      .update(`${ts}.${req.body.toString("utf8")}`)
      .digest("hex");

    // 3. compara em tempo constante, com os tamanhos conferidos antes
    const a = Buffer.from(sig), b = Buffer.from(esperado);
    if (a.length !== b.length || !timingSafeEqual(a, b)) return res.sendStatus(401);

    // 4. responda rápido. O Nexchat espera 5s por padrão e desiste.
    res.sendStatus(200);
    enfileirar(JSON.parse(req.body.toString("utf8")), req.get("X-Chatwoot-Delivery"));
  });
Requisito 3: processe fora da requisição

O tempo limite de entrega é de 5 segundos por padrão, para abrir e para ler. Se o seu handler faz trabalho síncrono — gravar em banco, chamar outra API, enviar e-mail — a entrega estoura o prazo e é contada como falha.

E falha tem efeito visível do nosso lado: em message_created e message_updated, erro na entrega para uma inbox de canal API marca a mensagem como failed na tela do atendente; para um agent bot, tira a conversa de pending e a devolve para a fila humana. Responda 200 primeiro, processe depois.

Respostas 429 e 500 de um webhook de agent bot são retentadas. Outros códigos, não — a entrega é descartada. Por isso a idempotência por X-Chatwoot-Delivery importa dos dois lados.

Limites e erros

O Nexchat limita por IP e por conta. Os valores abaixo são os de produção; integração que trombe neles com frequência é sinal de desenho errado, não de limite baixo.

EscopoLimiteJanela
Geral, por IP3.000 requisições1 min
Busca de contatos, por conta1001 min
Relatórios, por conta1.0001 min
Relatórios, por chamador1001 min
conversations/meta, por chamador301 min
Upload de anexo, por conta601 h
Criar agente, por conta1001 dia
Excluir conversa, por conta601 min

Estouro responde 429. Faça backoff exponencial com jitter; não reenvie em laço fixo. Os contadores por chamador usam o seu token como chave, então duas integrações com o mesmo token dividem o mesmo balde — mais um motivo para cada parceiro ter o seu.

CódigoSignificaO que fazer
401Token ausente, inválido, ou rota fora da lista do botNão repita. Confira o header e o tipo do token.
403Token válido, permissão insuficiente na contaPeça a permissão; repetir não resolve.
404Recurso inexistente ou fora do seu alcanceOs dois casos respondem igual, de propósito. Não use 404 para inferir existência.
422Payload recusado na validaçãoCorpo traz os campos com erro. É bug seu — não retente.
429Limite estouradoBackoff com jitter.
5xxFalha nossaRetente com backoff, idempotente via source_id.

Referência completa

As 149 operações, extraídas da especificação OpenAPI 3.1 que acompanha a versão em produção. A coluna de credencial diz o tipo mínimo de token aceito.

Requisitos de segurança

Os três primeiros itens são condição para liberar a integração em produção. Os demais são o que esperamos de um parceiro que trata dado de assinante de ISP.

Dúvida de integração ou pedido de escopo além da lista do bot: abra com a equipe técnica do Nexchat informando a conta, a inbox e a operação que falta. Peça sempre a operação, não o token.

Referência gerada da especificação OpenAPI 3.1 que acompanha a versão em produção do Nexchat em chat.nexxchat.com.br. Onde esta página e a especificação divergirem, vale esta página — ela reflete as restrições da nossa instalação, que são mais estreitas que as do projeto de origem.