@zappnix/sdk
v1.0.2
Published
SDK oficial TypeScript da Zappnix API — automação de WhatsApp com fluxos, webhooks e anti-ban embutido.
Downloads
398
Maintainers
Readme
@zappnix/sdk
SDK oficial TypeScript da Zappnix API — automação de WhatsApp com fluxos, webhooks e anti-ban embutido.
Instalação
npm install @zappnix/sdkRequisitos: Node.js 18+ (usa fetch nativo).
Quickstart
import { Zappnix } from '@zappnix/sdk';
const zap = new Zappnix({ apiKey: process.env.ZAPPNIX_KEY! });
// Health check
await zap.ping();
// → { ok: true, workspace: '...', scopes: [...] }
// Enviar texto
await zap.instance('main').messages.text({
to: '5531987654321',
text: 'Olá! 🚀',
});
// Botões — tipo reply (resposta rápida)
await zap.instance('main').messages.buttons({
to: '5531987654321',
body: 'Quer continuar?',
buttons: [
{ text: 'Sim', type: 'reply' },
{ text: 'Não', type: 'reply' },
],
});
// Botões CTA — url, call e copy (não misturar com reply)
await zap.instance('main').messages.buttons({
to: '5531987654321',
body: '🎉 Oferta exclusiva — use o cupom no checkout:',
buttons: [
{ text: 'Copiar cupom', type: 'copy', value: 'PROMO50' },
{ text: 'Ver oferta', type: 'url', value: 'https://exemplo.com/oferta' },
{ text: 'Falar com vendas', type: 'call', value: '5511999999999' },
],
});Tipos de botão
| type | value | Comportamento |
|---------|--------------------------|--------------------------------------------------------------|
| reply | (não usado) | Resposta rápida — callback via webhook/waitForClick |
| url | URL (https://…) | Abre link no navegador do contato |
| call | Telefone E.164 (dígitos) | Inicia ligação telefônica |
| copy | Código a copiar | Copia pro clipboard — cupom, voucher, PIX, código de barras |
Restrição WhatsApp: botões
replyNÃO podem ser combinados com tipos CTA (url,call,copy) na mesma mensagem — o WhatsApp Web não renderiza. Use tudoreplyOU tudo CTA.
Disparar fluxos completos (killer feature)
const run = await zap.instance('main').flows.start('tpl_onboarding', {
to: '5531987654321',
variables: {
nome: 'João',
produto: 'Curso de Marketing',
valor: '297',
},
});
console.log(run.status); // 'completed' | 'waiting'
console.log(run.runId); // null | 'flowrun_...'
// Polling status (se waiting)
if (run.status === 'waiting' && run.runId) {
const status = await zap.flows.run(run.runId);
console.log(status.status); // 'waiting' | 'resumed' | 'completed' | ...
}Webhooks com signature
import crypto from 'crypto';
// Criar webhook
const wh = await zap.webhooks.create({
name: 'CRM sync',
url: 'https://meu-app.com/webhook/zapnix',
events: ['message.received', 'flow.completed'],
});
console.log(wh.secret); // SAVE — só aparece uma vez!
// No seu servidor, verificar signature:
function verify(req, secret) {
const sig = req.headers['x-signature'];
const [tsPart, v1Part] = sig.split(',');
const ts = tsPart.split('=')[1];
const v1 = v1Part.split('=')[1];
const expected = crypto
.createHmac('sha256', secret)
.update(`${ts}.${JSON.stringify(req.body)}`)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(v1, 'hex'),
Buffer.from(expected, 'hex')
);
}Anti-ban automático
Toda mensagem aceita options para humanização:
await zap.instance('main').messages.text({
to: '5531987654321',
text: 'Olá!',
options: {
delay: { min: 2, max: 5 }, // espera 2-5s antes (jitter)
typing: { seconds: 3 }, // mostra "digitando..." 3s
useCipher: false, // cifra cirílica anti-filtro
},
});Erros tipados
import { ZappnixApiError } from '@zappnix/sdk';
try {
await zap.instance('main').messages.text({ to: '...', text: '...' });
} catch (err) {
if (err instanceof ZappnixApiError) {
console.log(err.code); // 'instance_not_connected' | 'invalid_phone' | ...
console.log(err.status); // 400 | 404 | 503 | ...
console.log(err.details); // { instance: '...', status: 'disconnected' }
}
}Gerenciar instâncias
// Criar instância nova (com aquecimento anti-ban)
const inst = await zap.instances.create({
name: 'venda-01',
warmupOnConnect: true, // recomendado pra números novos
});
console.log(inst.nextStep); // dica do próximo passo
// Disparar conexão (gera QR)
await zap.instances.connect('venda-01');
// Pegar QR atual (polling)
const qr = await zap.instances.qr('venda-01');
console.log(qr.qrCode); // data:image/png;base64,...
console.log(qr.pairingCode); // 'A1B2-C3D4' (se pareou por número)
// Estado de aquecimento (anti-ban) — qualquer instância
const i = await zap.instances.get('venda-01');
console.log(i.warmupPhase); // 'quarantine' | 'active' | null
console.log(i.warmupPhaseStartedAt); // pra calcular tempo restante
console.log(i.warmupCompletedAt); // null se nunca aqueceu
// Pular aquecimento (libera pra campanha já)
await zap.instances.skipWarmup('venda-01');
// Resetar ciclo de aquecimento
await zap.instances.resetWarmup('venda-01');
// Restart de socket (mantém pairing)
await zap.instances.restart('venda-01');
// Apagar (irreversível — logout WA + remove do DB)
await zap.instances.delete('venda-01');Configurar proxy / atualizar instância
// 1) Criar um proxy no workspace
const proxy = await zap.proxies.create({
name: 'Proxy 4G - SP',
host: 'host.axtron.io',
port: 824,
type: 'socks5',
username: 'usr_abc',
password: 'secret123',
isPool: false, // true = entra no pool de rotação automática
});
// 2) Atribuir proxy fixo a uma instância (toma efeito na PRÓXIMA conexão)
await zap.instances.update('venda-01', { proxyId: proxy.id });
// Ou: ativar rotação automática do pool
await zap.instances.update('venda-01', { proxyRotation: true });
// 3) Outras configs em uma só chamada
await zap.instances.update('venda-01', {
isProtected: true, // exclui de disparos automáticos
warmupOnConnect: true, // aquece próximo reconnect
displayOrder: 5,
});
// Forçar troca imediata de proxy (não espera reconexão natural)
await zap.instances.restart('venda-01');
// Listar / atualizar / remover proxies
const { proxies } = await zap.proxies.list();
await zap.proxies.update(proxy.id, { isPool: true });
await zap.proxies.remove(proxy.id); // affectedInstances no responseSenhas de proxy são write-only: a API nunca retorna
password. CadaProxyda listagem trazhasPassword: booleanpra UI mostrar "***". Pra trocar senha, envie um novo valor emupdate(). Pra remover auth, envieusername: null, password: null.
Debug de webhooks
// Ver últimas 50 entregas — pra investigar "por que não chamou meu endpoint?"
const { deliveries } = await zap.webhooks.deliveries(wh.id);
for (const d of deliveries) {
console.log(d.event, d.status, d.responseStatus, d.errorReason);
}
// Testar endpoint manualmente
const test = await zap.webhooks.test(wh.id);
console.log(test.ok, test.status); // true, 200API completa
Workspace-level:
zap.ping()— health check + scopeszap.instances.{list|get|create|delete|connect|qr|restart|skipWarmup|resetWarmup|update}()zap.flows.{list|get|run|cancelRun}()zap.contacts.{get|setAttributes}()zap.webhooks.{list|create|update|remove|test|deliveries}()zap.proxies.{list|get|create|update|remove}()— CRUD de proxies (atribua viainstances.update)zap.profiles.{list|get|create|update|remove}()— CRUD de WhatsApp business profiles
Criar instância já com perfil + proxy
// 1) Cria profile
const profile = await zap.profiles.create({
name: 'Loja XYZ',
displayName: 'Loja XYZ Oficial',
about: 'Atendimento 8h às 18h',
description: 'Roupas masculinas premium.',
email: '[email protected]',
website: 'https://xyz.com',
})
// 2) Cria proxy
const proxy = await zap.proxies.create({
name: 'Proxy SP', host: 'host.axtron.io', port: 824, type: 'socks5',
username: 'u', password: 'p', isPool: false,
})
// 3) Cria instância JÁ com profile + proxy + warmup configurados
await zap.instances.create({
name: 'venda-01',
warmupOnConnect: true,
profileId: profile.id,
proxyId: proxy.id,
})
// 4) Conecta (gera QR)
await zap.instances.connect('venda-01')Instance-scoped (zap.instance(name).*):
messages.{text|media|audio|buttons|list|location|typing|read|reaction}()flows.start(templateId, { to, variables })contacts.check(phone)groups.{list|get(jid)}()
Documentação completa: https://api.zapnixhub.com/v1/docs
License
MIT
