Pular para o conteúdo principal

SDK Node.js

📦 TypeScript-first: SDK oficial com tipos completos, retry automático e paginação lazy

O SDK Node.js é a forma mais rápida de integrar a Notifica em aplicações JavaScript/TypeScript. Este guia cobre:

  • Instalação e setup
  • Envio de notificações (email, SMS, WhatsApp, in-app, push)
  • Gerenciamento de subscribers, templates e workflows
  • Webhooks e analytics
  • Tratamento de erros

Instalação

npm install @notifica/node

Ou com yarn/pnpm:

yarn add @notifica/node
# ou
pnpm add @notifica/node

Requisitos: Node.js 18+ · TypeScript 5+ (opcional, tipos incluídos)

Zero dependências externas. Tree-shakeable.


Setup básico

import { Notifica } from '@notifica/node';

const notifica = new Notifica('nk_live_sua_chave');

const notification = await notifica.notifications.send({
channel: 'email',
recipient: '[email protected]',
templateId: 'welcome',
payload: { name: 'Fernanda' },
});

console.log('Enviada:', notification.id, notification.status);

Autenticação

// Chave de produção
const notifica = new Notifica('nk_live_sua_chave');

// Chave de sandbox (desenvolvimento)
const notifica = new Notifica('nk_test_sua_chave');
dica

Use variáveis de ambiente para não commitar chaves no código:

const notifica = new Notifica(process.env.NOTIFICA_API_KEY!);

Configuração avançada

const notifica = new Notifica('nk_live_...', {
// URL customizada (self-hosted ou staging)
baseUrl: 'https://api.staging.notifica.com.br',

// Timeout em milissegundos
timeout: 60_000,

// Retry com backoff exponencial (padrão: 3 tentativas)
maxRetries: 5,
});
OpçãoPadrãoDescrição
baseUrlhttps://api.notifica.com.brURL base da API
timeout30000Timeout em ms
maxRetries3Tentativas com backoff exponencial

Enviando notificações

Todas as notificações são assíncronas e retornam status accepted (202).

Email

const n = await notifica.notifications.send({
channel: 'email',
recipient: '[email protected]',
templateId: 'order-confirmation',
payload: {
name: 'Roberto',
orderId: 'ORD-12345',
},
});

WhatsApp

const n = await notifica.notifications.send({
channel: 'whatsapp',
recipient: '+5511998765432',
templateId: 'welcome',
payload: {
customerName: 'João',
company: 'Acme',
},
});

SMS

const n = await notifica.notifications.send({
channel: 'sms',
recipient: '+5511998765432',
payload: {
content: 'Seu código de verificação é: 583921',
},
});

In-App

const n = await notifica.notifications.send({
channel: 'in_app',
recipient: 'subscriber-id-aqui',
payload: {
title: 'Novo comentário',
body: 'Maria comentou na sua tarefa #123',
},
});

Com chave de idempotência

Para evitar duplicatas em retries:

const n = await notifica.notifications.send({
channel: 'email',
recipient: '[email protected]',
templateId: 'payment-receipt',
payload: { amount: 'R$ 99,90' },
idempotencyKey: 'payment-12345', // Use ID do seu sistema
});

Tracking de entrega

Ver status de uma notificação

const n = await notifica.notifications.get('notification-id');
console.log(n.status); // "delivered"
console.log(n.deliveredAt); // 2024-01-15T14:30:05Z

Listar tentativas de entrega

const attempts = await notifica.notifications.listAttempts('notification-id');
for (const a of attempts) {
console.log(`Tentativa ${a.attemptNumber}: ${a.status} (${a.provider})`);
}

Listar notificações com filtros

const page = await notifica.notifications.list({
status: 'failed',
channel: 'email',
limit: 50,
});

for (const n of page.data) {
console.log(n.id, n.status);
}

// Paginação via cursor
if (page.meta.hasMore) {
const nextPage = await notifica.notifications.list({
cursor: page.meta.cursor,
});
}

Subscribers (Assinantes)

Criar ou atualizar (upsert)

const sub = await notifica.subscribers.create({
externalId: 'user-123',
email: '[email protected]',
phone: '+5511999999999',
name: 'Maria Silva',
customProperties: {
plan: 'pro',
company: 'Acme',
},
});

Se o externalId já existir, o subscriber é atualizado automaticamente.

Listar com busca

const page = await notifica.subscribers.list({
search: 'maria',
limit: 20,
});
console.log(`Encontrados: ${page.total} subscribers`);

Atualizar

const sub = await notifica.subscribers.update('subscriber-id', {
name: 'Maria Santos',
});

Deletar (LGPD)

Soft delete com nullificação de PII:

await notifica.subscribers.delete('subscriber-id');

Preferências de notificação

// Consultar
const prefs = await notifica.subscribers.getPreferences('subscriber-id');

// Atualizar
await notifica.subscribers.setPreferences('subscriber-id', {
preferences: [
{ category: 'marketing', channel: 'email', enabled: false },
{ category: 'transacional', channel: 'email', enabled: true },
],
});

Importação em massa

const result = await notifica.subscribers.bulkImport({
subscribers: [
{ externalId: 'user-1', email: '[email protected]', name: 'Ana' },
{ externalId: 'user-2', email: '[email protected]', name: 'Bruno' },
],
});
console.log(`Importados: ${result.imported} subscribers`);

Templates

Criar template

const tmpl = await notifica.templates.create({
channel: 'email',
slug: 'welcome',
name: 'Email de Boas-vindas',
content: 'Olá {{name}}, bem-vindo ao {{company}}!',
status: 'published',
});

Listar por canal

const templates = await notifica.templates.list({
channel: 'email',
status: 'published',
});

Preview com dados de exemplo

const result = await notifica.templates.preview('template-id', {
variables: { name: 'Maria', company: 'Acme' },
});
console.log(result.output); // "Olá Maria, bem-vindo ao Acme!"
console.log(result.valid); // true

Validar template

const result = await notifica.templates.validate('template-id');
if (!result.valid) {
console.log('Erros:', result.errors);
}

Workflows

Criar workflow

const wf = await notifica.workflows.create({
slug: 'onboarding',
name: 'Onboarding do Usuário',
steps: [
{ type: 'send', channel: 'email', template: 'welcome' },
{ type: 'delay', duration: '24h' },
{ type: 'send', channel: 'email', template: 'getting-started' },
{ type: 'delay', duration: '72h' },
{ type: 'send', channel: 'whatsapp', template: 'check-in' },
],
});

Disparar workflow

const run = await notifica.workflows.trigger('onboarding', {
recipient: 'user-123',
data: { name: 'João', plan: 'pro' },
});
console.log('Workflow run:', run.id, run.status);

Acompanhar execução

const run = await notifica.workflows.getRun('run-id');
console.log('Status:', run.status);

Cancelar workflow em execução

const run = await notifica.workflows.cancelRun('run-id');

Webhooks

Criar webhook

O signing secret só é retornado na criação — guarde-o!

const wh = await notifica.webhooks.create({
url: 'https://api.empresa.com/webhooks/notifica',
events: ['notification.sent', 'notification.delivered', 'notification.failed'],
});
console.log('Secret (guarde!):', wh.secret);

Listar deliveries

const page = await notifica.webhooks.listDeliveries('webhook-id', { limit: 50 });
for (const d of page.data) {
console.log(`Evento: ${d.eventType}, Status HTTP: ${d.responseStatus}`);
}

Testar webhook

await notifica.webhooks.test('webhook-id');

Domínios de envio

Registrar e verificar domínio

// Registrar
const domain = await notifica.domains.create({ domain: 'mail.empresa.com.br' });
console.log('Configure os registros DNS e depois verifique');

// Verificar DNS
const verified = await notifica.domains.verify(domain.id);
if (verified.status === 'verified') {
console.log('Domínio verificado!');
}

// Health check
const health = await notifica.domains.checkHealth(domain.id);
console.log('SPF:', health.spf.status);
console.log('DKIM:', health.dkim.status);
console.log('DMARC:', health.dmarc.status);

Analytics

// Resumo dos últimos 7 dias
const overview = await notifica.analytics.overview('7d');
console.log(`Enviados: ${overview.sent}, Entregues: ${overview.delivered}`);

// Estatísticas por canal
const stats = await notifica.analytics.byChannel('30d');
for (const s of stats) {
console.log(`${s.channel}: ${s.sent} enviados`);
}

// Timeseries para gráficos
const points = await notifica.analytics.timeseries({
period: '7d',
granularity: 'day',
});

// Top templates
const top = await notifica.analytics.topTemplates({ period: '30d', limit: 5 });

Notificações In-App

// Listar não-lidas
const notifications = await notifica.inApp.list('subscriber-id', {
unreadOnly: true,
limit: 20,
});

// Contagem de não-lidas
const count = await notifica.inApp.getUnreadCount('subscriber-id');
console.log(`${count} notificações não lidas`);

// Marcar como lida
await notifica.inApp.markRead('subscriber-id', 'notification-id');

// Marcar todas como lidas
await notifica.inApp.markAllRead('subscriber-id');

Audit Logs (Admin Only)

Admin Authentication Required

Audit logs require admin authentication (Bearer token from backoffice login). They are not available with regular API keys (nk_live_... or nk_test_...).

Track security-sensitive actions in your organization:

  • API Keys: created, rotated, revoked
  • Team Members: invited, removed, role_changed
  • Subscriptions: created, plan_changed, cancelled, payment_failed
  • Domains: added, verified, removed
  • Webhooks: created, updated, deleted
// List recent audit logs
const { data: logs, meta } = await notifica.audit.list({ limit: 50 });

for (const log of logs) {
console.log(`${log.action} by ${log.actor.name} at ${log.created_at}`);
}

// Filter by action type
const apiKeyLogs = await notifica.audit.list({
action: 'api_key.created',
limit: 20,
});

// Filter by resource type
const webhookLogs = await notifica.audit.list({
resource_type: 'webhook',
});

// Filter by date range
const logs = await notifica.audit.list({
start_date: '2024-01-01T00:00:00Z',
end_date: '2024-01-31T23:59:59Z',
});

// Get a specific audit log
const log = await notifica.audit.get('audit_abc123');

// Auto-paginate through all logs
for await (const log of notifica.audit.paginate({ resource_type: 'api_key' })) {
console.log(log.action, log.resource_id);
}

TypeScript Types

import type {
AuditLog,
AuditLogAction,
AuditResourceType,
AuditActorType,
AuditActor,
ListAuditLogsParams,
} from '@notifica/node';

// Actions: 'api_key.created' | 'api_key.rotated' | 'api_key.revoked' | ...
// Resource types: 'api_key' | 'team_member' | 'subscription' | 'domain' | 'webhook'
// Actor types: 'user' | 'api_key' | 'system'

Tratamento de erros

import { NotificaError } from '@notifica/node';

try {
await notifica.notifications.send(params);
} catch (err) {
if (err instanceof NotificaError) {
console.log(`HTTP ${err.statusCode} | ${err.code}: ${err.message}`);

if (err.statusCode === 422) {
// Dados inválidos
console.log('Campos inválidos:', err.details);
}
if (err.statusCode === 429) {
// Rate limited — o SDK faz retry automático por padrão
console.log('Rate limited');
}
if (err.statusCode === 404) {
// Recurso não encontrado
}
if (err.statusCode === 409) {
// Conflito de idempotência
}
}
}
informação

O SDK faz retry automático com backoff exponencial para erros 429 e 5xx. Configure maxRetries: 0 para desabilitar.


Exemplo completo: Express.js

import express from 'express';
import { Notifica } from '@notifica/node';

const app = express();
app.use(express.json());

const notifica = new Notifica(process.env.NOTIFICA_API_KEY!);

app.post('/send-welcome', async (req, res) => {
const { email, name } = req.body;

try {
const n = await notifica.notifications.send({
channel: 'email',
recipient: email,
templateId: 'welcome',
payload: { name },
});

res.json({ notificationId: n.id, status: n.status });
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
});

app.listen(3000, () => console.log('Servidor rodando em :3000'));

FAQ

Q: Preciso usar TypeScript? A: Não. O SDK funciona com JavaScript puro, mas inclui tipos TypeScript para autocomplete e validação.

Q: Como funciona o retry automático? A: O SDK retenta automaticamente em erros 429 (rate limit) e 5xx (servidor) com backoff exponencial: 1s, 2s, 4s...

Q: Funciona no Deno/Bun? A: Sim, em qualquer runtime com suporte a fetch nativo.

Q: Como usar com ESM e CommonJS? A: O SDK suporta ambos:

// ESM
import { Notifica } from '@notifica/node';

// CommonJS
const { Notifica } = require('@notifica/node');

Q: O SDK é tree-shakeable? A: Sim. Bundlers como esbuild e webpack eliminam código não utilizado.