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.mdnames this controller directly: "NotificationHistoryController must be migrated beforeINotificationJobServicecan be removed." It depends onITenantNotificationLogServiceandINotificationJobService— both slated for eventual removal once all callers migrate to the framework's own services — plusIMailServicedirectly. See Chapter 13 — Notification History for the full legacy-status explanation and theTenantNotificationLogretention decision.
| Verb + route | Permission | Request | Response |
|---|---|---|---|
POST GetDataTable | NotificationHistory.ViewAll | NotificationHistoryFilterDto 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.View | — | TenantNotificationLogDetailsDto 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.View | query | NotificationCountersDto directly (same no-envelope pattern) |
POST RetryFailed | NotificationHistory.Retry | — | 200 OK, empty body — calls _jobService.RetryFailedAsync() |
POST SendTestEmail?to=&name=&lang= | none — no [MustHavePermission] attribute | query string | anonymous 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.