Get started

How it works

A 2-minute mental model of the platform. Read this once and the rest of the docs make sense.

The loop

Every message Nudgel sends follows the same loop, whether you kicked it off from a curl call or from the dashboard:

  1. You hit POST /v1/messages with a channel, recipient, template, and variables.
  2. The API authenticates the request (API key or sign-in session), validates payload, persists a row in messages, and enqueues a job in BullMQ.
  3. A worker picks it up, asks the CredentialResolver for the right provider client (per your routing rules), and calls the provider.
  4. Provider responds. Worker writes sent to the message row. Webhooks from the provider later mark it delivered, bounced, etc.
  5. You see the timeline in the dashboard, get notified via your own webhook, and the audit log records who triggered it.

HONEST STATUS

Steps 1 and 2 above are wired today. Step 3 (worker → provider call) ships in Live now along with the actual /v1/messages endpoint.

Tenants

A tenant is the unit of isolation. Everything in Nudgel belongs to a tenant: contacts, templates, providers, API keys, audit log, delivery history. Per-tenant Postgres row-level security plus an application-layer guard means one tenant can't see another's data, period.

Most teams use a single tenant. Some run separate tenants per brand (one for the consumer app, one for the operations dashboard) or per environment (production vs staging vs dev). You can create unlimited tenants on every plan.

Channels

Four channels, all hit through the same messages.send call — you change the channel field, the rest stays roughly the same:

ChannelWhat it sendsLive now providers
smsText up to 1600 chars (segmented)AT, Twilio, Daraja
emailHTML + plain textPostmark, Resend, SES
pushApp push notificationsFCM, APNS
whatsappTemplates + session messagesMeta WABA (beta)

Providers and routing

You bring your own provider keys. We don't mark up sends — your Africa's Talking bill comes straight from AT, your Twilio bill from Twilio. Connect each provider once, then define routing rules:

yamlexample routing — Live now
channel: sms
rules:
  - priority: 50
    match: { country: KE, segment: txn }
    primary: at-ke-shortcode
    fallback: [at-ke-bulk, twilio-global]
  - priority: 100
    match: { country: KE }
    primary: at-ke-bulk
  - priority: 100
    match: { country: NG }
    primary: twilio-ng
  - priority: 900
    match: { }              # any
    primary: twilio-global

Rules evaluate top-down. First match wins. If the primary fails transiently, we retry the fallbacks in order. Permanent failures (bad number, suppressed) terminate as expected.

Templates

A template is a named, versioned message body with variable substitution. SMS uses plain text; email uses MJML; WhatsApp uses Meta-approved template format; push uses a JSON payload schema.

Variables are {{like.this}} in Liquid. Templates can render in different languages — pass locale: "sw"in the send call, we pick the Swahili variant if you've uploaded one. Every template is versioned; you can roll back to any prior version.

Isolation and encryption

Three layers protect your data:

  1. App layer — every repository method takes tenantId as a required first argument. A custom ESLint rule blocks DB queries that don't scope by tenant.
  2. DB layer — Postgres row-level security on every tenant table. The session sets SET LOCAL app.tenant_id; policies match against it. Forgot to scope? You get zero rows.
  3. KMS — provider credentials are encrypted with a per-tenant master key (which is itself encrypted with a root key on the host). The CredentialResolver service is the only code path allowed to decrypt — enforced by ESLint.

Who runs what

ConcernOwner
Sign-in / OTP / Google OAuthour auth service
Tenant + membership + API keysNudgel
Provider credential storageNudgel (envelope encrypted)
Sending (queue, worker, provider call)Nudgel workers
Provider rates + invoicingYour provider directly
Hosted dashboardNudgel (Next.js)

Auth is delegated to our auth service so the human-side identity stays the same across every AutoTribes product (Nudgel, TribeFest and InstaEscrow, etc.). Tenancy and sending are Nudgel's exclusive domain.