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
channelNotificationChannelEmail, Push, InApp, Sms
recipientsRecipientDto[]At least one recipient
subjectstringEmail subject or notification title
htmlBodystringHTML content (email)
textBodystringPlain text fallback
templateSlugstringUse a stored Scriban template
templateDataobjectData for template rendering
priorityNotificationPriorityLow, Normal, High, Critical

Response: 200 OKNotificationResultDto

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 OKNotificationResultDto

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 OKNotificationResultDto

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 OKNotificationResultDto 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 OKNotificationResultDto | 404 Not Found

Get Notification by ID

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

Response: 200 OKNotificationDetailDto

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 OKPagedResult<NotificationSummaryDto>

Get Statistics

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

Response: 200 OKNotificationStatsDto

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 CreatedNotificationTemplateDto

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 OKNotificationTemplateDto | 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 OKPagedResult<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 OKRenderedNotification

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 OKPagedResult<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 OKint

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.