Skip to main content

Notify REST API Reference

The Notify Service is the single delivery hub for all platform notifications. Delivery channels are plugin-based — the core provides the NotificationChannel interface and adapters (Email, SMS, Telegram, Slack, WebSocket, Browser Push, Webhook) are installed as modules.

Built-in channels that require no adapter: WebSocket and Browser Push (FCM/APNs).

See the REST API Overview for authentication, error format, pagination, and rate limiting. See the WebSocket Protocol for the full real-time specification.

note

For layout brevity, the /api/v1 base path prefix is omitted from the endpoint tables below.


Endpoints

EndpointTypeDescription
POST /notificationsCRUDSend a notification
POST /notifications/batchActionSend to multiple recipients
GET /notifications/:idCRUDNotification status
GET /notificationsCRUDNotification history (paginated)
POST /notifications/:id/retryActionRetry a failed notification
GET /notifications/failedCRUDFailed notifications queue (paginated)
POST /notifications/templatesCRUDCreate a notification template
GET /notifications/templatesCRUDList templates
POST /notifications/channelsCRUDRegister a channel adapter
GET /notifications/channelsCRUDList registered channels

POST /api/v1/notifications — Send

POST https://api.septemcore.com/v1/notifications
Authorization: Bearer <access_token>
Content-Type: application/json

{
"channel": "email",
"recipient": {
"userId": "01j9pusr0000000000000001"
},
"subject": "Your invoice is ready",
"body": "Invoice #INV-2026-042 is available in your account.",
"priority": "normal",
"meta": { "invoiceId": "inv_042" }
}

Response 202 Accepted (fire-and-forget — delivery happens asynchronously):

{
"notificationId": "01j9pnot0000000000000001",
"status": "queued",
"channel": "email",
"createdAt": "2026-04-22T04:10:00Z"
}

POST /notifications always returns 202 Accepted immediately. kernel.notify().send() is non-blocking — delivery and retries happen via RabbitMQ queue asynchronously.

Request Fields

FieldRequiredDescription
channelRegistered channel name (e.g. email, sms, telegram, websocket)
recipient.userId✅ (or recipient.address)Platform user ID — core resolves linked channels
recipient.address✅ (or recipient.userId)Direct address (e.g. raw email or phone number)
subjectSubject line (email, push)
bodyNotification body text
prioritylow, normal (default), high, critical
templateIdIf set, body may be omitted — template variables applied via variables
variablesKey-value map for template substitution
metaArbitrary JSON metadata stored with the record

POST /api/v1/notifications/batch — Batch Send

POST https://api.septemcore.com/v1/notifications/batch
Authorization: Bearer <access_token>
Content-Type: application/json

{
"channel": "email",
"recipients": [
{ "userId": "01j9pusr0000000000000001" },
{ "userId": "01j9pusr0000000000000002" }
],
"templateId": "tmpl_invoice_ready",
"variables": { "planName": "Growth" },
"priority": "normal"
}
Batch limitValue
Max recipients per batch call500
Exceeded400 Bad Request (problems/batch-limit-exceeded)
Background job thresholdbatch > 100 recipients → async job

When batch > 100 recipients the service returns 202 Accepted with a job reference:

{
"jobId": "01j9pjob0000000000000001",
"status": "queued",
"total": 350
}

Track progress with GET /api/v1/notifications/jobs/:id:

{
"jobId": "01j9pjob0000000000000001",
"status": "running",
"total": 350,
"sent": 210,
"failed": 3
}

status values: queued, running, completed, failed.


GET /api/v1/notifications/:id — Status

{
"id": "01j9pnot0000000000000001",
"channel": "email",
"recipient": { "userId": "01j9pusr0000000000000001", "address": "[email protected]" },
"subject": "Your invoice is ready",
"status": "delivered",
"priority": "normal",
"retries": 0,
"sentAt": "2026-04-22T04:10:02Z",
"deliveredAt": "2026-04-22T04:10:04Z",
"failedAt": null,
"meta": { "invoiceId": "inv_042" }
}
Status valueMeaning
queuedIn RabbitMQ, not yet attempted
sendingAdapter is making the delivery attempt
deliveredAdapter confirmed delivery
failedMax retries exhausted — see failed queue

POST /api/v1/notifications/:id/retry — Manual Retry

Manually re-enqueue a failed notification:

POST https://api.septemcore.com/v1/notifications/01j9pnot0000000000000001/retry
Authorization: Bearer <access_token>

Response 202 Accepted — notification re-queued.


GET /api/v1/notifications/failed — Failed Queue

Lists notifications that exhausted all retry attempts (cursor-paginated):

GET https://api.septemcore.com/v1/notifications/failed
?channel=email
&since=2026-04-01T00:00:00Z
&limit=20
Authorization: Bearer <access_token>

Retry Policy

Delivery retries happen transparently via RabbitMQ with exponential backoff. The calling service is never blocked.

ParameterValue
Max retries5 (per-adapter, configurable)
Backoff schedule30 s → 60 s → 120 s → 240 s → 480 s (±10% jitter)
Timeout per attempt10 s (per-adapter, configurable)
After max retriesStatus: failed. Recorded in notifications_failed table. Visible in Admin UI → Notifications → Failed
Manual retryPOST /notifications/:id/retry
Automatic fallbackNot provided — no automatic channel fallback

Note: Retry does NOT block the caller. POST /notifications returns 202 Accepted immediately. RabbitMQ queue per tenant: notify.outgoing.{tenantId} (one slow tenant cannot affect others). Queue policy: x-max-length: 10000, overflow: reject-publish503.


Templates

Templates store reusable notification content with variable substitution.

EndpointDescription
POST /notifications/templatesCreate template
GET /notifications/templatesList templates (cursor-paginated)
GET /notifications/templates/:idTemplate details
PATCH /notifications/templates/:idUpdate template
DELETE /notifications/templates/:idDelete template

POST /api/v1/notifications/templates

POST https://api.septemcore.com/v1/notifications/templates
Authorization: Bearer <access_token>
Content-Type: application/json

{
"id": "tmpl_invoice_ready",
"name": "Invoice Ready",
"channel": "email",
"subject": "Your {{planName}} invoice is ready",
"body": "Invoice {{invoiceNumber}} for your {{planName}} plan is now available.",
"variables": ["planName", "invoiceNumber"]
}

Variable syntax: {{variableName}}. All declared variables must be provided in POST /notifications variables map — missing variables → 400 Bad Request.


Channels

Channels are installed by registering adapter modules via module.manifest.json (notificationChannels field). After installation, the channel automatically appears in Settings → Notifications.

EndpointDescription
GET /notifications/channelsList registered channels
POST /notifications/channelsRegister a custom channel adapter
GET /notifications/channels/:idChannel details and config
DELETE /notifications/channels/:idUnregister a channel

Channel Object

{
"id": "email",
"name": "Email (SendGrid)",
"type": "email",
"iconUrl": "https://cdn.platform.io/icons/sendgrid.svg",
"status": "active",
"config": {
"apiKey": "[redacted]",
"fromEmail": "[email protected]"
},
"registeredAt": "2026-04-01T09:00:00Z"
}

Built-in channels (no adapter required):

Channel IDTypeNotes
websocketreal-timenhooyr.io/websocket. See WebSocket Protocol
pushbrowser pushService Worker + FCM/APNs

Plugin channels (installed as modules):

AdapterType
Email (SMTP / SendGrid / Mailgun)email
SMS (Twilio / Vonage)sms
Telegramsocial
Slacksocial
Discordsocial
Webhookwebhook

Rate Limiting

LimitValueEnv var
Per-tenant100 notifications / minuteNOTIFY_RATE_LIMIT_PER_TENANT
Per-module50 notifications / minute
Batch max recipients500
Exceeded429 Too Many Requests — message is not lost, queued with delay

Principle: Without rate limiting, a buggy module loop (send() for 100K users) would get the platform's IP banned by SendGrid/Telegram, affecting all tenants.


Notification History Retention

DataRetentionStorage
Notification history90 days (NOTIFY_HISTORY_RETENTION_DAYS)PostgreSQL
Failed notifications180 daysPostgreSQL
Long-term audit trail7 yearsAudit Service (every send recorded)

Error Reference

Error typeStatusTrigger
problems/channel-not-found404Specified channel is not registered for this tenant
problems/batch-limit-exceeded400More than 500 recipients in one batch call
problems/template-not-found404templateId does not exist
problems/template-variable-missing400Required template variable not provided
problems/notification-not-failed400Retry attempted on a non-failed notification
problems/rate-limit-exceeded429Per-tenant or per-module notification rate exceeded
problems/queue-full503RabbitMQ per-tenant queue at x-max-length: 10000