API Reference (9 files updated): - Marketplace API: corrected offer endpoints (scoped under /purchase-requests/:id/offers), marked phantom /search /stats /seller/:sellerId /withdraw routes as NOT IMPLEMENTED, documented PUT→PATCH mismatches, removed invalid SellerOffer 'active' status - Dispute API: corrected resolve schema (action enum), categories (no 'fraud'), removed 'under_review' status, added security callouts (3 unguarded endpoints), route shadowing documented, all socket events marked as TODO stubs - Notification API: corrected mark-all-read method+path, fixed broken GET /:id, added unread-count-update event, 90-day TTL documented - Payment API: /create→/save, removed 10+ phantom endpoints, fixed release/refund paths (no /shkeeper/ segment), added 3 unauthenticated endpoint security warnings, stats undercounting documented, export privilege gap documented - Authentication API: 8-digit→6-digit code, no-complexity warning on reset-with-code, rate limiter counts all attempts, passkey stub claims removed, deleteAccount bug noted - Admin API: PUT→PATCH bug documented, wrong status values documented, hard vs soft delete clarified, scanner no-auth security bug, 3 NOT IMPLEMENTED endpoints - Chat API: file upload wrong endpoint bug, archive PUT→PATCH bug, rate limits added - Points API: corrected redeem schema, referral triggers on 'completed' only, leaderboard period ignored, removed 'refund' PointTransaction type - Socket Events: removed request-cancelled, notification-read; added unread-count-update; dispute events all stubs; referral-signup is auth-domain not points-domain Data Models (3 files updated): - SellerOffer: removed 'active' from status enum, withdrawOffer() is dead code - PurchaseRequest: added pending_payment/active statuses, added 'urgent' urgency, corrected description minimum (5 chars), removed finalized/archived - Dispute: corrected action enum, categories (no fraud), removed under_review, security callout on unguarded status/resolve endpoints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.8 KiB
title, tags
| title | tags | |||
|---|---|---|---|---|
| Notification API |
|
Notification API
Last updated: 2026-05-29 — aligned with code (see Doc vs Code Audit Report)
Endpoints live under /api/notifications/*. Two routers are mounted:
- New controller pattern:
notificationControllerRoutes.ts(controller-backed, requires auth) - Legacy:
notification/routes.ts(no auth gate — userId is passed in query/body)
Both routers are mounted at /api, so the paths collide; the controller router wins for the shared paths (it is mounted first). The legacy router is still used by background scripts and admin tools that have no JWT context.
Model: Notification. Notifications are auto-deleted after 90 days. Real-time delivery is via new-notification and unread-count-update Socket.IO events on user-<userId>. See Socket Events.
List
GET /api/notifications
Description: Paginated notifications for the caller.
Auth required: Bearer JWT (controller route); legacy variant takes ?userId=....
Query params:
page(default 1)limit(default 20)unreadOnly(true|false, defaultfalse) Response 200:
{
"success": true,
"data": {
"notifications": [Notification, ...],
"pagination": { "page": 1, "limit": 20, "total": 42, "hasMore": true }
}
}
GET /api/notifications/unread-count
Description: Just the integer unread count.
Auth required: Bearer JWT
Response 200: { "success": true, "data": { "unreadCount": 5 } }
GET /api/notifications/:id
Description: Single notification by id. Available on the controller router.
Auth required: Bearer JWT
Errors: 404 not found, 403 not owner.
⚠️ KNOWN BUG: The controller fetches only the 1 most-recent notification for the user and does an in-memory ID match. Any notification that is not the user's single latest will return
404even if it exists and belongs to the user. Do not rely on this endpoint for fetching arbitrary notifications by id.
Mutations
PATCH /api/notifications/:id/read
Description: Mark one notification as read.
Auth required: Bearer JWT (controller); legacy variant requires { userId } in body.
Response 200: { success: true, data: { /* updated notification */ } }
Side effects: Emits unread-count-update to user-<userId>.
PATCH /api/notifications/mark-all-read
Description: Mark every notification for the caller as read.
Auth required: Bearer JWT
Response 200: { "success": true, "data": { "modifiedCount": 12 } }
Note: Earlier versions of this documentation incorrectly listed this as
POST /api/notifications/read-all. The correct path and method arePATCH /notifications/mark-all-read.
PATCH /api/notifications/bulk/mark-read
Description: Mark a list of notifications as read.
Auth required: Bearer JWT
Request body: { ids: string[] }
Response 200: { success, data: { modifiedCount } }
DELETE /api/notifications/:id
Description: Delete a notification.
Auth required: Bearer JWT
Errors: 404 not found.
DELETE /api/notifications/bulk/delete
Description: Bulk delete.
Auth required: Bearer JWT
Request body: { ids: string[] }
POST /api/notifications
Description: Create a notification. Primarily used by other services and admin tools. Auth required: Bearer JWT (controller); legacy variant is open. Request body:
{
userId: string;
type: string; // e.g. "order_update", "chat_message", "payment_received"
title: string;
body?: string;
data?: Record<string, unknown>;
channel?: "in_app" | "email" | "push";
}
Response 201: { success, data: { notification } }
Side effects: Emits new-notification to user-<userId>; also increments unread count via unread-count-update.
Real-time socket events
new-notification
Emitted to user-<userId> when a new notification is created for that user.
unread-count-update
Emitted to user-<userId> whenever the unread notification count changes (e.g. after marking one or all as read, or after a new notification arrives). This is the canonical cross-tab sync event.
Note: Earlier docs referenced a
notification-readsocket event for cross-tab sync. That event does not exist. The real event isunread-count-update.
Preferences
Notification preferences live on User (preferences.notifications.email | sms | push). They are read and written through the User API (GET /api/user/profile, PUT /api/user/profile).
Data retention
Notifications are automatically deleted after 90 days.