Interested in an on-premise deployment or AI transformation? Calculate your AI costs. Call/text πŸ“ž (571) 293-0242

IBL Notification System β€” Developer Documentation

Base URL: /api/notification/v1/ Authentication: Authorization: Token YOUR_ACCESS_TOKEN API Version: v1


Table of Contents

  1. Introduction
  2. System Overview
  3. Authentication
  4. Quickstart
  5. Core Concepts
  6. Notification Types Reference
  7. API Reference
  8. Template System
  9. Special Notification Types
  10. Notification Preferences
  11. Platform SMTP Configuration
  12. Notification Lifecycle
  13. Error Reference
  14. Rate Limits and Best Practices

1. Introduction

The IBL Notification System provides multi-channel notification delivery for the IBL learning platform. It handles routing, templating, and delivery of notifications to learners, administrators, and other platform participants across email, push, and in-app channels.

Supported Channels

  • Email β€” Delivered via configured SMTP
  • Push Notifications β€” Delivered to registered mobile or browser clients via FCM
  • In-App β€” Surfaced within the IBL platform UI and accessible via API

Key Capabilities

  • Multi-channel delivery with per-channel enable/disable controls
  • 22+ built-in notification types triggered automatically by platform events (enrollments, completions, credential issuance, and more)
  • Customizable notification templates for your platform with inheritance from defaults β€” your edits apply to a copy, not the original
  • Enable or disable specific notification types for your platform
  • AI-powered proactive learner notifications for engagement and progress recommendations (optional, requires configuration)
  • Human support ticket routing with configurable recipient lists

Delivery Overview

flowchart LR
    P([Your Platform]) --> NS[Notification System]
    NS --> E[Email]
    NS --> Push[Push Notifications]
    NS --> IA[In-App]

2. System Overview

The notification system operates on an event-driven model. Actions within your platform β€” such as a learner completing a course, a manager sending an invitation, or a policy being assigned β€” trigger notifications. The system evaluates your configuration, selects the appropriate template, and delivers the notification through the enabled channels.

Your templates, preferences, and recipient rules are scoped to your platform only.

How Notifications Are Generated

Notifications reach your users through two paths:

Automatic β€” Events on your platform trigger notifications without any action from you. When a learner enrolls in a course, completes a credential, or receives a license assignment, the system generates and delivers the corresponding notification. For each event, the system checks:

  1. Whether the notification type is enabled for your platform
  2. Which channels are configured for delivery
  3. Which template applies (your customized version or the inherited default)
  4. Who the recipients are

Manual (Direct Send) β€” You compose and send notifications on demand using the Direct Send API. You select a template or write custom content, choose delivery channels, and define your audience from multiple sources (email addresses, usernames, user groups, departments, programs, or CSV uploads). Recipients are merged and deduplicated across sources before sending.

Both paths deliver through the same channels and respect your platform's template and preference configuration.

Admin and User Interaction Points

As a platform admin, you use the Admin API to:

  • Enable or disable notification types for your platform
  • Customize templates (your edits apply to a copy of the default)
  • Configure human support routing recipients
  • Control AI-powered proactive notification settings
  • Send direct notifications to targeted recipients

Your users use the User API to:

  • Retrieve their notification list
  • Mark notifications as read
  • Dismiss notifications

System Flow

flowchart TD
    PE([Platform Events]) -->|Automatic| NS[Notification System]
    DS([Direct Send API]) -->|Manual| NS

    AdminAPI[Admin API] -->|Configure templates\nand preferences| NS
    UserAPI[User API] -->|Retrieve and manage\nnotifications| NS

    NS --> CH{Channel\nRouter}
    CH --> Email[Email]
    CH --> Push[Push Notifications]
    CH --> InApp[In-App]

    Email --> R([Your Recipients])
    Push --> R
    InApp --> R

Notification Lifecycle

Each notification begins as UNREAD when delivered. Your users can mark them as READ or CANCELLED. A READ notification can be reverted to UNREAD, but CANCELLED is terminal.

stateDiagram-v2
    [*] --> UNREAD : Notification delivered

    UNREAD --> READ : User marks as read
    READ --> UNREAD : User marks as unread

    UNREAD --> CANCELLED : User cancels
    READ --> CANCELLED : User cancels

    CANCELLED --> [*]

3. Authentication

All Notification API endpoints require token-based authentication. Requests must include a valid access token in the Authorization header:

Authorization: Token YOUR_ACCESS_TOKEN

Obtain a token from your platform's authentication endpoint. Tokens are scoped to a user identity and validated on every request.

Permission Levels

ActionRequired Role
Read own notificationsAuthenticated user
Manage own notifications (read/unread/delete)Authenticated user
List/customize templatesPlatform Admin
Toggle notification typesPlatform Admin
Test SMTP credentialsPlatform Admin
Send direct notificationsPlatform Admin or Department Admin

Example Request

curl -X GET "https://platform.iblai.app/api/notification/v1/orgs/acme-learning/users/jane.doe/notifications/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json"

RBAC

If RBAC is enabled on your platform, permissions are validated against granular resource actions in addition to role checks. For example, listing notifications requires Ibl.Notifications/Notification/list and writing requires Ibl.Notifications/Notification/write. A role check alone is not sufficient when RBAC enforcement is active β€” the token's associated user must also hold the relevant resource action grant.

Security

Store tokens securely on the server side. Never expose tokens in client-side JavaScript, browser storage accessible to third-party scripts, or version control. Treat a token with the same care as a password β€” it grants full API access as the authenticated user.


4. Quickstart

Prerequisites

  • API token β€” Pass it in every request as Authorization: Token YOUR_ACCESS_TOKEN.
  • Platform key β€” The slug that identifies your organisation (e.g., acme-learning). This appears as the org or platform_key path segment in every URL.

Step 1: List Notifications for a User

Retrieve a paginated list of notifications. Unread notifications are returned first, followed by read ones in reverse-chronological order.

GET /api/notification/v1/orgs/{org}/users/{user_id}/notifications/

Query parameters (all optional)

ParameterDescription
statusFilter by status: UNREAD, READ
channelFilter by delivery channel (e.g. email, push_notification)
exclude_channelExclude a specific channel from results
start_dateReturn notifications created on or after this date
end_dateReturn notifications created on or before this date
curl -X GET \
  "https://platform.iblai.app/api/notification/v1/orgs/acme-learning/users/jane.doe/notifications/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN"

Response

{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "username": "jane.doe",
      "title": "New course available: Introduction to Data Science",
      "body": "

Hi Jane, you have been enrolled in Introduction to Data Science.

", "status": "UNREAD", "channel": "email", "context": { "course_name": "Introduction to Data Science", "username": "jane.doe" }, "short_message": "You have been enrolled in Introduction to Data Science.", "created_at": "2026-04-11T08:30:00Z", "updated_at": "2026-04-11T08:30:00Z" }, { "id": "7cb92a41-1e3d-4f8b-a2c6-9d0e5f7b3a12", "username": "jane.doe", "title": "Your certificate is ready", "body": "

Your certificate for Python Fundamentals is ready to download.

", "status": "READ", "channel": "email", "context": { "course_name": "Python Fundamentals", "username": "jane.doe" }, "short_message": "Your Python Fundamentals certificate is ready.", "created_at": "2026-04-10T14:15:00Z", "updated_at": "2026-04-10T14:22:00Z" } ] }

Response fields

FieldTypeDescription
idUUIDUnique notification identifier
usernamestringRecipient's username
titlestringRendered notification title
bodystringRendered full body (may contain HTML)
statusstringUNREAD, READ, or CANCELLED
channelstring or nullDelivery channel name
contextobjectTemplate variables used to render this notification
short_messagestringShort summary for push notification previews
created_atISO 8601Creation timestamp
updated_atISO 8601Last status change timestamp

Step 2: Check Unread Count

GET /api/notification/v1/orgs/{org}/users/{user_id}/notifications-count/?status=UNREAD
curl -X GET \
  "https://platform.iblai.app/api/notification/v1/orgs/acme-learning/users/jane.doe/notifications-count/?status=UNREAD" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN"
{
  "count": 5
}

Step 3: Mark a Notification as Read

PUT /api/notification/v1/orgs/{org}/users/{user_id}/notifications/
curl -X PUT \
  "https://platform.iblai.app/api/notification/v1/orgs/acme-learning/users/jane.doe/notifications/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "notification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "READ"
  }'

To mark multiple notifications, pass a comma-separated list:

{
  "notification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6,7cb92a41-1e3d-4f8b-a2c6-9d0e5f7b3a12",
  "status": "READ"
}
{
  "message": "Notification status updated successfully",
  "success": true
}

Step 4: Mark All Notifications as Read

POST /api/notification/v1/orgs/{platform_key}/mark-all-as-read
curl -X POST \
  "https://platform.iblai.app/api/notification/v1/orgs/acme-learning/mark-all-as-read" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

To mark a specific subset, provide notification_ids:

{
  "notification_ids": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "7cb92a41-1e3d-4f8b-a2c6-9d0e5f7b3a12"
  ]
}

Response

{
  "message": "Successfully marked 5 notifications as read",
  "count": 5
}

This endpoint operates on the authenticated user derived from the token. The platform_key scopes the operation to your platform only.


What's Next


5. Core Concepts

ConceptDescription
PlatformYour isolated notification environment. Templates, preferences, and delivery settings are scoped to your platform.
Notification TemplateDefines content, channels, and behavior for a notification type. You inherit defaults until you customize β€” your changes apply to your own copy only.
NotificationA sent notification record tied to a user, with delivery and read status tracking.
ChannelA delivery method: email, push_notification, or sms.
Notification TypeA category of notification (e.g., USER_NOTIF_COURSE_ENROLLMENT). Each type maps to one template for your platform.
Notification PreferenceA platform-level toggle that enables or disables a notification type for all users on your platform.

How Template Inheritance Works

flowchart TD
    A[Default Template\nshared until you customize] --> B{You customize?}
    B -- No --> C[Uses default as-is\nno copy created]
    B -- Yes --> D[Your copy created\nedits apply to your copy only]
    D --> E{Reset requested?}
    E -- Yes --> C
    E -- No --> D

6. Notification Types Reference

TypeCategoryTriggerDescription
USER_NOTIF_USER_REGISTRATIONUserUser account createdWelcomes new users to the platform
APP_REGISTRATIONUserUser registers via a linked applicationWelcome message with app name and benefits
USER_NOTIF_COURSE_ENROLLMENTLearningEnrolled in a courseConfirms course enrollment to the learner
USER_NOTIF_COURSE_COMPLETIONLearningCompleted a courseCongratulates on course completion with certificate link
USER_NOTIF_CREDENTIALSLearningCredential issuedNotifies learner of new credential with credential URL
USER_NOTIF_LEARNER_PROGRESSLearningPeriodic progress summaryDelivers progress digest with courses, time spent, credentials
USER_NOTIF_USER_INACTIVITYEngagementUser inactive for configured periodRe-engagement notification with inactivity details
PLATFORM_INVITATIONInvitationAdmin sends platform inviteInvites user to join the platform with redirect link
COURSE_INVITATIONInvitationAdmin sends course inviteInvites user to a course with enrollment link
PROGRAM_INVITATIONInvitationAdmin sends program inviteInvites user to a program with enrollment link
COURSE_LICENSE_ASSIGNMENTLicenseCourse license assigned to userNotifies user of course access via license
COURSE_LICENSE_GROUP_ASSIGNMENTLicenseCourse license assigned to user groupNotifies group members of course access
PROGRAM_LICENSE_ASSIGNMENTLicenseProgram license assigned to userNotifies user of program access via license
PROGRAM_LICENSE_GROUP_ASSIGNMENTLicenseProgram license assigned to user groupNotifies group members of program access
USER_LICENSE_ASSIGNMENTLicensePlatform user license assignedNotifies user of platform license with benefits
USER_LICENSE_GROUP_ASSIGNMENTLicensePlatform user license assigned to groupNotifies group members of platform license
ROLE_CHANGEAdminUser's platform role changedNotifies user of role promotion or demotion
ADMIN_NOTIF_COURSE_ENROLLMENTAdminUser enrolls in a courseAlerts admins with student name, email, and course
POLICY_ASSIGNMENTRBACRBAC policy assigned or removedNotifies user of role assignment/removal with resources
HUMAN_SUPPORT_NOTIFICATIONSupportHuman support ticket createdAlerts support staff with ticket details and chat link
PROACTIVE_LEARNER_NOTIFICATIONAIScheduledAI-generated personalized learning recommendations
REPORT_COMPLETEDAdminAsync report finishes processingNotifies user with report status and download URL
CUSTOM_NOTIFICATIONCustomCode-drivenPlatform-defined custom notification with custom targeting

7. API Reference

Base path: /api/notification/v1/

Authentication: Token header required on all endpoints unless noted otherwise.


7.1 Notifications API Reference

Summary
MethodEndpointAuthRBAC PermissionDescription
GET/orgs/{org}/notifications/TokenIbl.Notifications/Notification/listList paginated notifications scoped to the org
PUT/orgs/{org}/notifications/TokenIbl.Notifications/Notification/writeUpdate notification status scoped to the org
PATCH/orgs/{org}/notifications/bulk-update/TokenIbl.Notifications/Notification/writeBulk status update scoped to the org
GET/orgs/{org}/users/{user_id}/notifications/TokenIbl.Notifications/Notification/listList paginated notifications for a specific user
PUT/orgs/{org}/users/{user_id}/notifications/TokenIbl.Notifications/Notification/writeUpdate status of one or more notifications by ID
PATCH/orgs/{org}/users/{user_id}/notifications/bulk-update/TokenIbl.Notifications/Notification/writeSet a single status across all of a user's notifications
DELETE/orgs/{org}/users/{user_id}/notifications/{id}/TokenIbl.Notifications/Notification/deleteDelete a single notification
GET/orgs/{org}/users/{user_id}/notifications-count/TokenIbl.Notifications/Notification/listReturn count of notifications matching filters
POST/orgs/{platform_key}/mark-all-as-readTokenIbl.Notifications/Notification/writeMark all unread notifications as read

GET /orgs/{org}/users/{user_id}/notifications/

List notifications for a specific user on your platform. Results are ordered with unread notifications first, then by creation date descending. Paginated.

Path parameters

NameTypeDescription
orgstring (slug)Platform key
user_idstringUsername of the target user

Query parameters

NameTypeRequiredDescription
statusstringNoFilter by status: READ, UNREAD, CANCELLED
channelstringNoFilter by channel name (e.g. email, push_notification)
start_datestringNoNotifications created on or after this date
end_datestringNoNotifications created on or before this date
exclude_channelstringNoExclude a specific channel
pageintegerNoPage number for pagination

Response 200 OK

{
  "count": 2,
  "next": 2,
  "previous": null,
  "results": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "username": "jane.doe",
      "title": "Your course certificate is ready",
      "body": "

Your certificate for Intro to Data Science is now available.

", "status": "UNREAD", "channel": "email", "context": { "course_name": "Intro to Data Science", "username": "jane.doe" }, "short_message": "Your certificate for Intro to Data Science is ready.", "created_at": "2026-04-10T14:23:01.123456Z", "updated_at": "2026-04-10T14:23:01.123456Z" } ] }

Response fields

FieldTypeDescription
countintegerTotal notifications matching the query
nextinteger or nullNext page number
previousinteger or nullPrevious page number
results[].idUUIDUnique notification identifier
results[].usernamestring or nullRecipient's username
results[].titlestringRendered notification title
results[].bodystringRendered body (may contain HTML)
results[].statusstringREAD, UNREAD, or CANCELLED
results[].channelstring or nullDelivery channel name
results[].contextobject or nullTemplate context variables used for rendering
results[].short_messagestringShort message for SMS or preview
results[].created_atISO 8601Creation timestamp
results[].updated_atISO 8601Last update timestamp
curl -X GET "https://platform.iblai.app/api/notification/v1/orgs/acme-learning/users/jane.doe/notifications/?status=UNREAD" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN"

PUT /orgs/{org}/users/{user_id}/notifications/

Update the status of one or more notifications by UUID.

Request body

FieldTypeRequiredDescription
notification_idstringYesComma-separated notification UUIDs
statusstringYesREAD, UNREAD, or CANCELLED
{
  "notification_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6,7cb93e21-1234-4abc-9876-def012345678",
  "status": "READ"
}

Response 200 OK

{
  "message": "Notification status updated successfully",
  "success": true
}

PATCH /orgs/{org}/users/{user_id}/notifications/bulk-update/

Set a single status on all notifications for the specified user on your platform.

Request body

FieldTypeRequiredDescription
statusstringYesREAD, UNREAD, or CANCELLED

Response 200 OK

{
  "message": "Notification status updated successfully"
}

Error 400 Bad Request β€” returned when the user has no notifications.

{
  "error": "Notification does not exist"
}

DELETE /orgs/{org}/users/{user_id}/notifications/{id}/

Permanently delete a single notification.

Path parameters

NameTypeDescription
orgstringPlatform key
user_idstringUsername
idstringNotification ID

Response 200 OK

{
  "message": "Notification deleted successfully"
}

Error 404 Not Found

{
  "message": "Notification does not exist"
}

GET /orgs/{org}/users/{user_id}/notifications-count/

Return the count of notifications for a user.

Query parameters

NameTypeRequiredDescription
statusstringNoREAD, UNREAD, or CANCELLED
channelstringNoFilter by channel name

Response 200 OK

{
  "count": 5
}

POST /orgs/{platform_key}/mark-all-as-read

Mark all unread notifications as read for the authenticated user on the platform. Optionally restrict to specific IDs.

Request body

FieldTypeRequiredDescription
notification_idsarray of UUIDsNoIf provided, only these are marked. If omitted, all unread are marked.

Response 200 OK

{
  "message": "Successfully marked 3 notifications as read",
  "count": 3
}

7.2 Notification Templates API Reference

All template endpoints require Platform Admin role.

Summary
MethodEndpointAuthRoleDescription
GET/platforms/{platform_key}/templates/TokenPlatform AdminList all templates
GET/platforms/{platform_key}/templates/{type}/TokenPlatform AdminGet template detail
PATCH/platforms/{platform_key}/templates/{type}/TokenPlatform AdminCustomize a template (creates your copy on first edit)
PATCH/platforms/{platform_key}/templates/{type}/toggle/TokenPlatform AdminEnable or disable a notification type
POST/platforms/{platform_key}/templates/{type}/reset/TokenPlatform AdminReset to default
POST/platforms/{platform_key}/templates/{type}/test/TokenPlatform AdminSend a test notification

GET /platforms/{platform_key}/templates/

Returns every notification template visible to your platform, including inherited defaults and your customized overrides. Custom notification types are appended after system types.

Response 200 OK

[
  {
    "id": 14,
    "type": "USER_NOTIF_COURSE_ENROLLMENT",
    "name": "Course Enrollment",
    "description": "Sent when a learner enrolls in a course",
    "is_inherited": false,
    "source_platform": "acme-learning",
    "is_enabled": true,
    "can_customize": true,
    "is_custom": false,
    "message_title": "You have been enrolled in {{ course_name }}",
    "email_subject": "Welcome to {{ course_name }}",
    "spas": ["skills", "admin"],
    "allowed_channels": ["email", "push_notification"],
    "available_context": {
      "username": "Learner's username",
      "course_name": "Name of the course",
      "site_name": "Platform display name"
    }
  }
]

Response fields

FieldTypeDescription
idUUID or stringTemplate ID. Custom notification types use a custom_ string format.
typestringNotification type key
namestringHuman-readable name
descriptionstringWhen this notification is sent
is_inheritedbooleantrue if using the unmodified default template
source_platformstringPlatform key that owns the active template
is_enabledbooleanWhether this type is enabled for the platform
can_customizebooleanWhether template content is editable
is_custombooleantrue for custom notification types
message_titlestringPush/in-app title
email_subjectstringEmail subject line
spasarray of stringsSPAs that surface this notification
allowed_channelsarray of stringsDelivery channels
available_contextobjectVariable keys and descriptions

GET /platforms/{platform_key}/templates/{type}/

Returns full content and configuration of a single template. If you have a customized template, that is returned; otherwise the default template is returned with is_inherited: true.

Response 200 OK

{
  "id": 14,
  "type": "USER_NOTIF_COURSE_ENROLLMENT",
  "name": "Course Enrollment",
  "description": "Sent when a learner enrolls in a course",
  "message_title": "You have been enrolled in {{ course_name }}",
  "message_body": "Hi {{ username }}, you have been enrolled in {{ course_name }}.",
  "short_message_body": "Enrolled in {{ course_name }}",
  "email_subject": "Welcome to {{ course_name }}",
  "email_from_address": "no-reply@acme-learning.com",
  "email_html_template": "

Hi {{ username }},

You have been enrolled in {{ course_name }}.

", "spas_detail": [ {"id": 2, "name": "skills", "description": "Skills SPA"} ], "allowed_channels_detail": [ {"id": 1, "name": "email"}, {"id": 3, "name": "push_notification"} ], "is_inherited": false, "is_enabled": true, "source_platform": "acme-learning", "can_customize": true, "metadata": {}, "available_context": { "username": "Learner's username", "course_name": "Name of the course" }, "periodic_config": null, "policy_config": null, "human_support_config": null, "created_at": "2025-03-01T09:00:00Z", "updated_at": "2025-11-15T14:32:00Z" }

Additional response fields (detail only)

FieldTypeDescription
message_bodystringFull body text
short_message_bodystringShort version for SMS/preview
email_from_addressstringSender email
email_html_templatestringHTML email body
spas_detailarraySPA objects with id, name, description
allowed_channels_detailarrayChannel objects with id, name
metadataobjectRaw configuration blob
periodic_configobject or nullSchedule config (for PROACTIVE_LEARNER_NOTIFICATION only)
policy_configobject or nullRole config (for POLICY_ASSIGNMENT only)
human_support_configobject or nullRecipient config (for HUMAN_SUPPORT_NOTIFICATION only)

periodic_config fields (when present)

FieldTypeDescription
learner_scopestringACTIVE_LEARNERS or ALL_LEARNERS
report_period_daysintegerDays of activity to include
frequencystringDAILY, WEEKLY, MONTHLY, or CUSTOM
custom_interval_daysinteger or nullInterval when frequency is CUSTOM
execution_timestringHH:MM (24-hour)
timezonestringTimezone name
mentorsarrayMentor configs: [{"unique_id", "prompt", "name"}]
last_execution_datestring or nullISO 8601 date of last run
next_execution_datestring or nullISO 8601 date of next run

policy_config fields (when present)

FieldTypeDescription
enabled_policiesarrayPer-role configs: [{"role_name", "enabled", "subject"}]
notify_on_assignmentbooleanNotify on policy assignment
notify_on_removalbooleanNotify on policy removal

human_support_config fields (when present)

FieldTypeDescription
recipient_modestringplatform_admins_and_mentor_owner, platform_admins_only, mentor_owner_only, or custom
custom_recipientsarrayRecipient targets when mode is custom

PATCH /platforms/{platform_key}/templates/{type}/

Customize a notification template. On the first PATCH for a given type, the system creates your own copy of the default template and applies the changes. Subsequent PATCHes update your existing copy. Only fields present in the request body are changed.

Writable fields

FieldTypeDescription
namestringTemplate display name
descriptionstringDescription
message_titlestringPush/in-app title
message_bodystringBody text
short_message_bodystringShort version
email_subjectstringEmail subject
email_from_addressstringSender email
email_html_templatestringHTML email body
spa_idsarray of integersSPA IDs
channel_idsarray of integersChannel IDs

Periodic config fields (for PROACTIVE_LEARNER_NOTIFICATION)

FieldTypeDescription
periodic_learner_scopestringACTIVE_LEARNERS or ALL_LEARNERS
periodic_report_period_daysinteger (1–365)Report window
periodic_frequencystringDAILY, WEEKLY, MONTHLY, CUSTOM
periodic_custom_interval_daysinteger (1–365)Interval for CUSTOM
periodic_execution_timestringHH:MM format
periodic_timezonestringTimezone name
periodic_mentorsarrayMentor configs

Policy config fields (for POLICY_ASSIGNMENT)

FieldTypeDescription
policy_enabled_policiesarrayPer-role config
policy_notify_on_assignmentbooleanNotify on assignment
policy_notify_on_removalbooleanNotify on removal

Human support config fields (for HUMAN_SUPPORT_NOTIFICATION)

FieldTypeDescription
human_support_recipient_modestringRecipient mode
human_support_custom_recipientsarrayCustom recipients

Example request

curl -X PATCH "https://platform.iblai.app/api/notification/v1/platforms/acme-learning/templates/USER_NOTIF_COURSE_ENROLLMENT/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email_subject": "Welcome to {{ course_name }} on Acme Learning",
    "message_title": "Enrollment confirmed: {{ course_name }}"
  }'

Returns the full updated template in the same shape as the detail response.


PATCH /platforms/{platform_key}/templates/{type}/toggle/

Enable or disable a notification type. This does not modify template content.

Request body

FieldTypeRequiredDescription
allow_notificationbooleanYestrue to enable; false to disable
curl -X PATCH "https://platform.iblai.app/api/notification/v1/platforms/acme-learning/templates/USER_NOTIF_COURSE_ENROLLMENT/toggle/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"allow_notification": false}'

Response 200 OK

{
  "type": "USER_NOTIF_COURSE_ENROLLMENT",
  "is_enabled": false,
  "platform": "acme-learning",
  "message": "Notification disabled successfully"
}

POST /platforms/{platform_key}/templates/{type}/reset/

Deletes your customized template. Your platform falls back to the default template. The toggle state (enabled/disabled) is not affected.

No request body required.

curl -X POST "https://platform.iblai.app/api/notification/v1/platforms/acme-learning/templates/USER_NOTIF_COURSE_ENROLLMENT/reset/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN"

Response 200 OK

{
  "message": "Template reset to default. Platform will now use main template.",
  "deleted": true
}

If no platform override existed:

{
  "message": "Template was already using default from main platform.",
  "deleted": false
}

POST /platforms/{platform_key}/templates/{type}/test/

Send a test email using the template. The email is sent to the requesting admin's email address.

Request body

FieldTypeRequiredDescription
contextobjectNoKey-value pairs injected into the template. Overrides defaults.

Default context (auto-injected): username, site_name, course_name, platform_key.

curl -X POST "https://platform.iblai.app/api/notification/v1/platforms/acme-learning/templates/USER_NOTIF_COURSE_ENROLLMENT/test/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "context": {
      "course_name": "Introduction to Machine Learning"
    }
  }'

Response 200 OK

{
  "success": true,
  "message": "Test notification sent successfully to admin@acme-learning.com",
  "recipient": "admin@acme-learning.com"
}

Response 500 β€” delivery failure

{
  "success": false,
  "message": "Failed to send test notification. Check email configuration."
}

7.3 Push Notifications

Push notifications allow your platform to send real-time alerts via Firebase Cloud Messaging (FCM).

These endpoints are only available when push notifications are enabled on your platform.

Register FCM Device Token
POST /api/notification/v1/orgs/{org}/users/{user_id}/register-fcm-token/

Request body

FieldTypeRequiredDefaultDescription
namestringYesβ€”Device or app name
registration_idstringYesβ€”FCM device registration token
activebooleanNotrueWhether this registration is active
cloud_message_typestringNo"FCM"Cloud messaging type
application_idstringNo"ibl_fcm_app"Application identifier
curl -X POST \
  "https://platform.iblai.app/api/notification/v1/orgs/acme-learning/users/john.doe/register-fcm-token/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John iPhone 15",
    "registration_id": "eX3ampleFCMToken:APA91bHPRgkF..."
  }'

Response 200 OK

{
  "success": true,
  "message": "Token created successfully"
}
Remove FCM Device Token
DELETE /api/notification/v1/orgs/{org}/users/{user_id}/register-fcm-token/

Request body

FieldTypeRequiredDescription
registration_idstringYesDevice registration token to remove
curl -X DELETE \
  "https://platform.iblai.app/api/notification/v1/orgs/acme-learning/users/john.doe/register-fcm-token/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"registration_id": "eX3ampleFCMToken:APA91bHPRgkF..."}'

Response 200 OK

{
  "success": true,
  "message": "Registration ID delete successfully"
}

7.4 SMTP Configuration

Test SMTP Credentials

Opens a live SMTP connection and sends a test email to verify credentials.

POST /api/notification/v1/platforms/{platform_key}/config/test-smtp/

Auth: Token, Platform Admin (Ibl.Notifications/SMTP/action)

Request body

FieldTypeRequiredDefaultDescription
smtp_hoststringYesβ€”SMTP server hostname
smtp_portintegerYesβ€”SMTP server port (1–65535)
smtp_usernamestringYesβ€”SMTP username
smtp_passwordstringYesβ€”SMTP password (write-only)
use_tlsbooleanNotrueEnable STARTTLS
use_sslbooleanNofalseEnable SSL/TLS on connect
test_emailemailYesβ€”Recipient for the test email
from_emailemailNoβ€”Sender address (defaults to smtp_username)

use_tls and use_ssl are mutually exclusive. Use use_tls: true with port 587 or use_ssl: true with port 465.

curl -X POST \
  "https://platform.iblai.app/api/notification/v1/platforms/acme-learning/config/test-smtp/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "smtp_host": "smtp.gmail.com",
    "smtp_port": 587,
    "smtp_username": "notifications@example.com",
    "smtp_password": "app-specific-password",
    "use_tls": true,
    "use_ssl": false,
    "test_email": "verify@example.com",
    "from_email": "notifications@example.com"
  }'

Response 200 OK

{
  "success": true,
  "status": "success",
  "message": "Test email sent successfully to verify@example.com. Please check your inbox to confirm delivery."
}

Response 500 β€” authentication failure

{
  "success": false,
  "status": "error",
  "message": "SMTP test failed: Authentication failed. Please check your username and password."
}

Response 500 β€” connection failure

{
  "success": false,
  "status": "error",
  "message": "SMTP test failed: Connection failed. Please check your host and port settings."
}

7.5 Sending Direct Notifications

Send notifications on demand to any combination of recipients on your platform. You select a template or write custom content, choose delivery channels, define your audience from multiple sources, preview the recipient list, and send.

Auth: Token, Platform Admin or Department Admin

Builder Flow
flowchart TD
    A([1. Get context]) --> B([2. Validate sources])
    B --> C([3. Preview])
    C --> D{Review recipients}
    D -- Looks good --> E([4. Send])
    D -- Adjust --> B
    C --> F([Browse recipients\npaginated])

    style A fill:#f5f5f5,stroke:#333
    style E fill:#f5f5f5,stroke:#333
Summary
MethodEndpointDescription
GET/orgs/{platform_key}/notification-builder/context/Get available templates, channels, and recipient source types
POST/orgs/{platform_key}/notification-builder/validate_source/Validate a recipient source before previewing
POST/orgs/{platform_key}/notification-builder/preview/Combine sources, deduplicate recipients, create a build
GET/orgs/{platform_key}/notification-builder/{build_id}/recipients/Browse paginated recipients for a build
POST/orgs/{platform_key}/notification-builder/send/Send the notification to all recipients in a build

GET /orgs/{platform_key}/notification-builder/context/

Returns the templates, channels, and recipient source types available on your platform. Call this first to populate your UI or to discover what IDs to use in subsequent requests.

Response 200 OK

{
  "status": "success",
  "data": {
    "templates": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "name": "Course Enrollment",
        "type": "USER_NOTIF_COURSE_ENROLLMENT"
      }
    ],
    "channels": [
      {"id": 1, "name": "email"},
      {"id": 2, "name": "push_notification"},
      {"id": 3, "name": "in_app"}
    ],
    "sources": [
      "email",
      "username",
      "platform",
      "csv",
      "department",
      "pathway",
      "program",
      "usergroup"
    ]
  }
}
curl -X GET \
  "https://your-domain.com/api/notification/v1/orgs/acme-learning/notification-builder/context/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN"

Recipient Source Types

You can target recipients from any combination of these sources. When you provide multiple sources in a preview request, recipients are merged and deduplicated.

Sourcedata valueDescription
emailComma-separated email addressesDirect email list. Validated against Django email rules.
usernameComma-separated usernamesPlatform usernames. Validated against your user records.
platformPlatform key (string)All users on your platform.
csvUploaded file (multipart)CSV file with an email column header.
departmentDepartment ID (integer)All active members of a department.
pathwayPathway ID (string)All suggested members of a pathway.
programProgram ID (string)All suggested members of a program.
usergroupUser Group ID (integer)All active members of a user group.

POST /orgs/{platform_key}/notification-builder/validate_source/

Validates a single recipient source and returns the valid count, any invalid entries, and a sample of resolved recipients. Call this per source before previewing to catch errors early.

Request body

FieldTypeRequiredDescription
typestringYesOne of the source types above
datastringYes (except CSV)The source value (emails, usernames, IDs, etc.)

For CSV sources, send as multipart form data with the file in a file_0 field.

curl -X POST \
  "https://your-domain.com/api/notification/v1/orgs/acme-learning/notification-builder/validate_source/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "email",
    "data": "jane@example.com,john@example.com,invalid-address"
  }'

Response 200 OK

{
  "status": "success",
  "valid_count": 2,
  "invalid_entries": ["invalid-address"],
  "sample_recipients": [
    {"username": "jane.doe", "email": "jane@example.com"},
    {"username": "john.smith", "email": "john@example.com"}
  ]
}

POST /orgs/{platform_key}/notification-builder/preview/

Combines all your sources, deduplicates recipients, and creates a build record. Returns a build_id you use to browse recipients and to send.

Request body

FieldTypeRequiredDescription
template_idUUIDNoID of an existing template. Mutually exclusive with template_data.
template_dataobjectNoCustom content: {"message_title": "...", "message_body": "..."}. Mutually exclusive with template_id.
channelsarray of integersYesChannel IDs from the context endpoint
sourcesarray of objectsYesEach object: {"type": "...", "data": "..."}
contextobjectNoCustom template variables (e.g. {"course_name": "Python 101"})
process_onISO 8601 datetimeNoSchedule send for a future time. If omitted, sends immediately on /send.

You must provide either template_id or template_data, not both. template_data.message_body supports template syntax ({{ variable }}).

curl -X POST \
  "https://your-domain.com/api/notification/v1/orgs/acme-learning/notification-builder/preview/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_data": {
      "message_title": "Platform Maintenance Notice",
      "message_body": "Hi {{ username }}, scheduled maintenance is planned for April 20."
    },
    "channels": [1, 3],
    "sources": [
      {"type": "usergroup", "data": "12"},
      {"type": "email", "data": "external-user@example.com"}
    ],
    "context": {}
  }'

Response 200 OK

{
  "status": "success",
  "build_id": "9c1a2b3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "count": 48,
  "warning": null,
  "recipients": [
    {"username": "jane.doe", "email": "jane@example.com", "status": "pending"},
    {"username": "john.smith", "email": "john@example.com", "status": "pending"}
  ]
}

Response fields

FieldTypeDescription
build_idUUIDUse this in /recipients and /send
countintegerTotal deduplicated recipients
warningstring or nullIf a similar notification was sent in the last 24 hours, this describes it
recipientsarrayFirst 10 recipients as a preview

GET /orgs/{platform_key}/notification-builder/{build_id}/recipients/

Paginated list of all recipients in a build. Use this to review the full audience before sending.

Query parameters

NameTypeRequiredDescription
searchstringNoFilter by username or email (case-insensitive)
pageintegerNoPage number (default: 1)
page_sizeintegerNoResults per page (default: 10)
curl -X GET \
  "https://your-domain.com/api/notification/v1/orgs/acme-learning/notification-builder/9c1a2b3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d/recipients/?page=1&page_size=20" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN"

Response 200 OK

{
  "count": 48,
  "next": "https://your-domain.com/...?page=2&page_size=20",
  "previous": null,
  "results": [
    {"username": "jane.doe", "email": "jane@example.com", "status": "pending"},
    {"username": "john.smith", "email": "john@example.com", "status": "pending"}
  ]
}

POST /orgs/{platform_key}/notification-builder/send/

Sends the notification to all recipients in the build. If process_on was set during preview and is in the future, the notification is queued for scheduled delivery.

Request body

FieldTypeRequiredDescription
build_idstring (UUID)YesThe build ID from the preview response
curl -X POST \
  "https://your-domain.com/api/notification/v1/orgs/acme-learning/notification-builder/send/" \
  -H "Authorization: Token YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"build_id": "9c1a2b3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d"}'

Response 200 OK

{
  "status": "success",
  "notifications_sent": 48,
  "build_id": "9c1a2b3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "message": "Notifications sent"
}

Possible message values:

MessageMeaning
"Notifications sent"Delivered immediately
"Notifications queued"Scheduled for future delivery (process_on is in the future)
"Similar notifications found"A matching notification was already sent in the last 24 hours
Duplicate Detection

The system generates a SHA-256 hash from the combination of recipients, template, and channels. If an identical notification was sent in the last 24 hours, the preview response includes a warning and the send response returns "Similar notifications found" instead of sending again.

Build Status Lifecycle
stateDiagram-v2
    [*] --> draft : preview created
    draft --> previewed : recipients resolved
    previewed --> sending : send requested
    previewed --> queued : scheduled for later
    queued --> sending : process_on reached
    sending --> completed : all delivered
    sending --> failed : error during delivery

8. Template System

8.1 How Templates Work

Every notification type ships with a default template. You do not have your own template record for a type until you customize it. Until that point, your platform inherits the default template β€” reads return it with "is_inherited": true in the response.

The system creates your own copy the first time you edit a template via PATCH. The default template's content and channel settings are copied into a new record for your platform, then your edits are applied. Subsequent PATCH requests update your copy directly.

Toggle state (enabled/disabled) is a separate record from the template content. Enabling or disabling a notification type does not affect the template, and resetting a template does not affect the toggle.

Reset deletes your customized template. Your platform immediately reverts to inheriting the default template ("is_inherited": true).

sequenceDiagram
    participant Admin
    participant API
    participant DB

    Admin->>API: PATCH /platforms/{platform_key}/templates/{type}/

    API->>DB: Lookup template for (type, platform)

    alt No platform copy exists
        DB-->>API: DoesNotExist
        API->>DB: Fetch default template
        DB-->>API: default template
        API->>DB: Create platform copy
        API->>DB: Copy channels + SPAs
    else Platform copy exists
        DB-->>API: existing platform template
    end

    API->>DB: Apply PATCH fields
    DB-->>API: updated template
    API-->>Admin: 200 OK

8.2 Template Variables

Templates use Django template syntax. The rendering pipeline auto-loads the notification_template_tags library, so its tags are available without explicit {% load %}.

Global Variables (available in every template)
VariableDescription
site_namePlatform name
site_urlPlatform URL
site_logo_urlPlatform logo URL
platform_namePlatform name (capitalized)
support_emailPlatform support email
privacy_urlPrivacy policy URL
terms_urlTerms of use URL
logo_urlPlatform logo URL
current_yearCurrent year
base_domainBase domain of the platform
skills_urlSkills platform URL
unsubscribe_urlCampaign unsubscribe URL
Common User Variables
VariableDescription
usernameRecipient's username
login_urlLogin or redirect URL
login_pathPath portion of the login URL
Variables by Notification Type

Registration

TypeVariableDescription
APP_REGISTRATIONapp_nameApplication name
APP_REGISTRATIONwelcome_messageWelcome message text
APP_REGISTRATIONbenefitsList of benefit strings
APP_REGISTRATIONclosing_messageClosing message text
USER_NOTIF_USER_REGISTRATIONwelcome_messageWelcome message
USER_NOTIF_USER_REGISTRATIONnext_stepsNext-step instructions

Course Notifications

TypeVariableDescription
USER_NOTIF_COURSE_ENROLLMENTcourse_nameCourse name
ADMIN_NOTIF_COURSE_ENROLLMENTcourse_nameCourse name
ADMIN_NOTIF_COURSE_ENROLLMENTstudent_nameEnrolled student's name
ADMIN_NOTIF_COURSE_ENROLLMENTstudent_emailEnrolled student's email
USER_NOTIF_COURSE_COMPLETIONcourse_nameCourse name
USER_NOTIF_COURSE_COMPLETIONcompletion_dateDate of completion
USER_NOTIF_COURSE_COMPLETIONcertificate_urlCertificate URL
USER_NOTIF_USER_INACTIVITYdays_inactiveDays inactive
USER_NOTIF_USER_INACTIVITYlast_activity_dateLast activity date

Learner Progress

TypeVariableDescription
USER_NOTIF_LEARNER_PROGRESScourses_takenList of courses
USER_NOTIF_LEARNER_PROGRESSvideos_watched_countVideos watched
USER_NOTIF_LEARNER_PROGRESStotal_time_spentTotal time spent (hours)
USER_NOTIF_LEARNER_PROGRESScredentialsCredentials earned

Credentials

TypeVariableDescription
USER_NOTIF_CREDENTIALSitem_nameCourse or program name
USER_NOTIF_CREDENTIALScredential_urlFull credential URL
USER_NOTIF_CREDENTIALScredential_pathCredential path

Invitations

TypeVariableDescription
PLATFORM_INVITATIONredirect_toRedirect destination after signup
COURSE_INVITATIONcourse_nameCourse name
PROGRAM_INVITATIONprogram_nameProgram name

Licenses

TypeVariableDescription
COURSE_LICENSE_ASSIGNMENTcourse_nameCourse name
PROGRAM_LICENSE_ASSIGNMENTprogram_nameProgram name
USER_LICENSE_ASSIGNMENTwelcome_messageWelcome text
USER_LICENSE_ASSIGNMENTbenefitsBenefit list
USER_LICENSE_ASSIGNMENTclosing_messageClosing text

Role and Policy

TypeVariableDescription
ROLE_CHANGEroleNew role name
ROLE_CHANGEdemotedTrue if user was demoted
POLICY_ASSIGNMENTrole_nameRole being assigned/removed
POLICY_ASSIGNMENTassignedTrue if assigned, False if removed
POLICY_ASSIGNMENTresourcesList of affected resources

Human Support

TypeVariableDescription
HUMAN_SUPPORT_NOTIFICATIONticket_subjectTicket subject
HUMAN_SUPPORT_NOTIFICATIONticket_descriptionTicket description
HUMAN_SUPPORT_NOTIFICATIONticket_statusTicket status
HUMAN_SUPPORT_NOTIFICATIONuser_nameUser who created the ticket
HUMAN_SUPPORT_NOTIFICATIONuser_emailUser's email
HUMAN_SUPPORT_NOTIFICATIONmentor_nameMentor name
HUMAN_SUPPORT_NOTIFICATIONplatform_keyPlatform identifier
HUMAN_SUPPORT_NOTIFICATIONsession_idChat session UUID
HUMAN_SUPPORT_NOTIFICATIONchat_linkURL to chat transcript
HUMAN_SUPPORT_NOTIFICATIONmentor_unique_idUnique identifier of the mentor
HUMAN_SUPPORT_NOTIFICATIONtemplate_contentOptional custom content (rendered if provided)

AI / Proactive Learner

TypeVariableDescription
PROACTIVE_LEARNER_NOTIFICATIONstudent_nameLearner's display name
PROACTIVE_LEARNER_NOTIFICATIONstudent_emailLearner's email
PROACTIVE_LEARNER_NOTIFICATIONmentor_nameMentor name
PROACTIVE_LEARNER_NOTIFICATIONai_recommendationAI-generated recommendation text
PROACTIVE_LEARNER_NOTIFICATIONusernameLearner's username
PROACTIVE_LEARNER_NOTIFICATIONplatform_keyPlatform identifier
PROACTIVE_LEARNER_NOTIFICATIONmentor_unique_idUnique identifier of the mentor

Report

TypeVariableDescription
REPORT_COMPLETEDreport_nameReport display name
REPORT_COMPLETEDreport_statuscompleted, error, or cancelled
REPORT_COMPLETEDdownload_urlDownload URL (completed reports only)
Template Syntax

Variable interpolation:

Hello {{ username }}, you have been enrolled in {{ course_name }}.

Conditionals:

{% if demoted %}
Your role has been removed.
{% else %}
You have been granted the {{ role }} role.
{% endif %}

Iterating lists:

{% for benefit in benefits %}
- {{ benefit }}
{% endfor %}

Rendering example:

Template source:

Dear {{ username }},

You have earned a credential for completing {{ item_name }}.
View your credential here: {{ credential_url }}

Β© {{ current_year }} {{ platform_name }}

Rendered output (with username="jsmith", item_name="Python Fundamentals", credential_url="https://skills.example.com/credentials/abc123", current_year=2026, platform_name="Acme Learning"):

Dear jsmith,

You have earned a credential for completing Python Fundamentals.
View your credential here: https://skills.example.com/credentials/abc123

Β© 2026 Acme Learning

8.3 Customizing Templates

You can customize any editable template via PATCH. The first PATCH creates your own copy of the default; subsequent requests update that copy.

Editable fields: name, description, message_title, message_body, short_message_body, email_subject, email_from_address, email_html_template, spa_ids, channel_ids

For system-managed notification types (PROACTIVE_LEARNER_NOTIFICATION, POLICY_ASSIGNMENT, HUMAN_SUPPORT_NOTIFICATION), only configuration fields are editable β€” message_body, short_message_body, and email_html_template are read-only.

HTML Sanitization

The email_html_template field is sanitized using bleach before rendering.

Allowed tags: a, abbr, b, blockquote, br, code, div, em, h1–h6, hr, i, img, li, ol, p, pre, span, strong, sub, sup, table, tbody, td, th, thead, tr, u, ul, main, footer

Allowed attributes:

Allowed URL protocols: http, https, mailto

Elements like