@datahex/wpp-client
v1.0.3
Published
Cliente Node.js para consumir a Datahex WPP API
Readme
@datahex/wpp-client
Biblioteca Node.js para consumir a Datahex WPP API em outras aplicações.
Ela encapsula:
- Autenticação por API token
- Chamadas HTTP da API
- Conexão Socket.IO autenticada
- Entrada automática na room da instância
- Eventos de QR Code, status e mensagens
- Envio de mensagem de texto pela fila da API
Requisitos
- Node.js 22+
- API Datahex WPP rodando
- API token criado em
POST /api-tokens - Uma instância WhatsApp criada
Teste com API real
Para validar o pacote contra uma API Datahex WPP real, configure as variáveis de ambiente e rode:
cp .env.example .env
# edite .env com os dados reais da sua API
npm run test:integrationO teste chama listInstances() usando o token real. Quando DATAHEX_WPP_INSTANCE_ID é informado, ele também chama getInstance() para essa instância. Quando DATAHEX_WPP_TEST_TO também é informado, ele envia uma mensagem real usando sendText().
Instalação
npm install @datahex/wpp-clientUso básico
import { DatahexWppClient } from '@datahex/wpp-client';
const wpp = new DatahexWppClient({
baseUrl: 'http://localhost:3000',
apiToken: process.env.DATAHEX_WPP_TOKEN!,
instanceId: process.env.DATAHEX_WPP_INSTANCE_ID!
});
wpp.on('wa:status', ({ status }) => {
console.log('status:', status);
});
wpp.on('wa:qr', ({ qr }) => {
console.log('QR Code data URL:', qr);
});
wpp.on('wa:message:received', ({ message }) => {
console.log('mensagem recebida:', message.remoteJid, message.text);
});
await wpp.connectWhatsapp();
await wpp.sendText({
to: '5511999999999',
text: 'Olá pela integração'
});Criar instância e conectar
const instance = await wpp.createInstance({ name: 'Integração ERP' });
wpp.on('wa:qr', ({ qr }) => {
// `qr` é uma data URL pronta para renderizar em img src.
console.log(qr);
});
await wpp.connectWhatsapp(instance._id);Enviar mensagem
Usando a instância configurada no construtor:
await wpp.sendText({
to: '5511999999999',
text: 'Pedido aprovado'
});Usando uma instância específica:
await wpp.sendText({
instanceId: '665f...',
to: '5511999999999',
text: 'Pedido aprovado'
});O método retorna o job criado na fila:
const job = await wpp.sendText({ to: '5511999999999', text: 'Olá' });
console.log(job.jobId, job.status);O envio real acontece no worker da API. Escute os eventos para saber o resultado:
wpp.on('wa:message:sent', ({ message }) => {
console.log('enviada:', message.messageId);
});
wpp.on('wa:message:error', ({ error }) => {
console.error('falha:', error);
});Contatos unificados
Mensagens continuam expondo remoteJid, mas podem trazer também contactId. Use os métodos de contato quando quiser agrupar conversas que alternam entre telefone e LID:
const contacts = await wpp.listContacts();
const messages = await wpp.listContactMessages(contacts[0]._id);
const profilePhoto = await wpp.loadContactProfilePhoto(contacts[0]._id);
if (profilePhoto?.downloadUrl) {
console.log(profilePhoto.downloadUrl);
}
await wpp.sendContactText({
contactId: contacts[0]._id,
text: 'Mensagem para o contato unificado'
});Enviar mídia
O pacote suporta imagens, áudios e PDFs. O arquivo é enviado para a API em base64; a API armazena no MinIO por tempo limitado e envia ao WhatsApp pelo worker.
import { readFile } from 'node:fs/promises';
await wpp.sendImage({
to: '5511999999999',
data: await readFile('./foto.png'),
mimetype: 'image/png',
caption: 'Imagem do pedido'
});
await wpp.sendAudio({
to: '5511999999999',
data: await readFile('./audio.ogg'),
mimetype: 'audio/ogg'
});
await wpp.sendPdf({
to: '5511999999999',
data: await readFile('./boleto.pdf'),
mimetype: 'application/pdf',
fileName: 'boleto.pdf'
});Também existem variantes por contato unificado:
await wpp.sendContactImage({ contactId, data, mimetype: 'image/jpeg' });
await wpp.sendContactAudio({ contactId, data, mimetype: 'audio/ogg' });
await wpp.sendContactPdf({ contactId, data, mimetype: 'application/pdf', fileName: 'arquivo.pdf' });Mensagens recebidas e eventos podem trazer message.media:
wpp.on('wa:message:received', ({ message }) => {
if (message.media?.downloadUrl) {
console.log(message.media.kind, message.media.downloadUrl, message.media.expiresAt);
}
});Eventos
wpp.on('connect', () => {});
wpp.on('disconnect', (reason) => {});
wpp.on('error', (error) => {});
wpp.on('wa:qr', ({ instanceId, qr }) => {});
wpp.on('wa:status', ({ instanceId, status }) => {});
wpp.on('wa:connected', ({ instanceId, user }) => {});
wpp.on('wa:disconnected', ({ instanceId, shouldReconnect, manual }) => {});
wpp.on('wa:message:received', ({ instanceId, message }) => {});
wpp.on('wa:message:sent', ({ instanceId, message }) => {});
wpp.on('wa:message:error', ({ instanceId, jobId, error }) => {});API do cliente
new DatahexWppClient(config)
type WppClientConfig = {
baseUrl: string;
apiToken: string;
instanceId?: string;
autoConnectSocket?: boolean;
socketTransports?: Array<'websocket' | 'polling'>;
};Por padrão, autoConnectSocket é true.
Métodos
setInstance(instanceId)getInstanceId()connectSocket()disconnectSocket()createInstance({ name })listInstances()getInstance(instanceId?)connectWhatsapp(instanceId?)disconnectWhatsapp(instanceId?)deleteInstance(instanceId?)sendText({ to, text, instanceId? })sendImage({ to, data, mimetype, caption?, fileName?, instanceId? })sendAudio({ to, data, mimetype, caption?, fileName?, instanceId? })sendPdf({ to, data, mimetype, caption?, fileName?, instanceId? })listMessages(instanceId?)listContacts(instanceId?)listContactMessages(contactId, instanceId?)loadContactProfilePhoto(contactId, instanceId?)sendContactText({ contactId, text, instanceId? })sendContactImage({ contactId, data, mimetype, caption?, fileName?, instanceId? })sendContactAudio({ contactId, data, mimetype, caption?, fileName?, instanceId? })sendContactPdf({ contactId, data, mimetype, caption?, fileName?, instanceId? })on(event, listener)once(event, listener)off(event, listener)
Quando instanceId não é informado no método, a biblioteca usa a instância configurada no construtor ou em setInstance.
Tratamento de erros
Erros HTTP são lançados como DatahexWppApiError:
import { DatahexWppApiError } from '@datahex/wpp-client';
try {
await wpp.sendText({ to: '5511999999999', text: 'Olá' });
} catch (error) {
if (error instanceof DatahexWppApiError) {
console.error(error.status, error.payload);
}
}Encerramento
Feche o Socket.IO quando sua aplicação finalizar:
process.on('SIGINT', () => {
wpp.disconnectSocket();
process.exit(0);
});