> ## Documentation Index
> Fetch the complete documentation index at: https://theteam-13fc7f49.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Notifications Endpoints

##### *Notification System — Backend Documentation*

## Table of Contents

* **Overview**
* **How It Works**
  * **SMTP Rule**
* **Configuration**
  * `smtp_threshold`
  * `batch_size`
* **Notification Types**
* **Request Body Fields**
* **Postman Examples**
  * **1. Send to a Single User (In-App Only)**
  * **2. Send to Multiple Specific Users**
  * **3. Send to a Single User + Email (SMTP)**
  * **4. Send to an Entire Role (e.g., All Students)**
  * **5. Send to Multiple Roles**
  * **6. Send to an Entire Company**
  * **7. Send to Multiple Companies**
  * **8. One Target per Request (No Combining)**
  * **9. Scheduled Notification (Future)**
  * **10. Scheduled + SMTP to a Single User**
  * **11. Each Notification Type — Quick Reference Payloads**
* **Other Notification Endpoints**
* **Architecture Summary**
* **Postman Setup Tips**
* **Common Error Responses**

***

## Overview

> **Boot list (19/10/2026):** `GET /auth/user` ships only the **3** newest non-archived notifications
> (`id`, `student_id`, `title`, `message`, `notification_type_id`, `notif_read_status`,
> `notif_archive_status`, `created_at`) plus `notification_count` (unread). The bell popup / notifications
> page load more with `GET /notifications/user/{user_id}?per_page=10&page=1` (see "Other Notification
> Endpoints"). It used to be the 10 newest rows with every column.

All notification sending goes through a **single unified endpoint**:

```text theme={null}
POST /api/notifications/send
```

This endpoint handles every scenario: sending to individual users, entire roles, full companies, with or without email (SMTP), and with optional scheduling.

**Authentication**: Bearer token required (Laravel Sanctum).

**Headers** (for all requests):

```json theme={null}
Authorization: Bearer {{token}}
Content-Type: application/json
Accept: application/json
```

***

## How It Works

1. The request hits `NotificationController@sendUnified`
2. `SendUnifiedNotificationRequest` validates the payload
3. `NotificationService::resolveRecipients()` collects the target user IDs from the **one** target sent: `user_ids`, `role_ids` or `company_ids` (`user_ids` and `role_ids` only match users of the sender's company)
4. `NotificationService::createDispatch()` creates the dispatch record and individual notification rows **in chunks of** `batch_size`
5. If `scheduled_at` is set and is in the future → a `ProcessNotificationDispatch` job is queued with a delay
6. Otherwise → `NotificationService::sendNow()` fires immediately

### SMTP Rule

| Target type | `notif_smtp_status` behavior |
| :- | :- |
| `user_ids` only, recipient count ≤ `smtp_threshold` | Respected — you control it |
| `user_ids` only, recipient count > `smtp_threshold` | **Forced to**`false` — too many recipients (configurable threshold) |
| `role_ids` or `company_ids` | **Forced to**`false` — no bulk email |

The original guard blocks SMTP for role/company targets. The `smtp_threshold` adds a second layer: even when targeting `user_ids` directly, if the resolved recipient count exceeds the threshold, SMTP is forced off and a warning is logged. This prevents accidental mass email blasts through the "allowed" path.

This is enforced in `NotificationService::sendNow()` — see the **Configuration** section below.

***

## Configuration

Two runtime-tunable values are extracted into `config/notifications_config.php` so they can be changed via environment variables without touching application code.

```php theme={null}
<?php
// config/notifications_config.php

return [
    'smtp_threshold' => env('NOTIF_SMTP_THRESHOLD', 20), // changeable later
    'batch_size'     => env('NOTIF_BATCH_SIZE', 1000),   // create Notifications in chunks
];
```

```shellscript theme={null}
# .env (optional overrides)
######### Notifs - Config #############
NOTIF_SMTP_THRESHOLD=20
NOTIF_BATCH_SIZE=1000
######### Notifs - Config #############
```

### `smtp_threshold`

**Default:** `20`

After `resolveRecipients()` produces the final user list, `sendNow()` checks the count. If it exceeds `smtp_threshold`, `notif_smtp_status` is forced to `false` — regardless of what was passed in the request — and a warning is logged.

```php theme={null}
// NotificationService.php — sendNow()

$threshold = config('notifications_config.smtp_threshold');

if ($smtpEnabled && count($recipientIds) > $threshold) {
    Log::warning('SMTP suppressed: recipient count exceeds threshold', [
        'count'     => count($recipientIds),
        'threshold' => $threshold,
    ]);
    $smtpEnabled = false;
}
```

### `batch_size`

**Default:** `1000`

When creating `Notification` rows in bulk, a single `Notification::insert()` on thousands of rows causes PHP memory exhaustion and can hit DB statement size limits. The full recipient list is split with `array_chunk()` and inserted in separate queries.

```php theme={null}
// NotificationService.php — createDispatch()

$batchSize = config('notifications_config.batch_size');
$rows = []; // build your notification row array as before

foreach (array_chunk($rows, $batchSize) as $chunk) {
    Notification::insert($chunk);
}
```

> The defaults in `notifications_config.php` are used when the `.env` keys are absent — so existing deployments that haven't set them will automatically behave as if they were set to `20` and `1000` respectively.

***

## Notification Types

These are stored in the `notification_types` table. Use the `id` value in `notification_type_id`:

| ID | Label | Use case |
| :- | :- | :- |
| 1 | Success | Positive confirmations |
| 2 | Danger | Critical alerts |
| 3 | Warning | Caution notices |
| 4 | Notify | General info |
| 5 | Assignment | New assignment posted |
| 6 | Grade | Grades released |
| 7 | Quiz | Upcoming quiz alerts |
| 8 | Announcement | General announcements |
| 9 | Reminder | Deadline/event reminders |
| 10 | Deadline | Upcoming or missed deadlines |
| 11 | Course Update | Course content changes |
| 12 | New Course | New course available |
| 13 | Enrollment | Enrollment confirmations/invitations |

***

## Request Body Fields

| Field | Type | Required | Description |
| :- | :- | :- | :- |
| `title` | string | Yes | Notification title |
| `message` | string | Yes | Notification body/content |
| `notification_type_id` | integer | Yes | One of the type IDs above (1–13) |
| `company_id` | integer | No | The company context. Not a validated field of this endpoint, but the company check refuses a `company_id` other than the sender's (Super Admin excepted). The app always sends it |
| `user_ids` | array\[int] | No\* | Specific user IDs to target |
| `role_ids` | array\[int] | No\* | Role IDs (`1` Student, `2` Instructor, `3` Content Manager, `4` Admin, `5` Super Admin) — every user of the sender's company with one of these roles. Each id must exist in `roles` |
| `company_ids` | array\[int] | No\* | Company IDs — all users in these companies |
| `notif_smtp_status` | boolean | No | Send email too? (only works with `user_ids` ≤ `smtp_threshold`) |
| `scheduled_at` | datetime | No | ISO 8601 / `Y-m-d H:i:s` — schedule for later |

> \***Exactly one** of `user_ids`, `role_ids` or `company_ids` must be a non-empty array; leave the others empty or out. Sending none, or two of them, is a `422` on the `target` key (see example 8).

***

## Postman Examples

### 1. Send to a Single User (In-App Only)

The simplest case — one user, no email, no scheduling.

```json theme={null}
POST /api/notifications/send

{
    "title": "Welcome aboard!",
    "message": "Your account has been set up successfully.",
    "notification_type_id": 1,
    "company_id": 1,
    "user_ids": [5]
}
```

**Expected response (201):**

```json theme={null}
{
    "message": "Notifications sent successfully.",
    "dispatch": { ... }
}
```

***

### 2. Send to Multiple Specific Users

```json theme={null}
POST /api/notifications/send

{
    "title": "Team meeting tomorrow",
    "message": "Don't forget our sync at 10 AM.",
    "notification_type_id": 9,
    "company_id": 1,
    "user_ids": [2, 5, 8, 12]
}
```

***

### 3. Send to a Single User + Email (SMTP)

Set `notif_smtp_status` to `true`. This only works when targeting `user_ids` (not roles/companies) **and** when the recipient count does not exceed `smtp_threshold`.

```json theme={null}
POST /api/notifications/send

{
    "title": "Your certificate is ready",
    "message": "Download your certificate from the platform.",
    "notification_type_id": 1,
    "company_id": 1,
    "user_ids": [5],
    "notif_smtp_status": true
}
```

> Make sure SMTP settings are configured via `POST /api/platform/smtp-settings` before testing this.

***

### 4. Send to an Entire Role (e.g., All Students)

Role IDs are fixed by the seeder and by the `Role` constants in the backend:

| Id | Role |
| :-: | :- |
| `1` | Student (labelled "User" in the `roles` table) |
| `2` | Instructor |
| `3` | Content Manager |
| `4` | Admin |
| `5` | Super Admin |

The app's **Reminders** screen sends the same ids: *All students* → `1`, *All instructors* → `2`, *All content creators* → `3`, *All admins* → `4`. Its *Everyone* option is not a role: the app sends `company_ids: [<your company>]` instead (example 6).

```json theme={null}
POST /api/notifications/send

{
    "title": "New course available!",
    "message": "Check out our latest Python course.",
    "notification_type_id": 12,
    "company_id": 1,
    "role_ids": [1]
}
```

> `notif_smtp_status` is **forced to false** here even if you pass `true`.

***

### 5. Send to Multiple Roles

Notify all instructors and students at once:

```json theme={null}
POST /api/notifications/send

{
    "title": "Platform maintenance tonight",
    "message": "The platform will be down from 11 PM to 2 AM.",
    "notification_type_id": 3,
    "company_id": 1,
    "role_ids": [1, 2]
}
```

***

### 6. Send to an Entire Company

Every user in company ID 1:

```json theme={null}
POST /api/notifications/send

{
    "title": "Happy New Year!",
    "message": "Wishing everyone a great 2026.",
    "notification_type_id": 8,
    "company_id": 1,
    "company_ids": [1]
}
```

> SMTP is also **forced off** for company-wide broadcasts.

***

### 7. Send to Multiple Companies

If you have a multi-tenant setup:

```json theme={null}
POST /api/notifications/send

{
    "title": "System update",
    "message": "Version 3.2 is now live across all platforms.",
    "notification_type_id": 11,
    "company_id": 1,
    "company_ids": [1, 2, 3]
}
```

***

### 8. One Target per Request (No Combining)

You can't mix targets in one request. This body, sending to two users **and** the student role, is refused:

```json theme={null}
POST /api/notifications/send

{
    "title": "Exam schedule published",
    "message": "The final exam schedule is now available.",
    "notification_type_id": 10,
    "company_id": 1,
    "user_ids": [7, 9],
    "role_ids": [1]
}
```

**Response (422):**

```json theme={null}
{
    "message": "Exactly one of company_ids, role_ids, or user_ids must be a non-empty array. The others must be empty or omitted.",
    "errors": {
        "target": [
            "Exactly one of company_ids, role_ids, or user_ids must be a non-empty array. The others must be empty or omitted."
        ]
    }
}
```

Send two requests instead: one with `"role_ids": [1]`, one with `"user_ids": [7, 9]` (the second one may also use `notif_smtp_status`).

***

### 9. Scheduled Notification (Future)

Send a reminder that gets delivered at a specific time:

```json theme={null}
POST /api/notifications/send

{
    "title": "Exam starts in 1 hour",
    "message": "Your JavaScript exam begins at 3 PM. Good luck!",
    "notification_type_id": 9,
    "company_id": 1,
    "user_ids": [5, 8, 12],
    "scheduled_at": "2026-04-10 14:00:00"
}
```

**Expected response (201):**

```json theme={null}
{
    "message": "Notification scheduled.",
    "dispatch": { ... }
}
```

> The `scheduled_at` datetime is parsed in `Africa/Tunis` timezone. If the datetime is in the past, it sends immediately instead of scheduling.

***

### 10. Scheduled + SMTP to a Single User

```json theme={null}
POST /api/notifications/send

{
    "title": "Payment due reminder",
    "message": "Your subscription renews on April 15. Please ensure payment is ready.",
    "notification_type_id": 10,
    "company_id": 1,
    "user_ids": [5],
    "notif_smtp_status": true,
    "scheduled_at": "2026-04-14 09:00:00"
}
```

***

### 11. Each Notification Type — Quick Reference Payloads

**Danger (2):**

```json theme={null}
{
    "title": "Account suspended",
    "message": "Your account has been flagged for review.",
    "notification_type_id": 2,
    "company_id": 1,
    "user_ids": [7]
}
```

**Warning (3):**

```json theme={null}
{
    "title": "Disk space running low",
    "message": "R2 storage is at 90% capacity.",
    "notification_type_id": 3,
    "company_id": 1,
    "role_ids": [4]
}
```

**Assignment (5):**

```json theme={null}
{
    "title": "New assignment posted",
    "message": "Chapter 3 exercises are now available.",
    "notification_type_id": 5,
    "company_id": 1,
    "role_ids": [1]
}
```

**Grade (6):**

```json theme={null}
{
    "title": "Grades released",
    "message": "Your midterm results are ready to view.",
    "notification_type_id": 6,
    "company_id": 1,
    "user_ids": [10, 11, 12]
}
```

**Quiz (7):**

```json theme={null}
{
    "title": "Quiz available",
    "message": "Chapter 5 quiz is now open. You have 30 minutes.",
    "notification_type_id": 7,
    "company_id": 1,
    "role_ids": [1]
}
```

***

## Other Notification Endpoints

These manage notifications **after** they've been sent.

### Mark as Read

```json theme={null}
POST /api/notifications/{id}/read
Body: { "company_id": 1 }
```

### Mark as Unread

```json theme={null}
POST /api/notifications/{id}/unread
Body: { "company_id": 1 }
```

### Mark All as Read (per user)

```json theme={null}
POST /api/notifications/user/{user_id}/mark-all-read?company_id=1
```

### Archive

```json theme={null}
POST /api/notifications/{id}/archive
Body: { "company_id": 1 }
```

### Unarchive

```json theme={null}
POST /api/notifications/{id}/unarchive
Body: { "company_id": 1 }
```

### Get Notifications by User

```json theme={null}
GET /api/notifications/user/{user_id}?company_id=1&per_page=15&page=1
```

Returns paginated notifications + `unread_count`.

### Get Notifications by Company

```json theme={null}
POST /api/notifications/company
Body: { "company_id": 1, "per_page": 20 }
```

### Get Notifications by Role

```json theme={null}
GET /api/notifications/role/{role_id}?company_id=1&per_page=15
```

### Get Single Notification

```json theme={null}
POST /api/notifications/{id}
Body: { "company_id": 1 }
```

### Delete Notification

```json theme={null}
DELETE /api/notifications/{id}?company_id=1
```

***

## Architecture Summary

```php theme={null}
Request
  → SendUnifiedNotificationRequest (validation)
  → NotificationController@sendUnified
    → NotificationService::resolveRecipients()
      (exactly one target: user_ids, or the users with role_ids, or the users of company_ids)
    → NotificationService::createDispatch()
      (creates NotificationDispatch + individual Notification rows)
      (inserts Notification rows in chunks of batch_size)
    → If scheduled_at is future:
        ProcessNotificationDispatch job queued with delay
    → Else:
        NotificationService::sendNow()
          (check recipient count vs smtp_threshold → force SMTP off if exceeded)
          (delivers in-app + SMTP email if applicable)
```

### Key Models

| Model | Table | Purpose |
| :- | :- | :- |
| `Notification` | `notifications` | Individual notification per user |
| `NotificationType` | `notification_types` | Type labels (success, danger, etc.) |
| `NotificationDispatch` | `notification_dispatches` | Groups a batch send |

### Key Files

| File | Purpose |
| :- | :- |
| `config/notifications_config.php` | Runtime-tunable thresholds (`smtp_threshold`, `batch_size`) |
| `app/Http/Controllers/NotificationController.php` | All notification endpoints |
| `app/Services/NotificationService.php` | Core send logic, recipient resolution, threshold guard, chunked inserts |
| `app/Http/Requests/SendUnifiedNotificationRequest.php` | Validation rules |
| `app/Jobs/ProcessNotificationDispatch.php` | Queued/scheduled delivery |
| `app/Mail/NotificationEmail.php` | Email template (Mailable) |
| `app/Models/Notification.php` | Notification model |
| `app/Models/NotificationType.php` | Type constants & model |

***

## Postman Setup Tips

1. **Environment variables** — set `{{base_url}}` (e.g., `http://localhost:8000/api`) and `{{token}}`
2. **Get a token** — call `POST {{base_url}}/auth/login` first and grab the token from the response
3. **Role IDs** — `1` Student, `2` Instructor, `3` Content Manager, `4` Admin, `5` Super Admin (`SELECT * FROM roles;` shows the same rows)
4. **Check your users table** — run `SELECT id, first_name, email, role_id FROM users;` to get valid user IDs
5. **SMTP testing** — configure SMTP first via `POST /api/platform/smtp-settings`, then test with `POST /api/platform/test-smtp` before trying `notif_smtp_status: true`

***

## Common Error Responses

| Status | Meaning | Likely cause |
| :- | :- | :- |
| 401 | Unauthenticated | Missing or expired Bearer token |
| 404 | No recipients resolved | The user\_ids/role\_ids/company\_ids matched zero users |
| 422 | Validation error | Missing required fields, invalid types, an unknown id, or not exactly one of `user_ids` / `role_ids` / `company_ids` (`target` error) |
| 500 | Server error | SMTP misconfigured, DB issue, etc. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.