Skip to main content
Version: 1.2

9.12 Notification History (Legacy)

Controller: NotificationHistoryController · Route: api/v1/NotificationHistory · GroupName: identity (note: every other controller in this chapter uses notifications/ notifications.campaigns/notifications.receipts — this one is grouped under identity instead, presumably a historical accident) · 5 endpoints.

This controller is explicitly flagged as legacy and blocks framework cleanup. docs/ARCHITECTURE/LEGACY_CLEANUP_READINESS.md names this controller directly: "NotificationHistoryController must be migrated before INotificationJobService can be removed." It depends on ITenantNotificationLogService and INotificationJobService — both slated for eventual removal once all callers migrate to the framework's own services — plus IMailService directly. See Chapter 13 — Notification History for the full legacy-status explanation and the TenantNotificationLog retention decision.

Verb + routePermissionRequestResponse
POST GetDataTableNotificationHistory.ViewAllNotificationHistoryFilterDto body + query skip=0&take=20&search=DtResult<TenantNotificationLogDto> (manually constructed — not via the platform's standard Result<T>/DataTable pipeline)
GET GetDetails/{id}NotificationHistory.ViewTenantNotificationLogDetailsDto directly (no Result<T> envelope at all — the action's return type is the DTO itself, unlike every other controller in this chapter)
GET GetCounters?tenantId=NotificationHistory.ViewqueryNotificationCountersDto directly (same no-envelope pattern)
POST RetryFailedNotificationHistory.Retry200 OK, empty body — calls _jobService.RetryFailedAsync()
POST SendTestEmail?to=&name=&lang=none — no [MustHavePermission] attributequery stringanonymous debug object (see below)

GET GetDetails/{id} and GetCounters — response shape caveat

Because these two actions return the DTO directly rather than a Result<T>, do not expect a succeeded/ message/data wrapper here — the JSON body is the payload:

{
"id": "6d7e8f10-0000-0000-0000-000000000001",
"tenantId": "acme-corp",
"notificationType": 3,
"channel": 2,
"status": 1,
"recipient": "966549000191",
"languageCode": "ar",
"messageBody": "Template:subscription_activated_ar",
"errorMessage": null,
"createdBy": "System",
"createdOn": "2026-07-01T12:00:00Z"
}

status here is the ErpCompat-renamed enum NotificationStatus (Pending=0, Sent=1, Failed=2, Retrying=3) — not NotificationDeliveryState used elsewhere in the framework. Do not confuse the two when integrating; they have different member sets and different meanings.

POST SendTestEmail — flagged as a debug/manual-test utility, not production API surface

This action has no [MustHavePermission] attribute — any authenticated user (any valid JWT) can trigger a real outbound email send through it, relying solely on the controller's blanket [Authorize]. The method signature also embeds a large hardcoded HTML email template and a hardcoded Arabic restaurant-branding default for the name parameter ("مطاعم شواطئ عدن"), which strongly indicates this endpoint was added as a one-off manual test utility and left in place, rather than designed as a documented product feature.

POST /api/v1/NotificationHistory/SendTestEmail?to=qa@example.com&name=Test%20User&lang=en

Response (success):

{ "success": true, "message": "Test email sent", "to": "qa@example.com", "subject": "...", "lang": "en" }

Response (failure, still 200 OK):

{ "success": false, "message": "SMTP connection failed", "exceptionType": "System.Net.Mail.SmtpException", "to": "qa@example.com" }

Recommendation for API consumers and reviewers: treat this endpoint as internal/QA-only, not part of the documented public contract. It is included here for completeness per this documentation's "no endpoint may remain undocumented" mandate, not as an endorsement of its design. See Chapter 18 — Troubleshooting for how to use it safely in a lower environment.

POST RetryFailed

Calls INotificationJobService.RetryFailedAsync() directly — a manual trigger for whatever legacy retry sweep that service still performs over TenantNotificationLog rows. This is unrelated to the framework's own NotificationRetryQueue/notification-retry-processor-pipeline engine described in Chapter 12 — the two retry mechanisms are independent and cover different tables.

Angular: if this legacy history grid is still surfaced in an admin UI, treat it as a read-only audit view of pre-framework-era sends; do not build new features against NotificationHistoryFilterDto/TenantNotificationLogDto — use Notification Analytics and Delivery Receipts for anything new. Related APIs: Chapter 13 — Notification History.