Skip to content

Official Node.js SDK for Notifica — notification infrastructure for Brazil

License

Notifications You must be signed in to change notification settings

notifica-tech/notifica-node

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@notifica/node

SDK oficial do Notifica para Node.js

Infraestrutura de notificações para o Brasil 🇧🇷

CI npm license downloads


WhatsApp, Email, SMS, Push e In-App em uma API unificada. Zero dependências. TypeScript nativo.

Instalação

npm install @notifica/node

Requer Node.js 18+ (usa fetch nativo).

Início Rápido

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

const notifica = new Notifica('nk_live_...');

// Enviar uma notificação via WhatsApp
const notification = await notifica.notifications.send({
  channel: 'whatsapp',
  to: '+5511999999999',
  template: 'welcome',
  data: { name: 'João' },
});

console.log(notification.id);     // 'notif-uuid'
console.log(notification.status); // 'pending'

Configuração

// Simples — apenas API key
const notifica = new Notifica('nk_live_...');

// Configuração completa
const notifica = new Notifica({
  apiKey: 'nk_live_...',
  baseUrl: 'https://app.usenotifica.com.br/v1', // padrão
  timeout: 15000,        // 15s (padrão: 30s)
  maxRetries: 5,         // padrão: 3
  autoIdempotency: true, // padrão: true
});
Opção Tipo Padrão Descrição
apiKey string Obrigatório. Sua API key (nk_live_... ou nk_test_...)
baseUrl string https://app.usenotifica.com.br/v1 URL base da API
timeout number 30000 Timeout em ms
maxRetries number 3 Retentativas automáticas em 429/5xx
autoIdempotency boolean true Gerar chave de idempotência automática para POSTs

Recursos

Notifications — Envio e consulta

// Enviar notificação
const notification = await notifica.notifications.send({
  channel: 'whatsapp',  // 'email' | 'whatsapp' | 'sms' | 'in_app' | 'push'
  to: '+5511999999999',
  template: 'welcome',
  data: { name: 'João' },
  metadata: { source: 'signup-flow' },
});

// Listar (com paginação manual)
const { data, meta } = await notifica.notifications.list({
  channel: 'email',
  status: 'delivered',
  limit: 50,
});
const page2 = await notifica.notifications.list({ cursor: meta.cursor });

// Auto-paginação com async iterator
for await (const n of notifica.notifications.listAll({ channel: 'email' })) {
  console.log(n.id, n.status);
}

// Detalhes + tentativas de entrega
const detail = await notifica.notifications.get('notif-uuid');
const attempts = await notifica.notifications.listAttempts('notif-uuid');

Templates — Gerenciamento

// Criar
const template = await notifica.templates.create({
  channel: 'email',
  slug: 'welcome-email',
  name: 'Email de Boas-Vindas',
  content: 'Olá {{name}}, bem-vindo ao {{company}}!',
  variants: {
    subject: 'Bem-vindo, {{name}}!',
    html_body: '<h1>Olá {{name}}</h1><p>Bem-vindo ao {{company}}!</p>',
  },
  status: 'active',
});

// Listar / obter / atualizar / deletar
const { data } = await notifica.templates.list({ channel: 'email' });
await notifica.templates.update('tpl-uuid', { status: 'active' });
await notifica.templates.delete('tpl-uuid');

// Preview com variáveis
const preview = await notifica.templates.preview('tpl-uuid', {
  variables: { name: 'João', company: 'Empresa Ltda' },
});
console.log(preview.rendered.subject); // "Bem-vindo, João!"

// Preview de conteúdo arbitrário (para editor em tempo real)
const livePreview = await notifica.templates.previewContent({
  content: 'Oi {{name}}!',
  channel: 'email',
  variables: { name: 'Maria' },
});

// Validar template
const validation = await notifica.templates.validate('tpl-uuid');
console.log(validation.valid, validation.warnings);

Workflows — Orquestração

// Criar workflow
const workflow = await notifica.workflows.create({
  slug: 'welcome-flow',
  name: 'Fluxo de Boas-Vindas',
  steps: [
    { type: 'send', channel: 'email', template: 'welcome-email' },
    { type: 'delay', duration: '1h' },
    { type: 'send', channel: 'whatsapp', template: 'welcome-whatsapp' },
  ],
});

// Disparar workflow
const run = await notifica.workflows.trigger('welcome-flow', {
  recipient: '+5511999999999',
  data: { name: 'João', plan: 'pro' },
});

// Gerenciar execuções
const { data: runs } = await notifica.workflows.listRuns({ status: 'running' });
const runDetail = await notifica.workflows.getRun('run-uuid');
await notifica.workflows.cancelRun('run-uuid');

Tipos de step:

Tipo Campos Descrição
send channel, template Envia notificação pelo canal
delay duration (5m, 1h, 1d) Pausa a execução
fallback channels[], template Tenta canais em ordem até sucesso

Subscribers — Gerenciamento de destinatários

// Criar/atualizar (upsert por external_id)
const subscriber = await notifica.subscribers.create({
  external_id: 'user-123',
  email: 'joao@empresa.com.br',
  phone: '+5511999998888',
  name: 'João Silva',
  locale: 'pt_BR',
  timezone: 'America/Sao_Paulo',
  custom_properties: { plan: 'pro' },
});

// Listar (com busca)
const { data } = await notifica.subscribers.list({ search: 'joao' });

// Atualizar / deletar (LGPD — nullifica PII, irreversível!)
await notifica.subscribers.update('sub-uuid', { name: 'João S.' });
await notifica.subscribers.delete('sub-uuid');

// Preferências de notificação
const prefs = await notifica.subscribers.getPreferences('sub-uuid');
await notifica.subscribers.updatePreferences('sub-uuid', {
  preferences: [
    { category: 'marketing', channel: 'email', enabled: false },
    { category: 'transactional', channel: 'whatsapp', enabled: true },
  ],
});

// Import em lote (transacional — tudo ou nada)
const result = await notifica.subscribers.bulkImport({
  subscribers: [
    { external_id: 'user-1', email: 'a@empresa.com.br', name: 'Ana' },
    { external_id: 'user-2', email: 'b@empresa.com.br', name: 'Bruno' },
  ],
});

Notificações In-App:

const { data } = await notifica.subscribers.listNotifications('sub-uuid', { unread_only: true });
await notifica.subscribers.markRead('sub-uuid', 'notif-uuid');
await notifica.subscribers.markAllRead('sub-uuid');
const count = await notifica.subscribers.getUnreadCount('sub-uuid');

Channels — Configuração de canais

const channel = await notifica.channels.create({
  channel: 'email',
  provider: 'aws_ses',
  credentials: { access_key_id: 'AKIA...', secret_access_key: '...', region: 'us-east-1' },
  settings: { from_address: 'noreply@empresa.com.br', from_name: 'Empresa' },
});

const channels = await notifica.channels.list();
const test = await notifica.channels.test('email');

Domains — Domínios de envio

// Registrar domínio e configurar DNS
const domain = await notifica.domains.create({ domain: 'suaempresa.com.br' });
// → Configure os registros em domain.dns_records no seu provedor DNS

const verified = await notifica.domains.verify(domain.id);
const health = await notifica.domains.getHealth(domain.id);
const alerts = await notifica.domains.listAlerts();

Webhooks — Eventos outbound

const webhook = await notifica.webhooks.create({
  url: 'https://meuapp.com.br/webhooks/notifica',
  events: ['notification.delivered', 'notification.failed'],
});
// ⚠️ Salve webhook.signing_secret — mostrado apenas na criação!

await notifica.webhooks.test(webhook.id);
const deliveries = await notifica.webhooks.listDeliveries(webhook.id);

Verificação de assinatura:

app.post('/webhooks/notifica', async (req, res) => {
  const payload = req.body;       // raw body string
  const signature = req.headers['x-notifica-signature'];
  const secret = process.env.WEBHOOK_SECRET!;

  const valid = await notifica.webhooks.verify(payload, signature, secret);
  if (!valid) return res.status(401).send('Assinatura inválida');

  // Processar evento...
  res.status(200).send('OK');
});

// Ou a versão que lança erro automaticamente:
await notifica.webhooks.verifyOrThrow(payload, signature, secret);

API Keys — Gerenciamento de chaves

const key = await notifica.apiKeys.create({
  key_type: 'secret',
  label: 'Backend Production',
  environment: 'production',
});
// ⚠️ Salve key.raw_key — mostrado apenas na criação!

const keys = await notifica.apiKeys.list();
await notifica.apiKeys.revoke('key-uuid');

Analytics — Métricas

const overview = await notifica.analytics.overview({ period: '7d' });
const channels = await notifica.analytics.byChannel({ period: '24h' });
const timeseries = await notifica.analytics.timeseries({ period: '7d', granularity: 'day' });
const top = await notifica.analytics.topTemplates({ period: '30d', limit: 5 });

Tratamento de Erros

O SDK lança erros tipados para cada cenário:

import {
  NotificaError,    // Erro base
  ApiError,         // Qualquer erro da API (4xx, 5xx)
  ValidationError,  // 422 — dados inválidos
  RateLimitError,   // 429 — rate limit excedido
  TimeoutError,     // Timeout de conexão
} from '@notifica/node';

try {
  await notifica.notifications.send({ channel: 'email', to: 'x' });
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.status);     // 422
    console.log(error.message);    // "Email inválido"
    console.log(error.details);    // { email: ["is invalid"] }
    console.log(error.requestId);  // "req-abc-123" (para suporte)
  }
  if (error instanceof RateLimitError) {
    console.log(error.retryAfter); // 30 (segundos)
  }
  if (error instanceof ApiError) {
    console.log(error.status, error.code);
  }
}

Idempotência

O SDK gera automaticamente chaves de idempotência para todas as requests POST, prevenindo operações duplicadas em caso de retry de rede.

// Automático (padrão)
await notifica.notifications.send({ channel: 'email', to: 'a@b.com' });

// Chave customizada (útil para deduplicação por lógica de negócio)
await notifica.notifications.send(
  { channel: 'email', to: 'a@b.com' },
  { idempotencyKey: 'signup-user-123' },
);

Retries Automáticos

Retenta automaticamente em falhas transientes:

  • 429 Too Many Requests — respeita header Retry-After
  • 5xx Server errors — backoff exponencial com jitter
const notifica = new Notifica({
  apiKey: 'nk_live_...',
  maxRetries: 5, // padrão: 3
});

Paginação

// 1. Manual (cursor-based)
let cursor: string | undefined;
do {
  const page = await notifica.notifications.list({ cursor, limit: 100 });
  for (const n of page.data) { console.log(n.id); }
  cursor = page.meta.has_more ? page.meta.cursor ?? undefined : undefined;
} while (cursor);

// 2. Auto-paginação (async iterator)
for await (const n of notifica.notifications.listAll()) {
  console.log(n.id);
}

Tipos TypeScript

Todos os tipos são exportados:

import type {
  Notification,
  SendNotificationParams,
  Template,
  Workflow,
  WorkflowStep,
  Subscriber,
  Channel,
  NotificationStatus,
  PaginatedResponse,
} from '@notifica/node';

Desenvolvimento

# Instalar dependências
npm install

# Type check
npm run typecheck

# Rodar testes (requer Node 22+)
npm test

# Build
npm run build

Contribuindo

Contribuições são bem-vindas! Por favor:

  1. Faça fork do repositório
  2. Crie sua branch (git checkout -b feature/minha-feature)
  3. Commit suas mudanças (git commit -m 'feat: minha feature')
  4. Push para a branch (git push origin feature/minha-feature)
  5. Abra um Pull Request

Requisitos

  • Node.js 18+ (usa fetch nativo e crypto.subtle)
  • Zero dependências externas

Links

Licença

MIT © Notifica

About

Official Node.js SDK for Notifica — notification infrastructure for Brazil

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published