{"openapi":"3.0.0","paths":{"/api/v1/subscriptions":{"post":{"description":"Register a new push notification subscription for a user device","operationId":"SubscriptionsController_subscribe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribePushDto"}}}},"responses":{"201":{"description":"Subscription created successfully","content":{"application/json":{"schema":{"example":{"id":"550e8400-e29b-41d4-a716-446655440000","companyId":"550e8400-e29b-41d4-a716-446655440001","userId":"550e8400-e29b-41d4-a716-446655440002","deviceId":"device-12345","deviceName":"Chrome on Windows","deviceType":"WEB","provider":"WEB_PUSH","enabled":true,"subscribedAt":"2025-10-24T12:00:00.000Z"}}}}},"409":{"description":"Subscription already exists"}},"summary":"Subscribe to push notifications","tags":["Push Subscriptions"]},"get":{"description":"Retrieve a list of push subscriptions with filtering","operationId":"SubscriptionsController_listSubscriptions","parameters":[{"name":"companyId","required":false,"in":"query","description":"Filter by company ID","schema":{"type":"string"}},{"name":"userId","required":false,"in":"query","description":"Filter by user ID","schema":{"type":"string"}},{"name":"enabled","required":false,"in":"query","description":"Filter by enabled status","schema":{"type":"boolean"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"type":"number"}},{"name":"provider","required":false,"in":"query","description":"Filter by push provider","schema":{"enum":["WEB_PUSH","FCM","APNS"],"type":"string"}},{"name":"deviceType","required":false,"in":"query","description":"Filter by device type","schema":{"enum":["WEB","IOS","ANDROID","TABLET","DESKTOP"],"type":"string"}}],"responses":{"200":{"description":"Subscriptions retrieved successfully"}},"summary":"List push subscriptions","tags":["Push Subscriptions"]}},"/api/v1/subscriptions/{id}":{"put":{"description":"Update an existing push notification subscription","operationId":"SubscriptionsController_updateSubscription","parameters":[{"name":"id","required":true,"in":"path","description":"Subscription ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSubscriptionDto"}}}},"responses":{"200":{"description":"Subscription updated successfully"},"404":{"description":"Subscription not found"}},"summary":"Update push subscription","tags":["Push Subscriptions"]},"delete":{"description":"Remove a push notification subscription","operationId":"SubscriptionsController_unsubscribe","parameters":[{"name":"id","required":true,"in":"path","description":"Subscription ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Subscription removed successfully"},"404":{"description":"Subscription not found"}},"summary":"Unsubscribe from push notifications","tags":["Push Subscriptions"]}},"/api/v1/notifications":{"post":{"description":"Send a push notification to a user","operationId":"NotificationsController_sendNotification","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendNotificationDto"}}}},"responses":{"201":{"description":"Notification sent successfully","content":{"application/json":{"schema":{"example":{"id":"550e8400-e29b-41d4-a716-446655440000","userId":"550e8400-e29b-41d4-a716-446655440001","notificationType":"TOKEN_ASSIGNED","title":"New Token Assigned","body":"You have been assigned 100 PROP tokens","status":"SENT","priority":"NORMAL","createdAt":"2025-10-24T12:00:00.000Z"}}}}}},"summary":"Send push notification","tags":["Notifications"]},"get":{"description":"Retrieve a list of notifications with filtering","operationId":"NotificationsController_listNotifications","parameters":[{"name":"companyId","required":false,"in":"query","description":"Filter by company ID","schema":{"type":"string"}},{"name":"userId","required":false,"in":"query","description":"Filter by user ID","schema":{"type":"string"}},{"name":"referenceType","required":false,"in":"query","description":"Filter by reference type","schema":{"type":"string"}},{"name":"referenceId","required":false,"in":"query","description":"Filter by reference ID","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"type":"number"}},{"name":"status","required":false,"in":"query","description":"Filter by status","schema":{"enum":["PENDING","PROCESSING","SENT","DELIVERED","READ","CLICKED","FAILED","EXPIRED","CANCELLED"],"type":"string"}},{"name":"notificationType","required":false,"in":"query","description":"Filter by notification type","schema":{"enum":["TOKEN_ASSIGNED","ASSET_CREATED","ASSET_DEPLOYED","ASSET_DEPLOYMENT_FAILED","CAMPAIGN_CREATED","CAMPAIGN_UPDATED","CAMPAIGN_COMPLETED","DISTRIBUTION_CREATED","DISTRIBUTION_UPDATED","TRANSACTION_COMPLETED","TRANSACTION_FAILED","KYC_APPROVED","KYC_REJECTED","WALLET_CREATED","SYSTEM_ALERT","GENERAL"],"type":"string"}}],"responses":{"200":{"description":"Notifications retrieved successfully"}},"summary":"List notifications","tags":["Notifications"]}},"/api/v1/notifications/{id}/read":{"patch":{"description":"Mark a notification as read by the user","operationId":"NotificationsController_markAsRead","parameters":[{"name":"id","required":true,"in":"path","description":"Notification ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Notification marked as read successfully"},"404":{"description":"Notification not found"}},"summary":"Mark notification as read","tags":["Notifications"]}},"/api/v1/notifications/user/{userId}":{"get":{"description":"Retrieve notifications for a specific user (for bell icon/inbox)","operationId":"NotificationsController_getUserNotifications","parameters":[{"name":"userId","required":true,"in":"path","description":"Clerk User ID (user_xxx format)","schema":{"type":"string"}},{"name":"unreadOnly","required":false,"in":"query","description":"Only return unread notifications","schema":{"type":"boolean"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"type":"number"}}],"responses":{"200":{"description":"Notifications retrieved successfully"}},"summary":"Get notifications for a user","tags":["Notifications"]}},"/api/v1/notifications/user/{userId}/read-all":{"patch":{"description":"Mark all unread notifications as read","operationId":"NotificationsController_markAllAsRead","parameters":[{"name":"userId","required":true,"in":"path","description":"Clerk User ID (user_xxx format)","schema":{"type":"string"}}],"responses":{"200":{"description":"All notifications marked as read"}},"summary":"Mark all notifications as read for a user","tags":["Notifications"]}},"/api/v1/notifications/user/{userId}/unread-count":{"get":{"description":"Get the count of unread notifications for bell badge","operationId":"NotificationsController_getUnreadCount","parameters":[{"name":"userId","required":true,"in":"path","description":"Clerk User ID (user_xxx format)","schema":{"type":"string"}}],"responses":{"200":{"description":"Unread count returned"}},"summary":"Get unread notification count","tags":["Notifications"]}},"/api/v1/notifications/{id}":{"delete":{"description":"Delete a notification by ID","operationId":"NotificationsController_deleteNotification","parameters":[{"name":"id","required":true,"in":"path","description":"Notification ID","schema":{"type":"string"}}],"responses":{"204":{"description":"Notification deleted successfully"},"404":{"description":"Notification not found"}},"summary":"Delete/dismiss notification","tags":["Notifications"]}},"/api/v1/email/purchase-confirmation":{"post":{"description":"Sends a purchase confirmation email to the customer after successful token minting","operationId":"EmailController_sendPurchaseConfirmation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseConfirmationDto"}}}},"responses":{"200":{"description":"Email sent successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Purchase confirmation email sent successfully"}}}}}},"400":{"description":"Invalid request data"},"500":{"description":"Failed to send email"}},"summary":"Send purchase confirmation email","tags":["Email Notifications"]}},"/api/v1/email/test":{"post":{"description":"Verifies email service connection and configuration","operationId":"EmailController_testEmailConfiguration","parameters":[],"responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"type":"object","properties":{"configured":{"type":"boolean"},"message":{"type":"string"}}}}}}},"summary":"Test email configuration","tags":["Email Notifications"]}},"/api/v1/health":{"get":{"operationId":"HealthController_check","parameters":[],"responses":{"200":{"description":"Service is healthy"},"503":{"description":"Service is unhealthy"}},"summary":"Health check","tags":["Health"]}},"/api/v1/health/ready":{"get":{"operationId":"HealthController_ready","parameters":[],"responses":{"200":{"description":"Service is ready"}},"summary":"Readiness check — verifies dependencies","tags":["Health"]}},"/api/v1/metrics":{"get":{"description":"Retrieve metrics and statistics for notifications and subscriptions","operationId":"MetricsController_getMetrics","parameters":[{"name":"companyId","required":true,"in":"query","description":"Company ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics retrieved successfully","content":{"application/json":{"schema":{"example":{"subscriptions":{"total":150,"active":142},"notifications":{"totalSent":1234,"unread":45}}}}}}},"summary":"Get notification metrics","tags":["Metrics"]}},"/api/v1/metrics/user":{"get":{"description":"Retrieve notification metrics for a specific user","operationId":"MetricsController_getUserMetrics","parameters":[{"name":"userId","required":true,"in":"query","description":"User ID","schema":{"type":"string"}},{"name":"companyId","required":true,"in":"query","description":"Company ID","schema":{"type":"string"}}],"responses":{"200":{"description":"User metrics retrieved successfully","content":{"application/json":{"schema":{"example":{"unreadCount":5,"subscriptionsCount":2}}}}}},"summary":"Get user notification metrics","tags":["Metrics"]}},"/api/v1/events":{"post":{"description":"Emit a real-time notification to connected WebSocket clients. Events are routed based on userId (user room), companyId (admin room), or broadcast flag.","operationId":"EventsController_emitEvent","parameters":[{"name":"X-Internal-Api-Key","in":"header","description":"Internal API key for service-to-service communication","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitEventDto"}}}},"responses":{"202":{"description":"Event accepted for processing"},"400":{"description":"Invalid event payload"}},"summary":"Emit a notification event","tags":["Events"]}},"/api/v1/events/user/{userId}":{"post":{"operationId":"EventsController_emitToUser","parameters":[{"name":"X-Internal-Api-Key","in":"header","description":"Internal API key for service-to-service communication","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitEventDto"}}}},"responses":{"202":{"description":""}},"summary":"Emit event to a specific user","tags":["Events"]}},"/api/v1/events/company/{companyId}":{"post":{"operationId":"EventsController_emitToCompany","parameters":[{"name":"X-Internal-Api-Key","in":"header","description":"Internal API key for service-to-service communication","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitEventDto"}}}},"responses":{"202":{"description":""}},"summary":"Emit event to a specific company","tags":["Events"]}},"/api/v1/events/stats":{"get":{"operationId":"EventsController_getStats","parameters":[],"responses":{"200":{"description":"Connection statistics"}},"summary":"Get WebSocket connection statistics","tags":["Events"]}},"/api/v1/waitlist/subscribe":{"post":{"description":"Add email to a waitlist for notifications (e.g., athlete launch)","operationId":"WaitlistController_subscribe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeWaitlistDto"}}}},"responses":{"200":{"description":"Already subscribed","content":{"application/json":{"schema":{"example":{"success":true,"message":"You are already on the waitlist","isNew":false}}}}},"201":{"description":"Successfully subscribed","content":{"application/json":{"schema":{"example":{"success":true,"message":"Successfully subscribed to the waitlist","isNew":true}}}}}},"summary":"Subscribe to waitlist","tags":["Waitlist"]}},"/api/v1/waitlist/subscribers":{"get":{"description":"Get list of waitlist subscribers (admin use)","operationId":"WaitlistController_listSubscribers","parameters":[{"name":"waitlistType","required":false,"in":"query","schema":{"enum":["ATHLETE_LAUNCH","PLATFORM_LAUNCH","PARTNER_INTEREST","FEATURE_INTEREST"],"type":"string"}},{"name":"offset","required":false,"in":"query","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"Subscribers retrieved"}},"summary":"List waitlist subscribers","tags":["Waitlist"]}},"/api/v1/waitlist/check":{"get":{"description":"Check if an email is already on a waitlist","operationId":"WaitlistController_checkSubscription","parameters":[{"name":"email","required":true,"in":"query","schema":{"type":"string"}},{"name":"waitlistType","required":false,"in":"query","schema":{"enum":["ATHLETE_LAUNCH","PLATFORM_LAUNCH","PARTNER_INTEREST","FEATURE_INTEREST"],"type":"string"}}],"responses":{"200":{"description":"Check result"}},"summary":"Check if email is subscribed","tags":["Waitlist"]}}},"info":{"title":"PXL8 Notifications API","description":"Push Notifications API for Web3 RWA Platform - Web Push (VAPID) and Firebase Cloud Messaging","version":"1.0","contact":{}},"tags":[{"name":"Push Subscriptions","description":"Manage push notification subscriptions"},{"name":"Notifications","description":"Send and manage notifications"},{"name":"Health","description":"Service health checks"},{"name":"Metrics","description":"Notification metrics and statistics"}],"servers":[{"url":"https://api.pxl8.io","description":"Production API"},{"url":"http://localhost:3009","description":"Local Development"}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"WebPushKeysDto":{"type":"object","properties":{"p256dh":{"type":"string","description":"P256DH key for Web Push encryption","example":"BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTp..."},"auth":{"type":"string","description":"Auth secret for Web Push encryption","example":"tBHItJI5svbpez7KI4CCXg=="}},"required":["p256dh","auth"]},"SubscribePushDto":{"type":"object","properties":{"companyId":{"type":"string","description":"Company ID (optional for multi-tenant customers)","example":"550e8400-e29b-41d4-a716-446655440000"},"userId":{"type":"string","description":"User ID (Clerk user ID)","example":"user_2tXqVWKu8Khnn"},"deviceId":{"type":"string","description":"Device ID (unique identifier for the device)","example":"device-12345"},"deviceName":{"type":"string","description":"Device name","example":"iPhone 15 Pro"},"deviceType":{"type":"string","description":"Device type","enum":["WEB","IOS","ANDROID","TABLET","DESKTOP"],"example":"WEB"},"platform":{"type":"string","description":"Platform","example":"iOS 17.0"},"provider":{"type":"string","description":"Push provider","enum":["WEB_PUSH","FCM","APNS"],"example":"WEB_PUSH"},"webPushEndpoint":{"type":"string","description":"Web Push endpoint (required for WEB_PUSH provider)","example":"https://fcm.googleapis.com/fcm/send/..."},"webPushKeys":{"description":"Web Push encryption keys (required for WEB_PUSH provider)","allOf":[{"$ref":"#/components/schemas/WebPushKeysDto"}]},"fcmToken":{"type":"string","description":"Firebase Cloud Messaging token (required for FCM provider)","example":"fGcE8qFZRUe5Vj7K..."},"preferences":{"type":"object","description":"User notification preferences","example":{"tokenAssigned":true,"assetCreated":true,"campaignUpdates":false}},"userAgent":{"type":"string","description":"User agent string","example":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."},"ipAddress":{"type":"string","description":"IP address","example":"192.168.1.1"},"metadata":{"type":"object","description":"Additional metadata","example":{"source":"web_app","version":"1.0.0"}}},"required":["userId","deviceType","provider"]},"UpdateSubscriptionDto":{"type":"object","properties":{"deviceName":{"type":"string","description":"Device name","example":"iPhone 15 Pro"},"deviceType":{"type":"string","description":"Device type","enum":["WEB","IOS","ANDROID","TABLET","DESKTOP"],"example":"WEB"},"platform":{"type":"string","description":"Platform","example":"iOS 17.0"},"webPushEndpoint":{"type":"string","description":"Web Push endpoint","example":"https://fcm.googleapis.com/fcm/send/..."},"webPushKeys":{"description":"Web Push encryption keys","allOf":[{"$ref":"#/components/schemas/WebPushKeysDto"}]},"fcmToken":{"type":"string","description":"Firebase Cloud Messaging token","example":"fGcE8qFZRUe5Vj7K..."},"enabled":{"type":"boolean","description":"Enable or disable subscription","example":true},"preferences":{"type":"object","description":"User notification preferences","example":{"tokenAssigned":true,"assetCreated":true,"campaignUpdates":false}}}},"SendNotificationDto":{"type":"object","properties":{"companyId":{"type":"string","description":"Company ID","example":"550e8400-e29b-41d4-a716-446655440000"},"userId":{"type":"string","description":"User ID","example":"550e8400-e29b-41d4-a716-446655440001"},"notificationType":{"type":"string","description":"Notification type","enum":["TOKEN_ASSIGNED","ASSET_CREATED","ASSET_DEPLOYED","ASSET_DEPLOYMENT_FAILED","CAMPAIGN_CREATED","CAMPAIGN_UPDATED","CAMPAIGN_COMPLETED","DISTRIBUTION_CREATED","DISTRIBUTION_UPDATED","TRANSACTION_COMPLETED","TRANSACTION_FAILED","KYC_APPROVED","KYC_REJECTED","WALLET_CREATED","SYSTEM_ALERT","GENERAL"],"example":"TOKEN_ASSIGNED"},"title":{"type":"string","description":"Notification title","example":"New Token Assigned"},"body":{"type":"string","description":"Notification body","example":"You have been assigned 100 PROP tokens"},"icon":{"type":"string","description":"Icon URL","example":"https://example.com/icon.png"},"image":{"type":"string","description":"Image URL","example":"https://example.com/image.jpg"},"badge":{"type":"string","description":"Badge URL","example":"https://example.com/badge.png"},"actionUrl":{"type":"string","description":"Action URL (where to navigate on click)","example":"/assets/550e8400-e29b-41d4-a716-446655440000"},"clickAction":{"type":"string","description":"Click action identifier","example":"OPEN_ASSET_DETAILS"},"data":{"type":"object","description":"Additional data payload","example":{"assetId":"550e8400-e29b-41d4-a716-446655440000","amount":100}},"referenceType":{"type":"string","description":"Reference entity type","example":"asset"},"referenceId":{"type":"string","description":"Reference entity ID","example":"550e8400-e29b-41d4-a716-446655440000"},"priority":{"type":"string","description":"Notification priority","enum":["LOW","NORMAL","HIGH","URGENT"],"example":"NORMAL"},"scheduledFor":{"format":"date-time","type":"string","description":"Schedule notification for later","example":"2025-10-25T12:00:00Z"},"metadata":{"type":"object","description":"Additional metadata","example":{"campaignId":"550e8400-e29b-41d4-a716-446655440002"}}},"required":["companyId","userId","notificationType","title","body"]},"PurchaseConfirmationDto":{"type":"object","properties":{"userId":{"type":"string","description":"User ID who made the purchase","example":"usr_abc123"},"userEmail":{"type":"string","description":"User email address","example":"customer@example.com"},"userName":{"type":"string","description":"User name for personalization","example":"John Doe"},"campaignName":{"type":"string","description":"Name of the campaign/asset purchased","example":"Premium Real Estate Portfolio"},"tokenCount":{"type":"number","description":"Number of tokens purchased","example":10,"minimum":1},"totalPrice":{"type":"number","description":"Total purchase price","example":500,"minimum":0},"pricePerToken":{"type":"number","description":"Price per token","example":50,"minimum":0},"currency":{"type":"string","description":"Currency code (USD, GBP, EUR, etc.)","example":"USD"},"stripePaymentIntentId":{"type":"string","description":"Stripe payment intent ID","example":"pi_1234567890abcdef"},"tokenNumbers":{"description":"Array of minted token numbers/IDs","example":["#001","#002","#003","#004","#005"],"type":"array","items":{"type":"string"}},"purchaseDate":{"type":"string","description":"Purchase date (ISO 8601 format)","example":"2025-11-11T19:30:00Z"},"campaignImage":{"type":"string","description":"Campaign/asset image URL","example":"https://app.pxl8.io/assets/campaign-image.jpg"}},"required":["userId","userEmail","campaignName","tokenCount","totalPrice","pricePerToken","currency","stripePaymentIntentId","tokenNumbers","purchaseDate"]},"EmitEventDto":{"type":"object","properties":{}},"SubscribeWaitlistDto":{"type":"object","properties":{}}}}}