Notifications
The notification system provides multi-channel notifications (push, in-app, email, SMS, chat) powered by Novu. The service acts as a thin multi-tenant proxy to Novu's REST API — payloads and responses are passed through as opaque JSON where possible.
All notification endpoints are available through the KrakenD API gateway.
Concepts
| Term | Description |
|---|---|
| Workflow | A Novu notification template defining content, channels, and delivery steps. You trigger workflows by their workflow_id. |
| Channel | Delivery method: push, in-app, email, SMS, chat |
| Subscriber | A user registered to receive notifications (1:1 with user ID) |
| Topic | A named group of subscribers for fan-out delivery |
| Digest | Batching behavior configured in a Novu workflow step — groups events before delivery |
| Provider | External service for delivery (FCM, APNS, SendGrid, Twilio, etc.) |
Architecture
The NotificationGatewayService extracts authentication context from request headers and forwards to the NotificationService, which owns the Novu integration with circuit breaker protection and per-tenant credential resolution.
Endpoint Paths
User-facing endpoints use /api/v1/notifications/, while admin/management endpoints use /api/v1/notifications/manage/.
All responses use protobuf JSON encoding. Fields with default values (false, 0, "") are omitted from the response. Your decoder must treat missing fields as their default value.
Push Device Registration
Register a device to receive push notifications via FCM.
Register a Device
POST /api/v1/notifications/register-push-device
{
"fcmToken": "firebase-cloud-messaging-token",
"platform": "PLATFORM_IOS",
"deviceId": "device-unique-id"
}
Response:
{
"subscriberId": "user_123",
"success": true
}
Unregister a Device
POST /api/v1/notifications/unregister-push-device
{
"fcmToken": "firebase-cloud-messaging-token"
}
Response:
{
"subscriberId": "user_123"
}
remainingCredentialCountappears when > 0 (other devices still registered).
Get Registered Channels
Check which notification channels are available for the current user.
POST /api/v1/notifications/get-registered-channels
{}
Response:
{
"channels": [
{"channel": "CHANNEL_IN_APP", "registered": true, "credentialCount": 1},
{"channel": "CHANNEL_PUSH"},
{"channel": "CHANNEL_EMAIL", "registered": true, "credentialCount": 1},
{"channel": "CHANNEL_SMS"}
]
}
Channels without credentials omit
registeredandcredentialCount.
Sending Notifications
All send endpoints use workflow_id to specify which Novu workflow to trigger. Call ListWorkflows first to discover available workflow IDs.
Send to a User
POST /api/v1/notifications/manage/send-notification
{
"workflowId": "push-notification",
"userId": "recipient-user-id",
"payload": {
"title": "New Message",
"body": "You have a new coaching update",
"deep_link": "socayo://conversation/conv_abc"
},
"transactionId": "optional-idempotency-key"
}
Response:
{
"acknowledged": true,
"status": "processed",
"transactionId": "txn_abc123"
}
| Field | Type | Description |
|---|---|---|
workflowId | string | Novu workflow identifier (required) |
userId | string | Recipient user ID (required) |
payload | object | Arbitrary JSON passed to the workflow template |
overrides | object | Novu provider overrides (e.g., FCM data payload) |
transactionId | string | Optional idempotency/tracking key |
Send Bulk
Trigger workflows for multiple recipients in a single call.
POST /api/v1/notifications/manage/send-bulk-notification
{
"events": [
{
"workflowId": "push-notification",
"userId": "user-1",
"payload": {"title": "Update", "body": "New feature available"}
},
{
"workflowId": "push-notification",
"userId": "user-2",
"payload": {"title": "Update", "body": "New feature available"}
}
]
}
Response:
{
"results": [
{"acknowledged": true, "status": "processed", "transactionId": "txn_1"},
{"acknowledged": true, "status": "processed", "transactionId": "txn_2"}
]
}
Cancel a Notification
Cancel a pending notification by transaction ID.
POST /api/v1/notifications/manage/cancel-notification
{
"transactionId": "txn_abc123"
}
Response:
{
"cancelled": true,
"message": "Event cancelled successfully"
}
In-App Inbox
Get Inbox Session
Get a Novu session token and WebSocket URL for real-time inbox updates.
POST /api/v1/notifications/get-inbox-session
{}
Response:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"socketUrl": "wss://novu-ws.yocaso.dev",
"expiresIn": "1296000"
}
| Field | Type | Description |
|---|---|---|
token | string | JWT for WebSocket auth |
socketUrl | string | Novu WebSocket URL |
expiresIn | string | Token validity in seconds (~15 days). String type (int64 protojson convention). |
Get Inbox Feed
POST /api/v1/notifications/get-inbox-feed
{
"page": 1,
"pageSize": 20
}
Pagination is 1-based. Optional filter object supports unseenOnly, unreadOnly, feedIds, and categories (plain strings).
Response:
{
"messages": [
{
"messageId": "69c0df5391079c0a4596f7d3",
"notificationId": "69c0df5291079c0a4596f79b",
"title": "Weekly Check-in",
"body": "Time to review your progress.",
"data": {
"title": "Weekly Check-in",
"body": "Time to review your progress.",
"deep_link": "socayo://screen?name=weekly"
},
"deepLink": "socayo://screen?name=weekly",
"status": "MESSAGE_STATUS_UNSEEN",
"createdAt": "2026-03-23T06:36:03.578Z"
}
],
"totalCount": 6,
"page": 1,
"pageSize": 20
}
hasMoreonly appears whentrue. Fields likecategory,deepLink,actionsare omitted when empty.
Get Unseen Count
POST /api/v1/notifications/get-inbox-unseen-count
Response:
{
"unseenCount": 3,
"unreadCount": 5
}
Counts are capped at 10.
hasMoreUnseen/hasMoreUnreadappear whentrue— display as "9+".
Mark Messages
Mark a single message:
POST /api/v1/notifications/mark-inbox-message
{
"messageId": "msg_123",
"markAs": "MESSAGE_STATUS_READ"
}
Response:
{
"messages": [
{
"messageId": "msg_123",
"channel": "in_app",
"seen": true,
"content": "Time to review your progress.",
"status": "sent",
"createdAt": "2026-03-23T06:36:03.578Z",
"lastSeenDate": "2026-03-23T10:24:35.518Z"
}
]
}
Mark all messages:
POST /api/v1/notifications/mark-all-inbox-messages
{
"markAs": "MESSAGE_STATUS_SEEN"
}
Response: {"updatedCount": 5}
Status options: MESSAGE_STATUS_SEEN, MESSAGE_STATUS_READ, MESSAGE_STATUS_UNSEEN, MESSAGE_STATUS_UNREAD.
Delete Inbox Message
POST /api/v1/notifications/delete-inbox-message
{
"messageId": "msg_123"
}
Response:
{
"status": {
"acknowledged": true,
"status": "deleted"
}
}
Preferences
Preferences are managed per-workflow and per-channel in Novu. The API returns the raw Novu preference structure.
Get Preferences
POST /api/v1/notifications/get-preferences
Response:
{
"preferences": {
"data": {
"global": {
"channels": {
"email": true,
"in_app": true,
"push": false
},
"enabled": true
},
"workflows": [
{
"channels": {"in_app": true, "push": false},
"enabled": true,
"workflow": {
"identifier": "product",
"name": "product"
}
},
{
"channels": {"in_app": true, "push": true},
"enabled": true,
"workflow": {
"identifier": "promotional",
"name": "promotional"
}
}
]
}
}
}
Critical workflows (system, transactional) are hidden from this response by Novu.
Update Preferences
Toggle channel(s) for a specific workflow or globally.
POST /api/v1/notifications/update-preferences
{
"channels": {"push": false},
"workflowId": "promotional"
}
Omit workflowId to apply globally. Response returns the full updated preferences (same structure as GetPreferences).
Topics
Topics enable pub/sub-style fan-out delivery.
Create a Topic
POST /api/v1/notifications/manage/create-topic
{
"topicKey": "weekly-updates",
"name": "Weekly Updates"
}
Add/Remove Subscribers
POST /api/v1/notifications/manage/add-subscribers-to-topic
{
"topicKey": "weekly-updates",
"userIds": ["user-1", "user-2"]
}
Up to 100 subscribers per call.
POST /api/v1/notifications/manage/remove-subscribers-from-topic
{
"topicKey": "weekly-updates",
"userIds": ["user-1"]
}
Send to Topic
POST /api/v1/notifications/manage/send-to-topic
{
"workflowId": "push-notification",
"topicKey": "weekly-updates",
"payload": {
"title": "Weekly Update",
"body": "Your weekly health summary is ready"
},
"excludeUserId": "user-admin"
}
List Topic Subscribers
POST /api/v1/notifications/manage/list-topic-subscribers
{
"topicKey": "weekly-updates",
"page": 1,
"pageSize": 50
}
Check Subscription
POST /api/v1/notifications/manage/check-topic-subscription
{
"topicKey": "weekly-updates",
"userId": "user-1"
}
Digest / Batching
Digest behavior is configured in the Novu workflow itself (digest step). This RPC triggers a workflow that has digest enabled.
POST /api/v1/notifications/manage/send-with-digest
{
"workflowId": "activity-digest",
"userId": "user-1",
"payload": {
"title": "Activity Update",
"body": "New activity in your coaching plan"
},
"transactionId": "digest-event-123"
}
Cancel a digest event:
POST /api/v1/notifications/manage/cancel-digest-event
{
"transactionId": "digest-event-123"
}
Subscriber Management
Create Subscriber
POST /api/v1/notifications/manage/create-subscriber
{
"subscriberId": "user-1",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@example.com",
"phone": "+1234567890",
"locale": "en-US"
}
Get / Update / Delete Subscriber
Get and delete use empty request bodies (user derived from auth headers):
POST /api/v1/notifications/get-subscriber
POST /api/v1/notifications/delete-subscriber
Update subscriber profile data:
POST /api/v1/notifications/update-subscriber-data
{
"data": {
"email": "jane.updated@example.com",
"locale": "en-GB"
}
}
List Subscribers
POST /api/v1/notifications/manage/list-subscribers
{
"page": 1,
"pageSize": 50
}
Workflow Management
Workflows are managed as opaque Novu JSON objects. The API passes workflow definitions through without interpretation.
Create Workflow
POST /api/v1/notifications/manage/create-workflow
{
"workflow": {
"name": "Welcome Notification",
"description": "Sent when a user completes onboarding",
"__source": "editor",
"steps": [
{
"name": "In-App Step",
"type": "in_app",
"controlValues": {
"body": "Welcome to your health coaching journey!"
}
}
]
}
}
Response: Returns the created workflow object from Novu.
Update / Get / List / Delete Workflow
POST /api/v1/notifications/manage/update-workflow
POST /api/v1/notifications/manage/get-workflow
POST /api/v1/notifications/manage/list-workflows
POST /api/v1/notifications/manage/delete-workflow
All return opaque Novu workflow JSON.
Provider Configuration
Configure external delivery providers (FCM, APNS, SendGrid, etc.).
POST /api/v1/notifications/manage/configure-provider
{
"provider": "PROVIDER_TYPE_FCM",
"credentials": {
"serviceAccount": "{...}"
},
"active": true
}
configure-provider uses upsert semantics: if an active integration already exists for the specified provider type, it updates the existing integration in place (preserving its ID and subscriber linkages). If no active integration exists, a new one is created.
This prevents duplicate integrations and ensures existing device registrations continue to work after credential updates. If multiple active integrations exist for the same provider type, the call returns 409 Conflict — resolve the duplicates manually via the Novu dashboard.
POST /api/v1/notifications/manage/get-providers
Promotion (Dev → Prod)
Manage promotion of notification changes from development to production.
POST /api/v1/notifications/manage/get-pending-changes
POST /api/v1/notifications/manage/promote-change
POST /api/v1/notifications/manage/promote-all-changes
Activity & Delivery Status
Get Delivery Status
Returns the raw Novu activity data for a notification.
POST /api/v1/notifications/manage/get-delivery-status
{
"transactionId": "txn_abc123"
}
Response: Returns {"activity": {...}} with raw Novu data.
Get Notification Activity
Query delivery history with channel and time filtering.
POST /api/v1/notifications/manage/get-notification-activity
{
"page": 1,
"pageSize": 50,
"channels": ["in_app", "push"],
"from": "2026-03-01T00:00:00Z",
"to": "2026-03-23T23:59:59Z"
}
Response: Returns {"entries": [...], "hasMore": true} with raw Novu activity entries.
RPC Summary
User-Facing (11 RPCs)
| Endpoint | Description |
|---|---|
register-push-device | Register FCM token |
unregister-push-device | Remove FCM token |
get-registered-channels | List available channels |
get-inbox-session | Get Novu session for WebSocket |
get-inbox-feed | Paginated inbox messages |
get-inbox-unseen-count | Unseen/unread counts |
mark-inbox-message | Mark single message status |
mark-all-inbox-messages | Bulk mark messages |
delete-inbox-message | Delete inbox message |
get-preferences | Get notification preferences |
update-preferences | Update notification preferences |
Admin/Management (29 RPCs)
| Endpoint | Description |
|---|---|
manage/send-notification | Trigger workflow for a user |
manage/send-bulk-notification | Trigger for multiple users |
manage/cancel-notification | Cancel pending notification |
manage/send-to-topic | Send to topic subscribers |
manage/send-with-digest | Trigger digest workflow |
manage/cancel-digest-event | Cancel digest event |
manage/create-topic | Create topic |
manage/delete-topic | Delete topic |
manage/add-subscribers-to-topic | Add subscribers to topic |
manage/remove-subscribers-from-topic | Remove from topic |
manage/list-topic-subscribers | List topic subscribers |
manage/check-topic-subscription | Check subscription |
manage/create-subscriber | Create subscriber |
manage/get-subscriber | Get subscriber details |
manage/update-subscriber-data | Update subscriber data |
manage/delete-subscriber | Delete subscriber |
manage/list-subscribers | List subscribers |
manage/create-workflow | Create workflow |
manage/update-workflow | Update workflow |
manage/get-workflow | Get workflow details |
manage/list-workflows | List workflows |
manage/delete-workflow | Delete workflow |
manage/configure-provider | Configure delivery provider |
manage/get-providers | List active providers |
manage/get-pending-changes | List pending promotions |
manage/promote-change | Promote single change |
manage/promote-all-changes | Promote all changes |
manage/get-delivery-status | Get delivery status |
manage/get-notification-activity | Query delivery history |