Skip to main content
Version: 1.2

9.8 Notification Analytics

Controller: NotificationAnalyticsController · Route: api/v1/NotificationAnalytics · GroupName: notifications · 10 endpoints, all GET, all read-only. Every action returns Task<IActionResult> (not ActionResult<T>) but still wraps its payload in the standard Result<T> shape.

All list-style endpoints accept NotificationAnalyticsFilterDto as [FromQuery]:

GET /api/v1/NotificationAnalytics/Summary?dateFrom=2026-06-27&dateTo=2026-07-04&channel=1&eventKey=PurchaseInvoicePosted
FieldTypeNotes
dateFrom / dateToDateTime?Default range when omitted: last 7 days. Maximum range: 90 days (per source XML doc comments)
channelNotificationChannel?Optional filter
eventKeystring?Optional filter
Verb + routePermissionReturns
GET SummaryNotificationAnalytics.ViewNotificationAnalyticsSummaryDto
GET ChannelsNotificationAnalytics.ViewNotificationChannelPerformanceDto[]
GET EventsNotificationAnalytics.ViewNotificationEventPerformanceDto[]
GET Failures/TopReasonsNotificationAnalytics.ViewAllNotificationFailureReasonDto[]
GET RetryQueueNotificationAnalytics.ViewNotificationRetryQueueMetricsDto
GET DeadLettersNotificationAnalytics.ViewAllNotificationDeadLetterMetricsDto
GET TrendsNotificationAnalytics.ViewNotificationDeliveryTrendDto[]
GET RecentFailuresNotificationAnalytics.ViewAllNotificationRecentFailureDto[]
GET SlaNotificationAnalytics.ViewNotificationSlaIndicatorDto[]
GET ProvidersNotificationAnalytics.ViewNotificationProviderStatisticsDto[]

Note the split permission model: broad operational views (Summary, Channels, Events, RetryQueue, Trends, Sla, Providers) require only .View; failure-detail views that could expose sensitive error context (Failures/TopReasons, DeadLetters, RecentFailures) require the stricter .ViewAll.

GET Summary

{
"succeeded": true,
"message": null,
"data": {
"totalDispatched": 18420,
"totalSucceeded": 18103,
"totalFailed": 210,
"totalPending": 107,
"deliveryRate": 98.28,
"dateFrom": "2026-06-27T00:00:00Z",
"dateTo": "2026-07-04T23:59:59Z"
}
}

(Field names shown reflect the DTO's confirmed purpose from source XML doc comments; exact property names should be cross-checked against NotificationAnalyticsSummaryDto at integration time if binding strictly — see Appendix § Verification Notes.)

GET RetryQueue

{
"succeeded": true,
"message": null,
"data": {
"totalPending": 12,
"totalRetrying": 3,
"totalExpired": 0,
"totalCancelled": 5,
"oldestPendingAgeMinutes": 47.5,
"oldestScheduledAt": "2026-07-04T09:30:00Z"
}
}

GET Providers

{
"succeeded": true,
"message": null,
"data": [
{
"providerName": "ZohoEmailProvider",
"channel": 1,
"healthState": 1,
"healthStateName": "Healthy",
"totalRequests": 9200,
"totalSucceeded": 9188,
"totalFailed": 12,
"totalFailovers": 2,
"consecutiveFailures": 0,
"averageLatencyMs": 340.2,
"availabilityPercentage": 99.87,
"lastSuccessOn": "2026-07-04T11:02:10Z",
"lastFailureOn": "2026-07-03T22:14:00Z",
"unavailableSince": null
}
]
}

healthState (ProviderHealthState): Unknown=0, Healthy=1, Degraded=2, Unavailable=3.

Angular: an operations dashboard — Summary/Channels/Trends/Sla for a health overview page; Failures/TopReasons/RecentFailures/DeadLetters for a drill-down incident view. Cache Summary/Trends briefly (e.g. 60s) since they aggregate over potentially large tables; do not cache RetryQueue/DeadLetters counts, which need to feel live to an operator actively triaging. Backend: INotificationAnalyticsService — aggregation queries against NotificationDeliveryAttempt, NotificationRetryQueue, NotificationDeadLetter, and provider health-monitor state. Related APIs: Retry Queue, Dead Letters, Delivery Receipts.