SeptemCore LogoSeptemCore
PrimitivesNotify

Sending Notifications

kernel.notify().send() returns 202 Accepted immediately. sendBatch() for multiple recipients — batch > 100 creates a background job. sendFromTemplate() with variable substitution. Priority levels: low/normal/high/critical.

All notification delivery is asynchronous. send() enqueues the notification to RabbitMQ and returns a notificationId immediately with 202 Accepted. Delivery, retry, and status tracking happen in the background without blocking the caller.


Send a Single Notification

import { kernel } from '@platform/sdk-core';

const result = await kernel.notify().send({
  userId:   '01j9pa5mz700000000000000',
  channel:  'email',
  subject:  'Your invoice is ready',
  body:     'Invoice #1042 for $250.00 is ready to download.',
  priority: 'normal',
});
// result: { notificationId: '01j9panot700000000000000' }

The method resolves as soon as the notification is enqueued. Delivery happens asynchronously — poll the status endpoint or subscribe to the notify.notification.sent event to confirm delivery.

Full SDK Signature

kernel.notify().send(options: {
  userId:    string;             // recipient — Notify resolves their channel config
  channel:   string;             // 'email' | 'sms' | 'telegram' | 'webhook' | any registered channel
  subject?:  string;             // channel-dependent (required for email, ignored for sms)
  body:      string;             // notification body text
  metadata?: Record<string, unknown>;  // arbitrary key-value attached to the notification record
  priority?: 'low' | 'normal' | 'high' | 'critical';  // default: 'normal'
}): Promise<{ notificationId: string }>

REST Equivalent

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

{
  "userId":   "01j9pa5mz700000000000000",
  "channel":  "email",
  "subject":  "Your invoice is ready",
  "body":     "Invoice #1042 for $250.00 is ready to download.",
  "priority": "normal"
}

Response 202 Accepted:

{
  "notificationId": "01j9panot700000000000000",
  "status": "queued",
  "channel": "email",
  "queuedAt": "2026-04-15T10:30:00.000Z"
}

Priority Levels

Priority controls the RabbitMQ queue priority and the delivery SLA. Higher-priority notifications are dequeued before lower-priority ones when the queue is under load.

PriorityRabbitMQ priorityTypical use caseDelivery SLA
low1Marketing, newsletters, digestsBest effort
normal5Order updates, routine alerts< 30 s
high7Payment receipts, security alerts< 5 s
critical9OTP codes, account lockout warnings< 2 s

critical notifications bypass the standard rate limiter and are delivered immediately, even if the tenant has reached the per-minute limit for low/normal/high messages.


Checking Delivery Status

const status = await kernel.notify().status('01j9panot700000000000000');
// { notificationId, status: 'delivered' | 'queued' | 'sending' | 'failed', deliveredAt, channel }
GET https://api.septemcore.com/v1/notifications/01j9panot700000000000000
Authorization: Bearer <access_token>

Response 200 OK:

{
  "notificationId": "01j9panot700000000000000",
  "status": "delivered",
  "channel": "email",
  "queuedAt": "2026-04-15T10:30:00.000Z",
  "deliveredAt": "2026-04-15T10:30:02.134Z",
  "attempts": 1
}

Send a Batch

Send to multiple recipients in a single call:

const result = await kernel.notify().sendBatch({
  recipients: [
    { userId: '01j9pa5mz700000000000000', channel: 'email' },
    { userId: '01j9pb3kz100000000000000', channel: 'email' },
  ],
  subject:  'Platform maintenance on Saturday',
  body:     'Scheduled downtime 02:00–04:00 UTC on 2026-04-19.',
  priority: 'normal',
});
// result: { jobId: '01j9pajob800000000000000', total: 2 }
POST https://api.septemcore.com/v1/notifications/batch
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "recipients": [
    { "userId": "01j9pa5mz700000000000000", "channel": "email" },
    { "userId": "01j9pb3kz100000000000000", "channel": "email" }
  ],
  "subject":  "Platform maintenance on Saturday",
  "body":     "Scheduled downtime 02:00–04:00 UTC on 2026-04-19.",
  "priority": "normal"
}

Response 202 Accepted:

{
  "jobId": "01j9pajob800000000000000",
  "total": 2,
  "status": "processing"
}

Batch limits

ParameterValue
Recipients per batch callMax 500
Batch → background job threshold> 100 recipients
Response for ≤ 100 recipients202 Accepted + array of notificationId
Response for > 100 recipients202 Accepted + { jobId } (background job)

When a batch triggers a background job, track progress:

GET https://api.septemcore.com/v1/notifications/jobs/01j9pajob800000000000000
Authorization: Bearer <access_token>
{
  "jobId":  "01j9pajob800000000000000",
  "status": "processing",
  "sent":   87,
  "failed": 3,
  "total":  500
}

status transitions: queuedprocessingcompleted | completed_with_errors.


Send from Template

await kernel.notify().sendFromTemplate({
  templateId: '01j9patpl900000000000000',
  userId:     '01j9pa5mz700000000000000',
  variables: {
    name:          'Alice Chen',
    invoiceNumber: '1042',
    amount:        '$250.00',
    dueDate:       '2026-04-30',
  },
  priority: 'normal',
});
POST https://api.septemcore.com/v1/notifications
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "templateId": "01j9patpl900000000000000",
  "userId":     "01j9pa5mz700000000000000",
  "variables": {
    "name":          "Alice Chen",
    "invoiceNumber": "1042",
    "amount":        "$250.00",
    "dueDate":       "2026-04-30"
  },
  "priority": "normal"
}

templateId and body are mutually exclusive — you cannot provide both in the same request.


Notification History

GET https://api.septemcore.com/v1/notifications?page_size=20&page_token=01j9panot...
Authorization: Bearer <access_token>
{
  "data": [
    {
      "notificationId": "01j9panot700000000000000",
      "channel": "email",
      "status": "delivered",
      "deliveredAt": "2026-04-15T10:30:02Z"
    }
  ],
  "next_page_token": "01j9panot600000000000000"
}

History is stored for 90 days. Failed notifications are separately accessible:

GET https://api.septemcore.com/v1/notifications/failed?page_size=20
Authorization: Bearer <access_token>

Manual Retry

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

Response 202 Accepted:

{
  "notificationId": "01j9panot700000000000000",
  "status": "queued",
  "attempt": 6
}

Manual retry is not subject to the standard 5-attempt limit — it always re-enqueues the notification regardless of previous attempts.


Error Reference

ScenarioHTTPCode
Channel not registered400CHANNEL_NOT_FOUND
User not found404not-found
Rate limit exceeded (non-critical)429rate-limit-exceeded — notification queued with delay
Batch > 500 recipients400BATCH_LIMIT_EXCEEDED
Batch job — queue full (>10 000)503queue-full
templateId and body both provided400validation-error

On this page