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… | Use | Credencial | Alcance |
|---|---|---|---|
| Ler e responder conversas, sincronizar contatos, puxar relatórios | Application API | api_access_token de agent bot | Uma conta, ações de atendimento |
| Embutir o chat no seu produto, para o seu usuário final falar com o suporte | Client API | Nenhuma — rota pública, identidade via HMAC | Um contato, as conversas dele |
| Criar contas e usuários (revenda, provisionamento white-label) | Platform API | api_access_token de platform app | Instalação inteira |
| Trazer um canal de mensagens próprio seu para dentro do Nexchat | Canal API | Application API + webhook assinado | Uma inbox |
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
| Item | Valor |
|---|---|
| Base URL | https://chat.nexxchat.com.br |
| Protocolo | HTTPS obrigatório. Chamada em HTTP é redirecionada e o token vaza no caminho — trate redirect 301 como erro de configuração sua. |
| Formato | JSON nos dois sentidos. Envie Content-Type: application/json. |
| Versionamento | No caminho: /api/v1/…, /api/v2/… (só relatórios), /public/api/v1/…, /platform/api/v1/…. Não há negociação por header. |
| Fuso | Timestamps 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>
| Tipo | Dono | Abre | Para parceiro |
|---|---|---|---|
agentBotApiKey | Agent bot | 7 operações, lista fechada | recomendado |
userApiKey | Usuário humano | 110 operações, conforme a permissão da pessoa | não emitimos |
platformAppApiKey | Platform app | 17 operações sobre a instalação toda | nunca 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:
| Recurso | Ações liberadas |
|---|---|
| Conversas | show · create · update · toggle_status · toggle_priority · toggle_typing_status · custom_attributes |
| Mensagens da conversa | create |
| Atribuição da conversa | create |
| Etiquetas da conversa | index · 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ê
- Você nos envia o nome da integração, a URL do seu webhook e os IPs de saída do seu backend.
- Nós criamos o agent bot na conta do cliente e devolvemos o token por canal cifrado, uma vez.
- Você guarda o token em cofre de segredos — nunca em repositório, variável de build, log ou código de frontend.
- 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.
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" }'
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:
| Valor | O que é | Quem gera |
|---|---|---|
inbox_identifier | Identificador da inbox do canal API. Público por natureza — vai no seu frontend. | Nexchat |
contact_identifier | O source_id do contato. É o que dá acesso à conversa daquela pessoa. | Você |
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"
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ê:
- Sem HMAC verificado — as leituras ficam restritas às conversas daquele vínculo contato-inbox.
- Com HMAC verificado — as leituras passam a abranger todas as conversas do contato, inclusive as que vieram por WhatsApp, e-mail ou telefone.
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.
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ção | Como |
|---|---|
| Seu canal → Nexchat | POST /api/v1/accounts/{id}/conversations/{id}/messages com message_type: "incoming" |
| Nexchat → seu canal | POST 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:
| Conversa | Mensagem | Contato / Inbox |
|---|---|---|
conversation_createdconversation_updatedconversation_status_changedconversation_typing_onconversation_typing_off |
message_createdmessage_updatedwebwidget_triggered |
contact_createdcontact_updatedinbox_createdinbox_updated |
Verificar a assinatura
Quando o webhook tem segredo, cada entrega traz estes headers:
| Header | Conteúdo |
|---|---|
X-Chatwoot-Signature | sha256= + HMAC-SHA256 hex de "{timestamp}.{corpo bruto}" |
X-Chatwoot-Timestamp | Unix epoch em segundos, o mesmo usado no cálculo |
X-Chatwoot-Delivery | Id da entrega, quando presente. Use para idempotência. |
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"));
});
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.
| Escopo | Limite | Janela |
|---|---|---|
| Geral, por IP | 3.000 requisições | 1 min |
| Busca de contatos, por conta | 100 | 1 min |
| Relatórios, por conta | 1.000 | 1 min |
| Relatórios, por chamador | 100 | 1 min |
conversations/meta, por chamador | 30 | 1 min |
| Upload de anexo, por conta | 60 | 1 h |
| Criar agente, por conta | 100 | 1 dia |
| Excluir conversa, por conta | 60 | 1 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ódigo | Significa | O que fazer |
|---|---|---|
401 | Token ausente, inválido, ou rota fora da lista do bot | Não repita. Confira o header e o tipo do token. |
403 | Token válido, permissão insuficiente na conta | Peça a permissão; repetir não resolve. |
404 | Recurso inexistente ou fora do seu alcance | Os dois casos respondem igual, de propósito. Não use 404 para inferir existência. |
422 | Payload recusado na validação | Corpo traz os campos com erro. É bug seu — não retente. |
429 | Limite estourado | Backoff com jitter. |
5xx | Falha nossa | Retente 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.
- 01Validação de identidade ligada na inbox
Toda inbox de canal API que serve usuário final roda com identity validation. O
hmac_tokenfica só no seu backend, e oidentifieré opaco — nunca CPF, e-mail, telefone ou id sequencial. - 02Assinatura de webhook verificada, com janela de replay
Corpo bruto, comparação em tempo constante, e rejeição de
X-Chatwoot-Timestampcom mais de 5 minutos. Endpoint que aceita entrega não assinada é endpoint público para qualquer um. - 03Token de agent bot, guardado em cofre
Sem token de usuário humano, sem token de platform app, nada no frontend, nada em repositório. Se um token vazar, nos avise antes de rotacionar: a rotação invalida o anterior na hora e derruba a integração.
- 04Dado de assinante não sai do necessário
A API devolve nome, telefone, e-mail, histórico de conversa e atributos personalizados. Isso é dado pessoal sob LGPD. Não espelhe em base sua o que você não usa, e não mande nada disso para terceiro ou provedor de IA sem previsão em contrato.
- 05Log sem segredo e sem conteúdo de conversa
Nunca logue o header
api_access_token, ohmac_token, o segredo de webhook, nem o corpo das mensagens. Em erro, logue oX-Chatwoot-Deliverye o código HTTP. - 06Backoff e idempotência
Retentativa com jitter,
source_idestável para não duplicar contato nem conversa, e deduplicação de webhook por id de entrega. - 07Um conjunto de credenciais por ambiente
Homologação e produção com tokens, inboxes e segredos distintos. Teste de carga combinado antes, nunca contra a conta de um cliente real.
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.