9.2 App Notification Templates
Controller: AppNotificationTemplateController · Route: api/v1/AppNotificationTemplate ·
GroupName: notifications · 9 endpoints · Full CRUD for the templates described in
Chapter 8.
Standard CRUD action set — see §9.0 conventions
for the shared DtParameters/DtResult/DeleteDto shapes reused below.
| Verb + route | Permission | Request | Response (data) |
|---|---|---|---|
POST GetDataTable | AppNotificationTemplates.ViewAll | DtParameters | DtResult<AppNotificationTemplateDto> (unwrapped) |
GET GetDetails/{id} | AppNotificationTemplates.View | — | AppNotificationTemplateDetailsDto |
GET GetEdit/{id} | AppNotificationTemplates.Edit | — | AppNotificationTemplateEditDto |
GET GetDropdownList?findBy=&onlyActive=true | AppNotificationTemplates.View | query string | AppNotificationTemplateViewListDto[] |
POST Create | AppNotificationTemplates.Create | AppNotificationTemplateEditDto | Guid (new ID) |
PUT Update/{id} | AppNotificationTemplates.Edit | AppNotificationTemplateEditDto | Guid |
DELETE Delete?restore= | AppNotificationTemplates.Delete | DeleteDto[] | Guid |
PUT Active | AppNotificationTemplates.Active | DeleteDto[] | Guid |
PUT Deactive | AppNotificationTemplates.Deactive | DeleteDto[] | Guid |
Field-level detail — AppNotificationTemplateEditDto
{
"id": "00000000-0000-0000-0000-000000000000",
"isActive": true,
"displayOrder": 0,
"eventKey": "PurchaseInvoicePosted",
"name": "تم اعتماد فاتورة شراء",
"fName": "Purchase invoice posted",
"subjectTemplate": "Invoice {{ invoiceNumber }} has been posted",
"bodyTemplate": "Hello {{ customerName }}, your invoice {{ invoiceNumber }} for {{ totalAmount }} {{ currencyCode }} has been posted.",
"channel": 1,
"languageCode": "en",
"whatsAppTemplateName": null,
"whatsAppLanguageCode": null,
"whatsAppBodyParams": null
}
Validation (AppNotificationTemplateValidator, FluentValidation): EventKey NotEmpty + max 100,
Name NotEmpty + max 200, FName max 200, SubjectTemplate max 500 (only when non-null), BodyTemplate
NotEmpty, Channel must be a defined enum value. No validation exists today for WhatsAppTemplateName,
WhatsAppLanguageCode, or WhatsAppBodyParams — malformed WhatsApp fields are only caught at dispatch time
(see §7.3), not at save time. Flag this to template authors.
Example: create a WhatsApp template row for the same event
{
"isActive": true,
"displayOrder": 0,
"eventKey": "PurchaseInvoicePosted",
"name": "تم اعتماد فاتورة شراء - واتساب",
"fName": "Purchase invoice posted - WhatsApp",
"bodyTemplate": "",
"channel": 6,
"languageCode": "en",
"whatsAppTemplateName": "invoice_posted_en",
"whatsAppLanguageCode": "en",
"whatsAppBodyParams": "[\"{{ customerName }}\", \"{{ invoiceNumber }}\", \"{{ totalAmount }}\"]"
}
bodyTemplate is still required by the validator even for WhatsApp rows (NotEmpty) — send an empty string
or a human-readable fallback description; it is never rendered for WhatsApp dispatch.
Possible errors: 400 FluentValidation failure (missing EventKey/Name/BodyTemplate, invalid
Channel); succeeded:false entity-not-found on GetDetails/GetEdit/Update with a bad id.
Angular: the template management screen should let an author pick Channel first, then conditionally
show WhatsApp-only fields (whatsAppTemplateName, whatsAppLanguageCode, whatsAppBodyParams) only when
Channel === 6, since the API accepts but ignores them for other channels.
Flutter: template authoring is typically a back-office/admin feature — usually not exposed in the
end-user mobile app; the mobile client is a template consumer, not editor.
Backend: AppNotificationTemplateService — standard _mapper.Map CRUD, wrapped in
BeginTransaction/SaveChangesAsync/CommitTransaction per platform convention.
Related APIs: Notification Event Configurations (which channels
are even attempted for an event), Chapter 8 — Templates.