Skip to main content

Notifications Module

The in‑app alert engine – real‑time updates, order status, support replies, and data export completions.

In-App Read Receipts IDOR


📖 Table of Contents


Base Route : /api/v1/notifications

All endpoints are private (require a valid access token) and are rate‑limited (100 requests per 15 minutes per IP).


Endpoints Overview

MethodEndpointAccessDescription
GET/Private (Bearer)Fetch the authenticated user's in‑app notifications (paginated, newest first)
PATCH/:notificationId/readPrivate (Bearer)Mark a specific notification as read (ownership enforced)

Endpoint Details

GET /

Retrieve the user's in‑app notification history. Notifications are created for events such as:

  • Order status updates (shipped, delivered, cancelled)
  • Support ticket replies
  • Data export completion
  • Password change confirmation

Headers: Authorization: Bearer <access_token>

Query parameters (optional):

ParamTypeDefaultMaxDescription
pageinteger1Page number (1‑based)
limitinteger20100Items per page (capped at 100)
unreadOnlybooleanfalseIf true, returns only unread notifications

Example request:

GET /api/v1/notifications?page=1&limit=20&unreadOnly=true

Response (200 OK):

{
"success": true,
"statusCode": 200,
"message": "Notifications retrieved successfully",
"data": {
"notifications": [
{
"_id": "64a7b...",
"type": "ORDER_STATUS",
"title": "Order #ORD-12345 has been shipped",
"message": "Your order has been dispatched. Tracking ID: AWB123456",
"isRead": false,
"metadata": {
"orderId": "64a7c...",
"trackingNumber": "AWB123456"
},
"createdAt": "2026-05-22T14:30:00.000Z"
},
{
"_id": "64a7d...",
"type": "SUPPORT_REPLY",
"title": "New reply on ticket #TCK-9A4B2",
"message": "Admin has replied to your support ticket.",
"isRead": true,
"metadata": {
"ticketId": "TCK-9A4B2"
},
"createdAt": "2026-05-21T10:15:00.000Z"
}
],
"meta": {
"total": 5,
"unreadCount": 2,
"limit": 20,
"page": 1
}
},
"timestamp": "2026-05-22T15:00:00.000Z"
}

Notifications are automatically created by various services (OrderService, SupportService, ExportQueueManager). The user does not create them directly.

PATCH /:notificationId/read

Mark a single notification as read. The endpoint verifies that the notification belongs to the authenticated user (IDOR protection) before updating.

Headers: Authorization: Bearer <access_token>

URL Parameter:

  • notificationId – valid MongoDB ObjectId of the notification.

Request body: None (empty).

Response (200 OK):

{
"success": true,
"statusCode": 200,
"message": "Notification marked as read",
"data": {
"_id": "64a7b...",
"isRead": true,
"readAt": "2026-05-22T15:05:00.000Z"
},
"timestamp": "2026-05-22T15:05:00.000Z"
}

Error cases:

  • Notification not found → 404 Not Found
  • Notification belongs to another user → 403 Forbidden (IDOR protection)

Validation & Security

ConcernMitigation
IDOR (Insecure Direct Object Reference)PATCH /:notificationId/read checks that the notification's userId matches req.user._id. Returns 403 if mismatched.
NoSQL injectionnotificationId is validated as a 24‑hex ObjectId via Zod in the route (implicitly or via controller).
Rate limitingstandardLimiter (100/15min) prevents enumeration of notification IDs.
Pagination abuselimit is capped at 100.

Zod validation (implied – add if not present):

const MarkNotificationReadSchema = z.object({
params: z.object({
notificationId: z.string().regex(/^[0-9a-fA-F]{24}$/, "Invalid notification ID format"),
}),
});

Response Structure (GET /)

FieldTypeDescription
notifications[]._idstringNotification unique ID
notifications[].typestringORDER_STATUS, SUPPORT_REPLY, EXPORT_READY, SECURITY_ALERT, etc.
notifications[].titlestringShort summary
notifications[].messagestringDetailed description (safe to display)
notifications[].isReadbooleanRead status
notifications[].metadataobjectOptional contextual data (orderId, ticketId, fileUrl, etc.)
notifications[].createdAtstring (ISO)When the notification was generated
meta.totalnumberTotal notifications matching the query
meta.unreadCountnumberNumber of unread notifications (regardless of pagination)
meta.limitnumberRequested limit
meta.pagenumberCurrent page

Notification Types (Examples)

TypeTriggerExample title
ORDER_STATUSOrder shipped, delivered, cancelledOrder #ORD-123 has been shipped
SUPPORT_REPLYAdmin replies to user's ticketNew reply on ticket #TCK-9A4B2
EXPORT_READYData export job completesYour data export is ready for download
SECURITY_ALERTPassword change, login from new deviceYour password was changed successfully
RETURN_STATUSReturn approved or rejectedReturn request #RET-456 has been approved

The frontend can use the type field to show different icons or handle actions (e.g., navigate to order detail on click).


Error Responses

StatusCodeExample messageWhen
400BAD_REQUEST"Invalid notification ID format"Invalid ObjectId in URL
401UNAUTHORIZED"Authentication required"Missing or invalid token
403FORBIDDEN"You do not have permission to access this notification"IDOR violation
404NOT_FOUND"Notification not found"Notification ID does not exist
429TOO_MANY_REQUESTS"Too many requests, please try again later."Rate limit exceeded

Runbook

For manual testing with Thunder Client / Postman, see ../../testing/notification-runbook.md (if created). The runbook covers:

  • Fetching paginated notifications
  • Filtering unread notifications
  • Marking a notification as read
  • IDOR test (trying to mark another user's notification)


Stay informed, never miss a beat – the Reshma‑Core notification engine.