Notification Service API Documentation
Overview
The Notification Service provides a comprehensive in-app notification system with support for multiple notification types, multilingual content, and real-time updates via Server-Sent Events (SSE).
Base URL
baseUrl/notification/api
Authentication
All endpoints require authentication via JWT token in the Authorization header:
Authorization: Bearer <token>
The token should contain a sub field with the member/user ID.
In-App Notification API
POST baseUrl/notification/api/in-apps
Create a new in-app notification. This is the primary endpoint for creating custom notifications with full control over content, format, and metadata.
Request
Endpoint: POST baseUrl/notification/api/in-apps
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body Schema:
{
// Localized title fields (optional, but recommended to provide at least title_en)
title_en?: string; // Max 255 characters
title_th?: string; // Max 255 characters
title_cn?: string; // Max 255 characters
// Localized content fields (optional)
content_en?: string;
content_th?: string;
content_cn?: string;
// Format of the content
format?: 'raw' | 'html'; // Default: 'raw'
// Type of notification
type?: 'promotion' | 'points' | 'tier' | 'news' | 'badge'; // Default: 'news'
// Point notification subtype (only relevant when type = 'points')
pointSubtype?: 'point_received' | 'receipt_error' | 'receipt_processing' | 'point_nearly_expire' | 'point_expired';
// Tier notification subtype (only relevant when type = 'tier')
tierSubtype?: 'tier_upgraded' | 'tier_adjusted' | 'tier_renewal_reminder';
// Metadata for notifications (JSON object) - structure varies by type/subtype
metadata?: {
// For point_received type:
points?: number;
source?: string; // e.g., "purchase", "bonus", "referral"
transactionId?: string;
receiptImageUrl?: string; // Must be valid URL
// For receipt_error type:
reason_en?: string;
reason_th?: string;
reason_cn?: string;
resolution_en?: string;
resolution_th?: string;
resolution_cn?: string;
receiptImageUrl?: string;
canRetry?: boolean;
transactionId?: string;
errorCode?: string;
// For receipt_processing type:
transactionId?: string;
receiptImageUrl?: string;
estimatedProcessingTime?: string; // e.g., "2-3 minutes"
status?: 'processing' | 'validating' | 'analyzing'; // Default: 'processing'
statusMessage_en?: string;
statusMessage_th?: string;
statusMessage_cn?: string;
description_en?: string;
description_th?: string;
description_cn?: string;
// For point_nearly_expire type:
points?: number;
expiryDate?: string; // ISO date string
daysRemaining?: number;
source?: string;
// For point_expired type:
points?: number;
expiryDate?: string; // ISO date string
source?: string;
// For tier_upgraded type:
validUntil?: string; // ISO date string
newTier_en?: string;
newTier_th?: string;
newTier_cn?: string;
previousTier_en?: string;
previousTier_th?: string;
previousTier_cn?: string;
benefits_en?: string[];
benefits_th?: string[];
benefits_cn?: string[];
tierLogoUrl?: string;
// For tier_adjusted type:
validUntil?: string;
newTier_en?: string;
newTier_th?: string;
newTier_cn?: string;
previousTier_en?: string;
previousTier_th?: string;
previousTier_cn?: string;
reason_en?: string;
reason_th?: string;
reason_cn?: string;
requirements_en?: string[];
requirements_th?: string[];
requirements_cn?: string[];
tierLogoUrl?: string;
// For tier_renewal_reminder type:
expiryDate?: string; // ISO date string (required)
daysRemaining?: number; // Required
currentTier_en?: string;
currentTier_th?: string;
currentTier_cn?: string;
requirements_en?: string[];
requirements_th?: string[];
requirements_cn?: string[];
benefits_en?: string[];
benefits_th?: string[];
benefits_cn?: string[];
tierLogoUrl?: string;
// For promotion type:
promotionId?: string;
discount?: number;
validUntil?: string;
terms?: string;
rewardName_en?: string;
rewardName_th?: string;
rewardName_cn?: string;
eventType?: string;
// For news type:
newsId?: string;
category?: string;
priority?: 'low' | 'medium' | 'high';
tags?: string[];
// For badge type:
badgeId?: string;
badgeCategory?: string;
earnedAt?: string; // ISO date string
rarity?: 'common' | 'rare' | 'epic' | 'legendary';
progressPercentage?: number; // 0-100
badgeName?: string;
currentValue?: number;
goalValue?: number;
daysLeft?: number | null;
unlockDescription?: {
en?: string;
th?: string;
cn?: string;
};
badgeRule?: {
type?: string;
purchaseAmount?: number;
purchaseCount?: number;
pointsAmount?: number;
minSpend?: number;
withinDays?: number;
window?: {
start?: string;
end?: string;
};
};
badgeNames?: {
en?: string;
th?: string;
cn?: string;
};
badgeImageUrl?: string;
badgeRarity?: 'common' | 'rare' | 'epic' | 'legendary';
unlockPercentage?: number;
};
// Member/User ID who will receive this notification (required, must be valid UUID)
memberId: string; // UUID format
}
Example Request 1: Simple News Notification
{
"title_en": "Welcome to Happy Mall!",
"title_th": "ยินดีต้อนรับสู่ Happy Mall!",
"title_cn": "欢迎来到 Happy Mall!",
"content_en": "Thank you for joining us. Start earning points with your first purchase!",
"content_th": "ขอบคุณที่เข้าร่วมกับเรา เริ่มรับคะแนนจากการซื้อครั้งแรกของคุณ!",
"content_cn": "感谢您的加入。从您的第一次购买开始赚取积分!",
"format": "raw",
"type": "news",
"memberId": "550e8400-e29b-41d4-a716-446655440000"
}
Example Request 2: Point Received Notification with Metadata
{
"title_en": "🎉 150 Points Received",
"title_th": "🎉 ได้รับ 150 คะแนน",
"title_cn": "🎉 获得150积分",
"content_en": "You have received 150 points from purchase! Your recent purchase has earned you 150 Points! Keep snapping those receipts to climb your tier and grab more Happy Mall perks.",
"content_th": "คุณได้รับ 150 คะแนนจากการซื้อ! ซื้อสินค้าล่าสุดของคุณได้รับคะแนน 150 คะแนน! รักษาความสะอาดของคุณเพื่อเลื่อนขั้นเป็นระดับของคุณและรับสิทธิประโยชน์จาก Happy Mall อีกมากมาย",
"content_cn": "您已从购买获得 150 积分!您的最近购买已获得 150 积分!保持拍照那些收据以提升您的等级并获得更多 Happy Mall 福利。",
"format": "raw",
"type": "points",
"pointSubtype": "point_received",
"metadata": {
"points": 150,
"source": "purchase",
"transactionId": "txn_1234567890",
"receiptImageUrl": "https://storage.example.com/receipts/txn_1234567890.jpg"
},
"memberId": "550e8400-e29b-41d4-a716-446655440000"
}
Example Request 3: Tier Upgraded Notification
{
"title_en": "🎊 Tier Upgrade!",
"title_th": "🎊 เลื่อนระดับ!",
"title_cn": "🎊 等级升级!",
"content_en": "Congratulations! You've been upgraded to Gold Tier. Enjoy exclusive benefits!",
"content_th": "ยินดีด้วย! คุณได้รับการอัพเกรดเป็นระดับ Gold รับสิทธิประโยชน์พิเศษ!",
"content_cn": "恭喜!您已升级为黄金等级。享受专属福利!",
"format": "raw",
"type": "tier",
"tierSubtype": "tier_upgraded",
"metadata": {
"validUntil": "2025-12-31T23:59:59Z",
"newTier_en": "Gold",
"newTier_th": "ทอง",
"newTier_cn": "黄金",
"previousTier_en": "Silver",
"previousTier_th": "เงิน",
"previousTier_cn": "白银",
"benefits_en": [
"10% bonus points on all purchases",
"Free shipping on orders over 500 THB",
"Early access to sales"
],
"benefits_th": [
"คะแนนโบนัส 10% สำหรับการซื้อทั้งหมด",
"จัดส่งฟรีสำหรับคำสั่งซื้อมากกว่า 500 บาท",
"เข้าถึงการขายก่อนใคร"
],
"benefits_cn": [
"所有购买获得10%奖励积分",
"订单超过500泰铢免费送货",
"提前获得销售机会"
],
"tierLogoUrl": "https://cdn.example.com/tiers/gold.png"
},
"memberId": "550e8400-e29b-41d4-a716-446655440000"
}
Example Request 4: Receipt Error Notification
{
"title_en": "Receipt Issue: Processing Error",
"title_th": "ปัญหาใบเสร็จ: ข้อผิดพลาดในการประมวลผล",
"title_cn": "收据问题:处理错误",
"content_en": "Something's wrong with your receipt. The image quality is too low. Please try uploading a clearer image. You can retry",
"content_th": "มีปัญหากับใบเสร็จของคุณ คุณภาพของภาพต่ำเกินไป กรุณาลองอัปโหลดภาพที่ชัดเจนขึ้น คุณสามารถลองใหม่ได้",
"content_cn": "您的收据有问题。图像质量太低。请尝试上传更清晰的图像。您可以重试",
"format": "raw",
"type": "points",
"pointSubtype": "receipt_error",
"metadata": {
"reason_en": "The image quality is too low",
"reason_th": "คุณภาพของภาพต่ำเกินไป",
"reason_cn": "图像质量太低",
"resolution_en": "Please try uploading a clearer image",
"resolution_th": "กรุณาลองอัปโหลดภาพที่ชัดเจนขึ้น",
"resolution_cn": "请尝试上传更清晰的图像",
"receiptImageUrl": "https://storage.example.com/receipts/txn_1234567890.jpg",
"canRetry": true,
"transactionId": "txn_1234567890",
"errorCode": "IMAGE_QUALITY_LOW"
},
"memberId": "550e8400-e29b-41d4-a716-446655440000"
}
Example Request 5: HTML Format Promotion
{
"title_en": "Special Promotion: 20% Off All Items",
"title_th": "โปรโมชั่นพิเศษ: ลด 20% ทุกสินค้า",
"title_cn": "特别促销:所有商品8折",
"content_en": "<h2>Limited Time Offer!</h2><p>Get <strong>20% off</strong> on all items. Use code <code>SAVE20</code> at checkout.</p><a href='https://app.example.com/promotions/summer2024'>Shop Now</a>",
"content_th": "<h2>ข้อเสนอจำกัดเวลา!</h2><p>รับส่วนลด <strong>20%</strong> สำหรับสินค้าทั้งหมด ใช้รหัส <code>SAVE20</code> เมื่อชำระเงิน</p><a href='https://app.example.com/promotions/summer2024'>ซื้อเลย</a>",
"content_cn": "<h2>限时优惠!</h2><p>所有商品享受<strong>8折</strong>优惠。结账时使用代码<code>SAVE20</code>。</p><a href='https://app.example.com/promotions/summer2024'>立即购买</a>",
"format": "html",
"type": "promotion",
"metadata": {
"promotionId": "promo_summer2024",
"discount": 20,
"validUntil": "2024-08-31T23:59:59Z",
"terms": "Valid for all items. Cannot be combined with other offers.",
"eventType": "summer_sale"
},
"memberId": "550e8400-e29b-41d4-a716-446655440000"
}
Response
Success Response (201 Created):
{
"statusCode": 201,
"data": {
"message": "Notification created successfully",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title_en": "🎉 150 Points Received",
"title_th": "🎉 ได้รับ 150 คะแนน",
"title_cn": "🎉 获得150积分",
"content_en": "You have received 150 points from purchase! Your recent purchase has earned you 150 Points! Keep snapping those receipts to climb your tier and grab more Happy Mall perks.",
"content_th": "คุณได้รับ 150 คะแนนจากการซื้อ! ซื้อสินค้าล่าสุดของคุณได้รับคะแนน 150 คะแนน! รักษาความสะอาดของคุณเพื่อเลื่อนขั้นเป็นระดับของคุณและรับสิทธิประโยชน์จาก Happy Mall อีกมากมาย",
"content_cn": "您已从购买获得 150 积分!您的最近购买已获得 150 积分!保持拍照那些收据以提升您的等级并获得更多 Happy Mall 福利。",
"format": "raw",
"type": "points",
"pointSubtype": "point_received",
"metadata": {
"points": 150,
"source": "purchase",
"transactionId": "txn_1234567890",
"receiptImageUrl": "https://storage.example.com/receipts/txn_1234567890.jpg"
},
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"readAt": null,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
}
Error Response (400 Bad Request):
{
"statusCode": 400,
"data": {
"message": "Validation error",
"errors": [
{
"field": "memberId",
"message": "Invalid UUID format"
},
{
"field": "title_en",
"message": "String must contain at most 255 character(s)"
}
]
}
}
Error Response (401 Unauthorized):
{
"statusCode": 401,
"data": {
"message": "Unauthorized - Invalid or missing token"
}
}
Auto-Translation Feature
If you only provide English content (title_en and/or content_en), the service will automatically translate it to Thai (title_th, content_th) and Chinese (title_cn, content_cn) using the translation service. However, it's recommended to provide all translations manually for better accuracy.
Example Request with Auto-Translation:
{
"title_en": "New Feature Available",
"content_en": "Check out our new feature!",
"format": "raw",
"type": "news",
"memberId": "550e8400-e29b-41d4-a716-446655440000"
}
The service will automatically generate title_th, title_cn, content_th, and content_cn.
Real-Time Notifications
When a notification is created, it automatically emits a Server-Sent Event (SSE) to the recipient member. The notification will be available in real-time if the member is connected to the SSE endpoint (GET baseUrl/notification/api/in-apps/me/events).
Notes
- Member ID: Must be a valid UUID v4 format
- Title Length: Maximum 255 characters per language
- Content Format:
raw: Plain text contenthtml: HTML formatted content (will be rendered in the app)
- Metadata: The structure of metadata varies based on the
typeandsubtypefields. Ensure the metadata matches the expected structure for your notification type. - URLs: Any URL fields (like
receiptImageUrl,tierLogoUrl) must be valid URLs - Dates: Date fields should be in ISO 8601 format (e.g.,
2024-12-31T23:59:59Z)
Additional In-App Notification Endpoints
GET baseUrl/notification/api/in-apps
Get all notifications with pagination and filtering.
Request
Endpoint: GET baseUrl/notification/api/in-apps
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Query Parameters:
{
page?: number; // Page number (default: 1, min: 1)
limit?: number; // Items per page (default: 20, min: 1, max: 100)
memberId?: string; // Filter by member ID (UUID)
read?: "true" | "false" | "all"; // Filter by read status
format?: "raw" | "html"; // Filter by format
type?: "promotion" | "points" | "tier" | "news" | "badge"; // Filter by type
locale?: "en" | "th" | "cn"; // Localize response content
search?: string; // Search in title/content
dateFrom?: string; // Start date (ISO 8601 or date string)
dateTo?: string; // End date (ISO 8601 or date string)
dateField?: "createdAt" | "updatedAt"; // Date field to filter by (default: "createdAt")
}
Example Request
GET baseUrl/notification/api/in-apps?page=1&limit=20&read=false&type=points&locale=en
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"message": "Notifications retrieved successfully",
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 45,
"totalPages": 3
},
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title_en": "🎉 150 Points Received",
"title_th": "🎉 ได้รับ 150 คะแนน",
"title_cn": "🎉 获得150积分",
"content_en": "You have received 150 points from purchase!",
"format": "raw",
"type": "points",
"pointSubtype": "point_received",
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"readAt": null,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
]
}
}
}
GET baseUrl/notification/api/in-apps/:id
Get a specific notification by ID.
Request
Endpoint: GET baseUrl/notification/api/in-apps/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the notification
}
Query Parameters:
{
locale?: "en" | "th" | "cn"; // Localize response content
}
Example Request
GET baseUrl/notification/api/in-apps/a1b2c3d4-e5f6-7890-abcd-ef1234567890?locale=en
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"message": "Notification retrieved successfully",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title_en": "🎉 150 Points Received",
"title_th": "🎉 ได้รับ 150 คะแนน",
"title_cn": "🎉 获得150积分",
"content_en": "You have received 150 points from purchase!",
"content_th": "คุณได้รับ 150 คะแนนจากการซื้อ!",
"content_cn": "您已从购买获得 150 积分!",
"format": "raw",
"type": "points",
"pointSubtype": "point_received",
"metadata": {
"points": 150,
"source": "purchase",
"transactionId": "txn_1234567890"
},
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"readAt": null,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
}
Error Response (404 Not Found):
{
"statusCode": 404,
"data": {
"message": "Notification not found"
}
}
GET baseUrl/notification/api/in-apps/me
Get all notifications for the authenticated member.
Request
Endpoint: GET baseUrl/notification/api/in-apps/me
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Query Parameters:
Same as GET baseUrl/notification/api/in-apps (excluding memberId as it's automatically set from the token)
Example Request
GET baseUrl/notification/api/in-apps/me?read=false&type=points&locale=en&page=1&limit=20
Response
Success Response (200 OK):
Same structure as GET baseUrl/notification/api/in-apps
GET baseUrl/notification/api/in-apps/me/recent
Get recent notifications for the authenticated member.
Request
Endpoint: GET baseUrl/notification/api/in-apps/me/recent
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Query Parameters:
{
limit?: number; // Number of notifications (default: 10, min: 1, max: 100)
locale?: "en" | "th" | "cn"; // Localize response content
}
Example Request
GET baseUrl/notification/api/in-apps/me/recent?limit=5&locale=en
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"message": "Recent notifications retrieved successfully",
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title_en": "🎉 150 Points Received",
"content_en": "You have received 150 points from purchase!",
"type": "points",
"readAt": null,
"createdAt": "2024-01-15T10:30:00.000Z"
}
]
}
}
GET baseUrl/notification/api/in-apps/me/unread-count
Get the unread notification count for the authenticated member.
Request
Endpoint: GET baseUrl/notification/api/in-apps/me/unread-count
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Example Request
GET baseUrl/notification/api/in-apps/me/unread-count
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"message": "Unread count retrieved successfully",
"data": {
"unreadCount": 5
}
}
}
GET baseUrl/notification/api/in-apps/me/events
Server-Sent Events (SSE) stream for real-time notifications.
Request
Endpoint: GET baseUrl/notification/api/in-apps/me/events
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Query Parameters:
{
locale?: "en" | "th" | "cn"; // Localize notification content
}
Example Request
GET baseUrl/notification/api/in-apps/me/events?locale=en
Response
Stream Response (200 OK - text/event-stream):
The connection remains open and streams events:
data: {"type":"connected","message":"SSE connection established","timestamp":"2024-01-15T10:30:00.000Z","locale":"en"}
data: {"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","title_en":"🎉 150 Points Received","type":"new_notification",...}
data: {"type":"heartbeat","timestamp":"2024-01-15T10:30:30.000Z","locale":"en"}
Event Types:
connected- Initial connection messagenew_notification- New notification receivednotification_read- Notification marked as readheartbeat- Periodic heartbeat (every 30 seconds)
PUT baseUrl/notification/api/in-apps/:id
Update a notification.
Request
Endpoint: PUT baseUrl/notification/api/in-apps/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Path Parameters:
{
id: string; // UUID of the notification
}
Request Body: All fields optional (same structure as POST baseUrl/notification/api/in-apps)
Example Request
{
"title_en": "Updated Title",
"content_en": "Updated content"
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"message": "Notification updated successfully",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title_en": "Updated Title",
"content_en": "Updated content",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}
}
PATCH baseUrl/notification/api/in-apps/:id/read
Mark a notification as read or unread.
Request
Endpoint: PATCH baseUrl/notification/api/in-apps/:id/read
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Path Parameters:
{
id: string; // UUID of the notification
}
Request Body:
{
read: boolean; // true to mark as read, false to mark as unread
}
Example Request
{
"read": true
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"message": "Notification status updated successfully",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"readAt": "2024-01-20T14:30:00.000Z",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}
}
PATCH baseUrl/notification/api/in-apps/me/read-all
Mark all notifications as read for the authenticated member.
Request
Endpoint: PATCH baseUrl/notification/api/in-apps/me/read-all
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Example Request
PATCH baseUrl/notification/api/in-apps/me/read-all
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"message": "All notifications marked as read successfully",
"data": {
"updatedCount": 5
}
}
}
DELETE baseUrl/notification/api/in-apps/:id
Delete a notification.
Request
Endpoint: DELETE baseUrl/notification/api/in-apps/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the notification
}
Example Request
DELETE baseUrl/notification/api/in-apps/a1b2c3d4-e5f6-7890-abcd-ef1234567890
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"message": "Notification deleted successfully"
}
}
Specialized Notification Endpoints
The following endpoints provide convenient helpers for creating specific notification types:
POST baseUrl/notification/api/in-apps/points/received
Create a point received notification with automatic content generation.
Request
Endpoint: POST baseUrl/notification/api/in-apps/points/received
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body:
{
memberId: string; // Required, UUID
points: number; // Required, must be positive
source?: string; // Optional, e.g., "purchase", "bonus"
transactionId?: string; // Optional
receiptImageUrl?: string; // Optional, must be valid URL
}
Example Request
{
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"points": 150,
"source": "purchase",
"transactionId": "txn_1234567890",
"receiptImageUrl": "https://storage.example.com/receipts/txn_1234567890.jpg"
}
Response
Success Response (201 Created):
{
"statusCode": 201,
"data": {
"message": "Point received notification created successfully",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title_en": "🎉 150 Points Received",
"type": "points",
"pointSubtype": "point_received",
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"createdAt": "2024-01-15T10:30:00.000Z"
}
}
}
Similar specialized endpoints exist for:
POST baseUrl/notification/api/in-apps/points/receipt-error- Create receipt error notificationPOST baseUrl/notification/api/in-apps/points/receipt-processing- Create receipt processing notificationPOST baseUrl/notification/api/in-apps/points/nearly-expire- Create point nearly expire notificationPOST baseUrl/notification/api/in-apps/points/expired- Create point expired notificationPOST baseUrl/notification/api/in-apps/tier/upgraded-enhanced- Create tier upgrade notificationPOST baseUrl/notification/api/in-apps/tier/adjusted- Create tier adjusted notificationPOST baseUrl/notification/api/in-apps/tier/renewal-reminder- Create tier renewal reminder notificationPOST baseUrl/notification/api/in-apps/badge/unlocked- Create badge unlocked notificationPOST baseUrl/notification/api/in-apps/badge/progress- Create badge progress notificationPOST baseUrl/notification/api/in-apps/promotion/create- Create promotion notificationPOST baseUrl/notification/api/in-apps/news/create- Create news notification
All follow similar request/response patterns with type-specific body schemas.
Mail Template API
GET baseUrl/notification/api/mail-templates
Get all mail templates with pagination and filtering.
Request
Endpoint: GET baseUrl/notification/api/mail-templates
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Query Parameters:
{
page?: number; // Page number (default: 1, min: 1)
limit?: number; // Items per page (default: 10, min: 1, max: 100)
event?: string; // Filter by event name
version?: string; // Filter by version
search?: string; // Search in name/event
}
Example Request
GET baseUrl/notification/api/mail-templates?page=1&limit=20&event=welcome
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 10,
"totalPages": 1
},
"data": [
{
"id": "template-id-123",
"name": "Welcome Email",
"version": "1.0.0",
"event": "welcome",
"subject_en": "Welcome to Happy Mall!",
"subject_th": "ยินดีต้อนรับสู่ Happy Mall!",
"subject_cn": "欢迎来到 Happy Mall!",
"contentType": "html",
"defaultSenderId": "sender-id-123",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
]
}
}
GET baseUrl/notification/api/mail-templates/:id
Get a specific mail template by ID.
Request
Endpoint: GET baseUrl/notification/api/mail-templates/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the mail template
}
Example Request
GET baseUrl/notification/api/mail-templates/template-id-123
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"id": "template-id-123",
"name": "Welcome Email",
"version": "1.0.0",
"event": "welcome",
"subject_en": "Welcome to Happy Mall!",
"subject_th": "ยินดีต้อนรับสู่ Happy Mall!",
"subject_cn": "欢迎来到 Happy Mall!",
"html_en": "<html><body><h1>Welcome!</h1><p>Thank you for joining us.</p></body></html>",
"html_th": "<html><body><h1>ยินดีต้อนรับ!</h1><p>ขอบคุณที่เข้าร่วมกับเรา</p></body></html>",
"html_cn": "<html><body><h1>欢迎!</h1><p>感谢您的加入</p></body></html>",
"text_en": "Welcome! Thank you for joining us.",
"text_th": "ยินดีต้อนรับ! ขอบคุณที่เข้าร่วมกับเรา",
"text_cn": "欢迎!感谢您的加入",
"contentType": "html",
"defaultSenderId": "sender-id-123",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
GET baseUrl/notification/api/mail-templates/:id/content
Get localized content for a mail template.
Request
Endpoint: GET baseUrl/notification/api/mail-templates/:id/content
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the mail template
}
Query Parameters:
{
locale?: string; // Optional locale (e.g., "en", "th", "cn")
}
Example Request
GET baseUrl/notification/api/mail-templates/template-id-123/content?locale=en
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"subject": "Welcome to Happy Mall!",
"html": "<html><body><h1>Welcome!</h1><p>Thank you for joining us.</p></body></html>",
"text": "Welcome! Thank you for joining us."
}
}
POST baseUrl/notification/api/mail-templates
Create a new mail template.
Request
Endpoint: POST baseUrl/notification/api/mail-templates
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body:
{
name: string; // Required, max 100 characters
version: string; // Required, max 20 characters
event: string; // Required, max 100 characters (event name)
subject_en?: string; // Optional
html_en?: string; // Optional
text_en?: string; // Optional
subject_th?: string; // Optional
html_th?: string; // Optional
text_th?: string; // Optional
subject_cn?: string; // Optional
html_cn?: string; // Optional
text_cn?: string; // Optional
contentType?: "html" | "text"; // Optional, default: "html"
defaultSenderId?: string; // Optional, UUID of default sender
}
Example Request
{
"name": "Welcome Email",
"version": "1.0.0",
"event": "welcome",
"subject_en": "Welcome to Happy Mall!",
"subject_th": "ยินดีต้อนรับสู่ Happy Mall!",
"subject_cn": "欢迎来到 Happy Mall!",
"html_en": "<html><body><h1>Welcome!</h1><p>Thank you for joining us.</p></body></html>",
"html_th": "<html><body><h1>ยินดีต้อนรับ!</h1><p>ขอบคุณที่เข้าร่วมกับเรา</p></body></html>",
"html_cn": "<html><body><h1>欢迎!</h1><p>感谢您的加入</p></body></html>",
"text_en": "Welcome! Thank you for joining us.",
"contentType": "html",
"defaultSenderId": "sender-id-123"
}
Response
Success Response (201 Created):
{
"statusCode": 201,
"data": {
"id": "template-id-123",
"name": "Welcome Email",
"version": "1.0.0",
"event": "welcome",
"createdAt": "2024-01-15T10:30:00.000Z"
}
}
PUT baseUrl/notification/api/mail-templates/:id
Update an existing mail template.
Request
Endpoint: PUT baseUrl/notification/api/mail-templates/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Path Parameters:
{
id: string; // UUID of the mail template
}
Request Body: All fields optional (same structure as POST)
Example Request
{
"subject_en": "Updated Welcome Subject",
"html_en": "<html><body><h1>Updated Welcome!</h1></body></html>"
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"id": "template-id-123",
"name": "Welcome Email",
"subject_en": "Updated Welcome Subject",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}
DELETE baseUrl/notification/api/mail-templates/:id
Delete a mail template.
Request
Endpoint: DELETE baseUrl/notification/api/mail-templates/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the mail template
}
Example Request
DELETE baseUrl/notification/api/mail-templates/template-id-123
Response
Success Response (204 No Content):
No response body.
Mail Sender API
GET baseUrl/notification/api/mail-senders
Get all mail senders with pagination and filtering.
Request
Endpoint: GET baseUrl/notification/api/mail-senders
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Query Parameters:
{
page?: number; // Page number (default: 1, min: 1)
limit?: number; // Items per page (default: 10, min: 1, max: 100)
search?: string; // Search in name/email
}
Example Request
GET baseUrl/notification/api/mail-senders?page=1&limit=20&search=no-reply
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 5,
"totalPages": 1
},
"data": [
{
"id": "sender-id-123",
"name": "No Reply",
"mailAddress": "noreply@example.com",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
]
}
}
GET baseUrl/notification/api/mail-senders/:id
Get a specific mail sender by ID.
Request
Endpoint: GET baseUrl/notification/api/mail-senders/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the mail sender
}
Example Request
GET baseUrl/notification/api/mail-senders/sender-id-123
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"id": "sender-id-123",
"name": "No Reply",
"mailAddress": "noreply@example.com",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
POST baseUrl/notification/api/mail-senders
Create a new mail sender.
Request
Endpoint: POST baseUrl/notification/api/mail-senders
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body:
{
name: string; // Required, max 100 characters
mailAddress: string; // Required, valid email format, max 256 characters
}
Example Request
{
"name": "Support",
"mailAddress": "support@example.com"
}
Response
Success Response (201 Created):
{
"statusCode": 201,
"data": {
"id": "sender-id-124",
"name": "Support",
"mailAddress": "support@example.com",
"createdAt": "2024-01-15T10:30:00.000Z"
}
}
PUT baseUrl/notification/api/mail-senders/:id
Update an existing mail sender.
Request
Endpoint: PUT baseUrl/notification/api/mail-senders/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Path Parameters:
{
id: string; // UUID of the mail sender
}
Request Body:
{
name?: string; // Optional, max 100 characters
mailAddress?: string; // Optional, valid email format, max 256 characters
}
Example Request
{
"name": "Support Team",
"mailAddress": "support-team@example.com"
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"id": "sender-id-123",
"name": "Support Team",
"mailAddress": "support-team@example.com",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}
DELETE baseUrl/notification/api/mail-senders/:id
Delete a mail sender.
Request
Endpoint: DELETE baseUrl/notification/api/mail-senders/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the mail sender
}
Example Request
DELETE baseUrl/notification/api/mail-senders/sender-id-123
Response
Success Response (204 No Content):
No response body.
Mail Action API
GET baseUrl/notification/api/mail-actions
Get all mail actions (sent emails) with filtering.
Request
Endpoint: GET baseUrl/notification/api/mail-actions
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Query Parameters: Various filtering options (page, limit, status, recipientEmail, etc.)
Example Request
GET baseUrl/notification/api/mail-actions?page=1&limit=20
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 100,
"totalPages": 5
},
"data": [
{
"id": "mail-action-id-123",
"recipientEmail": "user@example.com",
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"templateId": "template-id-123",
"status": "sent",
"sentAt": "2024-01-15T10:30:00.000Z",
"createdAt": "2024-01-15T10:30:00.000Z"
}
]
}
}
GET baseUrl/notification/api/mail-actions/:id
Get a specific mail action by ID.
Request
Endpoint: GET baseUrl/notification/api/mail-actions/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the mail action
}
Example Request
GET baseUrl/notification/api/mail-actions/mail-action-id-123
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"id": "mail-action-id-123",
"recipientEmail": "user@example.com",
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"templateId": "template-id-123",
"templateVersion": "1.0.0",
"senderId": "sender-id-123",
"status": "sent",
"sentAt": "2024-01-15T10:30:00.000Z",
"createdAt": "2024-01-15T10:30:00.000Z"
}
}
POST baseUrl/notification/api/mail-actions
Send an email using a template.
Request
Endpoint: POST baseUrl/notification/api/mail-actions
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body:
{
recipientEmail: string; // Required, valid email format, max 256 characters
memberId?: string; // Optional, UUID
locale?: string; // Optional, max 10 characters
templateData?: Record<string, any>; // Optional, dynamic data for template variables
templateId: string; // Required, UUID
version?: string; // Optional, max 50 characters
senderId?: string; // Optional, UUID
}
Example Request
{
"recipientEmail": "user@example.com",
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"locale": "en",
"templateId": "template-id-123",
"templateData": {
"memberName": "John Doe",
"points": 150
},
"senderId": "sender-id-123"
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"messageId": "msg-abc123",
"mailNotifyId": "mail-action-id-123"
}
}
Error Response (400 Bad Request):
{
"statusCode": 400,
"data": {
"message": "Failed to send mail"
}
}
POST baseUrl/notification/api/mail-actions/resend/:id
Resend a previously sent email.
Request
Endpoint: POST baseUrl/notification/api/mail-actions/resend/:id
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Path Parameters:
{
id: string; // UUID of the mail action to resend
}
Example Request
POST baseUrl/notification/api/mail-actions/resend/mail-action-id-123
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"messageId": "msg-abc456",
"mailNotifyId": "mail-action-id-123"
}
}
POST baseUrl/notification/api/mail-actions/bulk
Send bulk emails using a template.
Request
Endpoint: POST baseUrl/notification/api/mail-actions/bulk
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body:
{
templateId: string; // Required, UUID
recipients: Array<{ // Required
email: string; // Required
memberId?: string; // Optional, UUID
templateData?: Record<string, any>; // Optional
}>;
language?: string; // Optional
dynamicData?: Record<string, any>; // Optional, shared dynamic data
senderId?: string; // Optional, UUID
batchSize?: number; // Optional, batch size for processing
skipWhitelistCheck?: boolean; // Optional, skip whitelist validation
}
Example Request
{
"templateId": "template-id-123",
"recipients": [
{
"email": "user1@example.com",
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"templateData": {
"memberName": "John Doe"
}
},
{
"email": "user2@example.com",
"memberId": "660e8400-e29b-41d4-a716-446655440001",
"templateData": {
"memberName": "Jane Smith"
}
}
],
"language": "en",
"senderId": "sender-id-123",
"batchSize": 100
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"total": 2,
"success": 2,
"failed": 0,
"results": [
{
"email": "user1@example.com",
"status": "sent",
"messageId": "msg-abc123"
},
{
"email": "user2@example.com",
"status": "sent",
"messageId": "msg-abc124"
}
]
}
}
POST baseUrl/notification/api/mail-actions/preview
Preview an email without sending it.
Request
Endpoint: POST baseUrl/notification/api/mail-actions/preview
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body:
{
templateId: string; // Required, UUID
language?: string; // Optional
dynamicData?: Record<string, any>; // Optional, template variables
senderId?: string; // Optional, UUID
}
Example Request
{
"templateId": "template-id-123",
"language": "en",
"dynamicData": {
"memberName": "John Doe",
"points": 150
},
"senderId": "sender-id-123"
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"subject": "Welcome to Happy Mall!",
"html": "<html><body><h1>Welcome John Doe!</h1><p>You have 150 points.</p></body></html>",
"text": "Welcome John Doe! You have 150 points.",
"from": "noreply@example.com"
}
}
POST baseUrl/notification/api/mail-actions/send-to-all-subscribers
Send email to all subscribers using a template.
Request
Endpoint: POST baseUrl/notification/api/mail-actions/send-to-all-subscribers
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body:
{
templateId: string; // Required, UUID
language?: string; // Optional
dynamicData?: Record<string, any>; // Optional, shared dynamic data
batchSize?: number; // Optional, batch size for processing
}
Example Request
{
"templateId": "template-id-123",
"language": "en",
"dynamicData": {
"promotion": "Summer Sale 2024"
},
"batchSize": 1000
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"totalSubscribers": 5000,
"queued": 5000,
"batchSize": 1000,
"estimatedTime": "5 minutes"
}
}
POST baseUrl/notification/api/mail-actions/validate-emails
Validate emails against whitelist.
Request
Endpoint: POST baseUrl/notification/api/mail-actions/validate-emails
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Request Body:
{
emails: string[]; // Required, array of email addresses
}
Example Request
{
"emails": [
"user1@example.com",
"user2@example.com",
"invalid-email"
]
}
Response
Success Response (200 OK):
{
"statusCode": 200,
"data": {
"allowed": [
"user1@example.com",
"user2@example.com"
],
"blocked": [
"invalid-email"
]
}
}
Data Types & Enums
Notification Types
promotion- Promotion notificationspoints- Point-related notificationstier- Tier-related notificationsnews- News/announcement notificationsbadge- Badge-related notifications
Point Subtypes
point_received- Points receivedreceipt_error- Receipt verification errorreceipt_processing- Receipt being processedpoint_nearly_expire- Points about to expirepoint_expired- Points expired
Tier Subtypes
tier_upgraded- Tier upgradedtier_adjusted- Tier adjustedtier_renewal_reminder- Tier renewal reminder
Content Format
raw- Plain text contenthtml- HTML formatted content
Content Type (Mail)
html- HTML emailtext- Plain text email
Locales
en- Englishth- Thaicn- Chinese (Simplified)
Error Responses
All error responses follow this structure:
{
"statusCode": <HTTP_STATUS_CODE>,
"data": {
"message": "<Error message>",
"errors": [ // Optional, for validation errors
{
"field": "<field_name>",
"message": "<validation message>"
}
]
}
}
Common HTTP Status Codes
200 OK- Request succeeded201 Created- Resource created successfully204 No Content- Request succeeded with no content400 Bad Request- Invalid request data or business rule violation401 Unauthorized- Missing or invalid authentication token403 Forbidden- Insufficient permissions404 Not Found- Resource not found500 Internal Server Error- Server error
Notes
-
Authentication: All endpoints require a valid JWT token in the
Authorizationheader. The token'ssubfield should contain the member/user ID. -
Server-Sent Events (SSE): The
/in-apps/me/eventsendpoint maintains a persistent connection and streams notifications in real-time. The connection sends heartbeat messages every 30 seconds to keep the connection alive. -
Localization: Use the
localequery parameter to get localized content. For notifications, if not specified, all language fields will be returned. -
Mail Templates:
- Templates support both HTML and text formats
- Dynamic data can be injected into templates using template variables
- Templates are versioned for change tracking
-
Mail Sending:
- Supports single email, bulk emails, and broadcast to all subscribers
- Email validation against whitelist is available
- Preview endpoint allows testing templates before sending
- Failed emails can be resent using the resend endpoint
-
Date Formats: All date fields use ISO 8601 format (e.g.,
2024-12-31T23:59:59.000Z). -
Pagination: Pagination defaults to page 1 with 10-20 items per page (varies by endpoint). Maximum limit is typically 100 items per page.
Support
For issues or questions, please contact the development team or refer to the main project documentation.