// docs

Documentation

Everything you need to send notifications via the Notify Router API.

Getting Started

Notify Router turns a single API call into delivery across one or more platforms. You own Platforms (Telegram, Slack, Email, SMS, WhatsApp, Webhook), group them into Channels with a per-link priority, and authenticate every send with an API Key. Routing is decided at send time by two fields: channel_ids (which channels to hit) and mode (broadcast or route).

The API Key only authenticates the caller — it does not own platforms or carry routing config. Before you can send, you need an account with an active package, at least one active Platform, and a Channel that links to it.

Step 1 — Connect a Platform

A Platform is one delivery destination (a Telegram bot, a Slack webhook, an email sender, and so on). Credentials are stored encrypted at rest.

  1. Open the Platforms page in your dashboard.
  2. Add a connection and pick its type (Telegram, Slack, Email, SMS, WhatsApp, or Webhook).
  3. Enter its credentials (bot token, webhook URL, SMTP settings, …).
  4. Make sure the connection is marked Active — inactive platforms are skipped.

Step 2 — Create a Channel & attach Platforms

A Channel is a routing group. You attach one or more Platforms to a Channel, and each link carries a priority used by route-mode failover (lower priority number = tried first).

  1. Open the Channels page and create a channel (e.g. “Alerts”).
  2. Attach one or more platforms to it.
  3. Set each platform link’s priority for route-mode fallback.
  4. Copy the channel’s ID — you pass it as channel_ids when sending.

Step 3 — Create an API Key

The API Key is the credential your client sends in the x-api-key header. Treat it like a password.

  1. Open the API Keys page and create a key.
  2. Copy the key value immediately — it is shown only once.
  3. Optional: set Default Channels on the key so sends can omit channel_ids entirely.
  4. Keep the key on your server / backend; never expose it in public client-side code.

Step 4 — Send your first notification

Make a POST request to https://notifyroute.com/api/v1/ingest with your key in the x-api-key header and a JSON body.

curl
curl -X POST https://notifyroute.com/api/v1/ingest \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "channel_ids": ["YOUR_CHANNEL_ID"],
    "mode": "broadcast",
    "payload": { "title": "Hello", "body": "First notification" }
  }'
JavaScript (fetch)
const res = await fetch("https://notifyroute.com/api/v1/ingest", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": "YOUR_API_KEY",
  },
  body: JSON.stringify({
    channel_ids: ["YOUR_CHANNEL_ID"],
    mode: "broadcast",
    payload: { title: "Hello", body: "First notification" },
  }),
});
const data = await res.json(); // { data: { message_id } }

A successful call returns 202 Accepted with a message_id; delivery then happens asynchronously. You can watch the result on the Messages page or via GET /api/v1/ingest/logs.

Easy path: if you set Default Channels on the API key, you can omit channel_ids and just send a payload.

Body with default channels
// With default channels set on the API key, omit channel_ids:
{
  "mode": "broadcast",
  "payload": { "title": "Hello", "body": "World" }
}

API Reference

POST /api/v1/ingest — enqueue a notification. Header: x-api-key (required). Body fields:

FieldTypeRequiredNotes
channel_idsstring[] (UUID)Yes**Optional if the API key has Default Channels set.
modestringNo'broadcast' (default) or 'route'. route allows at most 1 channel.
payload.titlestringNoNotification title.
payload.bodystringNoNotification body. Provide title/body, or variables, or template_id.
template_idstring (UUID)NoUse a saved template (optional override).
variablesobjectNoKey/value map injected into the template.
recipient.emailstringNoRequired for Email platforms.
recipient.phonestringNoRequired for SMS platforms.
Success response
HTTP/1.1 202 Accepted
{ "data": { "message_id": "8e0c…" } }

GET /api/v1/ingest/logs — paginated delivery history for the authenticated key. Query params: page, per_page.

Errors return a non-2xx status with { "error": { "code", "error_code", "message", "meta" } }. Common cases:

HTTPerror_codeMeaning
400Invalid mode, missing channel_ids, route mode with >1 channel, or no content.
401Missing or invalid x-api-key.
403Channel not owned by your account.
403subscription_expiredYour package has expired — renew it.
403api_key_expiredThe API key has passed its expiry date.
429Daily or monthly quota exceeded.

Quotas come from your package: a daily and a monthly limit. A value of -1 means unlimited. Exceeding either returns 429 Too Many Requests.

Guides

Broadcast vs Route — broadcast fans out to every platform across all selected channels, automatically de-duplicating platforms that appear in more than one channel. Route targets exactly one channel and fails over platform-by-platform in priority order until one succeeds.

route mode (single channel)
{
  "channel_ids": ["ONE_CHANNEL_ID"],
  "mode": "route",
  "payload": { "title": "Order #1024", "body": "New paid order" }
}

Templates & variables — create a template in the dashboard, then reference it by template_id and pass a variables map to fill placeholders.

Sending with a template
{
  "channel_ids": ["YOUR_CHANNEL_ID"],
  "mode": "broadcast",
  "template_id": "YOUR_TEMPLATE_ID",
  "variables": { "name": "Lan", "amount": "299.000đ" }
}

Recipient — Email and SMS platforms need a destination address. Pass recipient.email and/or recipient.phone.

Sending with a recipient
{
  "channel_ids": ["YOUR_CHANNEL_ID"],
  "mode": "broadcast",
  "payload": { "title": "Receipt", "body": "Thanks for your order" },
  "recipient": { "email": "lan@example.com", "phone": "+84901234567" }
}

LadiPage / form integration — in your form’s API/Webhook config, set the request to POST to https://notifyroute.com/api/v1/ingest, add the header x-api-key: YOUR_API_KEY, and map form fields into the JSON body (e.g. payload.body). If your form builder cannot send custom headers, set Default Channels on the API key and route the form through a webhook relay (Make, n8n, or a small serverless function) that adds the header.

Troubleshooting — a message stuck as failed usually means no active platform is attached to the channel. “400 channel_ids is required” means you must pass channel_ids or set Default Channels on the key. 429 means you hit your quota. “403 subscription_expired” means you must renew your package.