Skip to content

API Reference ​

GrydNotifications exposes three REST API controllers for sending notifications, managing templates, and handling in-app notifications.

All endpoints inherit from GrydBaseController and return RFC 7807 ProblemDetails on errors.

Error Code Convention ​

Error codes use a suffix convention to determine HTTP status:

SuffixHTTP StatusExample
_NOT_FOUND404 Not FoundNOTIFICATION_NOT_FOUND
_ALREADY_EXISTS409 ConflictNOTIFICATION_TEMPLATE_ALREADY_EXISTS
_FORBIDDEN403 ForbiddenNOTIFICATION_INAPP_FORBIDDEN
_UNAUTHORIZED401 UnauthorizedNOTIFICATION_UNAUTHORIZED
_UNPROCESSABLE422 UnprocessableNOTIFICATION_UNPROCESSABLE
(other/none)400 Bad RequestNOTIFICATION_DELIVERY_FAILED

Notifications ​

Base path: /api/v1/notifications

Send Notification ​

Send a notification through the unified pipeline (auto-resolves channel provider).

http
POST /api/v1/notifications/send
Content-Type: application/json

{
  "channel": "Email",
  "recipients": [
    { "address": "user@example.com", "displayName": "John Doe" }
  ],
  "subject": "Order Confirmed",
  "htmlBody": "<h1>Your order has been confirmed</h1>",
  "textBody": "Your order has been confirmed",
  "templateSlug": null,
  "templateData": null,
  "priority": "Normal"
}
FieldTypeRequiredDescription
channelNotificationChannel✅Email, Push, InApp, Sms
recipientsRecipientDto[]✅At least one recipient
subjectstring❌Email subject or notification title
htmlBodystring❌HTML content (email)
textBodystring❌Plain text fallback
templateSlugstring❌Use a stored Scriban template
templateDataobject❌Data for template rendering
priorityNotificationPriority❌Low, Normal, High, Critical

Response: 200 OK — NotificationResultDto

json
{
  "notificationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "Sent",
  "statusDisplay": "Sent"
}

Send Email (Direct) ​

Bypass the unified pipeline and send an email directly.

http
POST /api/v1/notifications/email
Content-Type: application/json

{
  "to": ["user@example.com"],
  "cc": ["manager@example.com"],
  "bcc": [],
  "subject": "Monthly Report",
  "htmlBody": "<h1>Report attached</h1>",
  "fromAddress": "reports@myapp.com",
  "fromName": "Reports System"
}

Response: 200 OK — NotificationResultDto

Send Push Notification (Direct) ​

Send a push notification to specific device tokens or users.

http
POST /api/v1/notifications/push
Content-Type: application/json

{
  "title": "New Message",
  "body": "You have a new message from John",
  "deviceTokens": ["token1", "token2"],
  "data": {
    "messageId": "abc123",
    "type": "new_message"
  }
}

Response: 200 OK — NotificationResultDto

Schedule Notification ​

Schedule a notification for future delivery.

http
POST /api/v1/notifications/schedule
Content-Type: application/json

{
  "notification": {
    "channel": "Email",
    "recipients": [{ "address": "user@example.com" }],
    "subject": "Reminder",
    "htmlBody": "<p>Don't forget your appointment tomorrow!</p>"
  },
  "scheduledAt": "2026-02-21T09:00:00Z"
}

Response: 200 OK — NotificationResultDto with status: "Scheduled"

Cancel Scheduled Notification ​

http
DELETE /api/v1/notifications/schedule/{id}

Response: 200 OK | 404 Not Found

Error codes: NOTIFICATION_NOT_FOUND, NOTIFICATION_ALREADY_CANCELLED

Retry Failed Notification ​

Manually retry a failed notification.

http
POST /api/v1/notifications/{id}/retry

Response: 200 OK — NotificationResultDto | 404 Not Found

Get Notification by ID ​

http
GET /api/v1/notifications/{id}

Response: 200 OK — NotificationDetailDto

json
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "channel": "Email",
  "channelDisplay": "Email",
  "status": "Sent",
  "statusDisplay": "Sent",
  "priority": "Normal",
  "subject": "Order Confirmed",
  "htmlBody": "<h1>Your order has been confirmed</h1>",
  "templateSlug": "order-confirmation",
  "fromAddress": "noreply@myapp.com",
  "fromName": "My App",
  "retryCount": 0,
  "maxRetries": 3,
  "sentAt": "2026-02-20T14:30:00Z",
  "createdAt": "2026-02-20T14:29:58Z",
  "recipients": [
    { "address": "user@example.com", "displayName": "John Doe" }
  ],
  "deliveryAttempts": [
    {
      "attemptNumber": 1,
      "providerName": "MailKit",
      "isSuccess": true,
      "durationMs": 342.5,
      "attemptedAt": "2026-02-20T14:30:00Z"
    }
  ]
}

List Notifications (Paged) ​

http
GET /api/v1/notifications?page=1&pageSize=20&channel=Email&status=Sent&fromDate=2026-02-01&toDate=2026-02-28

Query Parameters:

ParameterTypeDefaultDescription
pageint1Page number
pageSizeint20Page size
channelNotificationChannel?—Filter by channel
statusNotificationStatus?—Filter by status
fromDateDateTime?—Created after this date
toDateDateTime?—Created before this date

Response: 200 OK — PagedResult<NotificationSummaryDto>

Get Statistics ​

http
GET /api/v1/notifications/stats?fromDate=2026-02-01&toDate=2026-02-28

Response: 200 OK — NotificationStatsDto

json
{
  "totalNotifications": 15230,
  "pendingNotifications": 12,
  "sentNotifications": 14800,
  "failedNotifications": 45,
  "deadLetteredNotifications": 3,
  "scheduledNotifications": 8,
  "queuedNotifications": 362
}

Notification Templates ​

Base path: /api/v1/notification-templates

Create Template ​

http
POST /api/v1/notification-templates
Content-Type: application/json

{
  "slug": "order-confirmation",
  "name": "Order Confirmation Email",
  "subjectTemplate": "Order #{{order_id}} Confirmed",
  "htmlBodyTemplate": "<h1>Hi {{customer_name}}</h1><p>Your order #{{order_id}} for {{total | math.format \"C2\"}} is confirmed.</p>",
  "textBodyTemplate": "Hi {{customer_name}}, your order #{{order_id}} is confirmed.",
  "locale": "en-US",
  "requiredVariables": "order_id,customer_name,total"
}

Response: 201 Created — NotificationTemplateDto

json
{
  "id": "a1b2c3d4-...",
  "slug": "order-confirmation",
  "name": "Order Confirmation Email",
  "locale": "en-US",
  "version": 1,
  "createdAt": "2026-02-20T14:30:00Z"
}

Error codes: NOTIFICATION_TEMPLATE_ALREADY_EXISTS (409)

Update Template ​

http
PUT /api/v1/notification-templates/{id}
Content-Type: application/json

{
  "templateId": "a1b2c3d4-...",
  "name": "Order Confirmation Email (Updated)",
  "subjectTemplate": "Order #{{order_id}} — Thank you!",
  "htmlBodyTemplate": "<h1>Thanks, {{customer_name}}!</h1>"
}

WARNING

The templateId in the body must match the id in the URL. A mismatch returns 400 Bad Request.

Response: 200 OK — NotificationTemplateDto | 404 Not Found

Delete Template ​

http
DELETE /api/v1/notification-templates/{id}

Response: 200 OK | 404 Not Found

List Templates (Paged) ​

http
GET /api/v1/notification-templates?page=1&pageSize=20&locale=en-US
ParameterTypeDefaultDescription
pageint1Page number
pageSizeint20Page size
localestring?—Filter by locale

Response: 200 OK — PagedResult<NotificationTemplateDto>

Render Template (Preview) ​

Preview how a template renders with provided data — without actually sending anything.

http
POST /api/v1/notification-templates/render
Content-Type: application/json

{
  "templateSlug": "order-confirmation",
  "locale": "en-US",
  "data": {
    "order_id": "ORD-12345",
    "customer_name": "John",
    "total": 199.99
  }
}

Response: 200 OK — RenderedNotification

json
{
  "subject": "Order #ORD-12345 Confirmed",
  "htmlBody": "<h1>Hi John</h1><p>Your order #ORD-12345 for $199.99 is confirmed.</p>",
  "textBody": "Hi John, your order #ORD-12345 is confirmed.",
  "templateSlug": "order-confirmation",
  "locale": "en-US",
  "templateVersion": 1
}

User Notifications (In-App) ​

Base path: /api/v1/user-notifications

List User Notifications ​

http
GET /api/v1/user-notifications?userId={userId}&page=1&pageSize=20&isRead=false&category=alerts
ParameterTypeDefaultDescription
userIdGuidrequiredUser ID
pageint1Page number
pageSizeint20Page size
isReadbool?—Filter read/unread
categorystring?—Filter by category

Response: 200 OK — PagedResult<UserNotificationDto>

json
{
  "items": [
    {
      "id": "...",
      "userId": "...",
      "title": "New Comment",
      "body": "John commented on your task",
      "icon": "💬",
      "category": "comments",
      "actionUrl": "/tasks/123",
      "priority": "Normal",
      "isRead": false,
      "createdAt": "2026-02-20T14:30:00Z"
    }
  ],
  "totalCount": 42,
  "pageNumber": 1,
  "pageSize": 20
}

Get Unread Count (Badge) ​

http
GET /api/v1/user-notifications/unread-count?userId={userId}

Response: 200 OK — int

json
42

Mark as Read ​

http
PUT /api/v1/user-notifications/{id}/read?userId={userId}

Response: 200 OK | 404 Not Found | 403 Forbidden

Error codes: NOTIFICATION_INAPP_NOT_FOUND, NOTIFICATION_INAPP_FORBIDDEN

Mark All as Read ​

http
PUT /api/v1/user-notifications/read-all?userId={userId}

Response: 200 OK

Delete User Notification ​

http
DELETE /api/v1/user-notifications/{id}?userId={userId}

Response: 200 OK | 404 Not Found | 403 Forbidden


Enums ​

NotificationChannel ​

ValueDescription
EmailEmail via SMTP (MailKit) or SendGrid
PushPush notification via FCM
InAppIn-app drawer notification
SmsSMS (future)

NotificationStatus ​

ValueDescription
PendingCreated, not yet processed
QueuedIn the processing queue
SendingActively being sent
SentSuccessfully delivered
FailedDelivery failed (may retry)
DeadLetteredFailed after all retries
ScheduledScheduled for future delivery
CancelledCancelled by user

NotificationPriority ​

ValueDescription
LowBatch-friendly, can be delayed
NormalStandard delivery
HighPrioritized in queue
CriticalImmediate processing

Released under the MIT License.