Notifications

Notifications are how Protocol keeps your users informed across every channel -- email, SMS, push, Slack, Teams, and webhooks. Powered by template-based rendering with Handlebars interpolation, Redis-backed rate limiting per channel, and delivery tracking with automatic retry, the notification system ensures reliable, observable message delivery at scale. On this page, we will explore the endpoints for sending and managing notifications programmatically.

The notification model

The notification model contains all the information about a single notification delivery, including the channel, template, recipient, and delivery status.

Channels

Six delivery channels are supported: email (SMTP), sms (Twilio), push (FCM), slack (Slack API), teams (Microsoft Teams), and webhook (HTTP POST). Each channel has independent rate limits enforced through Redis token buckets.

Properties

  • Name
    id
    Type
    string
    Description

    Unique identifier for the notification.

  • Name
    channel
    Type
    string
    Description

    Delivery channel. One of email, sms, push, slack, teams, or webhook.

  • Name
    template_id
    Type
    string
    Description

    Reference to the notification template used for rendering.

  • Name
    recipient
    Type
    string
    Description

    The recipient address -- email, phone number, user ID, or webhook URL depending on the channel.

  • Name
    status
    Type
    string
    Description

    Current delivery status. One of pending, sent, delivered, failed, or read.

  • Name
    subject
    Type
    string
    Description

    The notification subject line (used by email and push channels).

  • Name
    body
    Type
    string
    Description

    The rendered notification content after template interpolation.

  • Name
    sent_at
    Type
    timestamp
    Description

    Timestamp of when the notification was sent.

  • Name
    read_at
    Type
    timestamp
    Description

    Timestamp of when the notification was read by the recipient.


POST/v1/notifications/send

Send a notification

This endpoint allows you to send a notification to a recipient through any supported channel. The notification body is rendered from a template using Handlebars interpolation with the provided variables. Rate limiting is enforced per channel via Redis token buckets.

Required attributes

  • Name
    channel
    Type
    string
    Description

    The delivery channel. One of email, sms, push, slack, teams, or webhook.

  • Name
    recipient
    Type
    string
    Description

    The recipient address for the chosen channel.

  • Name
    template_id
    Type
    string
    Description

    The ID of the notification template to render.

Optional attributes

  • Name
    variables
    Type
    object
    Description

    Key-value pairs for Handlebars template interpolation.

  • Name
    subject
    Type
    string
    Description

    Override the template subject line.

Request

POST
/v1/notifications/send
curl http://localhost:3000/v1/notifications/send \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{\
    "channel": "email",\
    "recipient": "jane.doe@company.com",\
    "template_id": "tmpl_ticket_assigned",\
    "variables": {\
      "ticket_id": "TKT-4829",\
      "assignee_name": "Jane Doe",\
      "priority": "P1"\
    }\
  }'

Response

{
  "id": "ntf_9xKmPqRsT2uVwX",
  "channel": "email",
  "template_id": "tmpl_ticket_assigned",
  "recipient": "jane.doe@company.com",
  "status": "sent",
  "subject": "[P1] Ticket TKT-4829 assigned to you",
  "body": "Hi Jane Doe, ticket TKT-4829 has been assigned to you with priority P1.",
  "sent_at": 1708732800,
  "read_at": null
}

GET/v1/notifications

List all notifications

This endpoint allows you to retrieve a paginated list of all notifications. By default, a maximum of ten notifications are shown per page. You can filter by channel and status.

Optional attributes

  • Name
    channel
    Type
    string
    Description

    Filter notifications by delivery channel.

  • Name
    status
    Type
    string
    Description

    Filter notifications by delivery status.

  • Name
    limit
    Type
    integer
    Description

    Limit the number of notifications returned.

Request

GET
/v1/notifications
curl -G http://localhost:3000/v1/notifications \
  -H "Authorization: Bearer {token}" \
  -d channel="email" \
  -d limit=10

Response

{
  "has_more": false,
  "data": [
    {
      "id": "ntf_9xKmPqRsT2uVwX",
      "channel": "email",
      "template_id": "tmpl_ticket_assigned",
      "recipient": "jane.doe@company.com",
      "status": "delivered",
      "subject": "[P1] Ticket TKT-4829 assigned to you",
      "body": "Hi Jane Doe, ticket TKT-4829 has been assigned to you with priority P1.",
      "sent_at": 1708732800,
      "read_at": 1708733400
    },
    {
      "id": "ntf_3aB4cDeFgH5iJk"
      // ...
    }
  ]
}

GET/v1/notifications/unread

Get unread count

This endpoint returns the count of unread notifications for the authenticated user. Use this for badge counts and notification indicators in your UI.

Request

GET
/v1/notifications/unread
curl http://localhost:3000/v1/notifications/unread \
  -H "Authorization: Bearer {token}"

Response

{
  "unread_count": 7,
  "by_channel": {
    "email": 3,
    "slack": 2,
    "push": 1,
    "teams": 1
  }
}

PUT/v1/notifications/:id/read

Mark as read

This endpoint marks a notification as read. The read_at timestamp is set to the current time. This is idempotent -- calling it on an already-read notification returns the existing read timestamp.

Request

PUT
/v1/notifications/ntf_9xKmPqRsT2uVwX/read
curl -X PUT http://localhost:3000/v1/notifications/ntf_9xKmPqRsT2uVwX/read \
  -H "Authorization: Bearer {token}"

Response

{
  "id": "ntf_9xKmPqRsT2uVwX",
  "status": "read",
  "read_at": 1708733400
}

GET/v1/notifications/preferences

Get notification preferences

This endpoint retrieves the notification preferences for the authenticated user. Preferences control which channels are enabled, quiet hours, and per-event opt-in/opt-out settings.

Request

GET
/v1/notifications/preferences
curl http://localhost:3000/v1/notifications/preferences \
  -H "Authorization: Bearer {token}"

Response

{
  "channels": {
    "email": { "enabled": true, "quiet_hours": null },
    "sms": { "enabled": false, "quiet_hours": null },
    "push": { "enabled": true, "quiet_hours": { "start": "22:00", "end": "07:00" } },
    "slack": { "enabled": true, "quiet_hours": null },
    "teams": { "enabled": false, "quiet_hours": null },
    "webhook": { "enabled": false, "quiet_hours": null }
  },
  "events": {
    "ticket_assigned": ["email", "push", "slack"],
    "ticket_resolved": ["email"],
    "sla_breach": ["email", "push", "slack", "sms"]
  }
}

PUT/v1/notifications/preferences

Update notification preferences

This endpoint updates the notification preferences for the authenticated user. You can enable or disable channels, configure quiet hours, and set per-event channel preferences.

Optional attributes

  • Name
    channels
    Type
    object
    Description

    Channel configuration with enabled and quiet_hours settings per channel.

  • Name
    events
    Type
    object
    Description

    Map of event types to arrays of enabled channel names.

Request

PUT
/v1/notifications/preferences
curl -X PUT http://localhost:3000/v1/notifications/preferences \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{\
    "channels": {\
      "sms": { "enabled": true },\
      "push": { "quiet_hours": { "start": "23:00", "end": "08:00" } }\
    },\
    "events": {\
      "ticket_assigned": ["email", "push", "slack", "sms"]\
    }\
  }'

Response

{
  "channels": {
    "email": { "enabled": true, "quiet_hours": null },
    "sms": { "enabled": true, "quiet_hours": null },
    "push": { "enabled": true, "quiet_hours": { "start": "23:00", "end": "08:00" } },
    "slack": { "enabled": true, "quiet_hours": null },
    "teams": { "enabled": false, "quiet_hours": null },
    "webhook": { "enabled": false, "quiet_hours": null }
  },
  "events": {
    "ticket_assigned": ["email", "push", "slack", "sms"],
    "ticket_resolved": ["email"],
    "sla_breach": ["email", "push", "slack", "sms"]
  }
}

GET/v1/notifications/templates

List notification templates

This endpoint returns a paginated list of available notification templates. Templates use Handlebars syntax for dynamic content interpolation and can be associated with one or more channels.

Optional attributes

  • Name
    channel
    Type
    string
    Description

    Filter templates by supported channel.

  • Name
    limit
    Type
    integer
    Description

    Limit the number of templates returned.

Request

GET
/v1/notifications/templates
curl -G http://localhost:3000/v1/notifications/templates \
  -H "Authorization: Bearer {token}" \
  -d limit=10

Response

{
  "has_more": false,
  "data": [
    {
      "id": "tmpl_ticket_assigned",
      "name": "Ticket Assigned",
      "channels": ["email", "push", "slack"],
      "subject": "[{{priority}}] Ticket {{ticket_id}} assigned to you",
      "body": "Hi {{assignee_name}}, ticket {{ticket_id}} has been assigned to you with priority {{priority}}.",
      "variables": ["ticket_id", "assignee_name", "priority"],
      "created_at": 1708646400,
      "updated_at": 1708732800
    },
    {
      "id": "tmpl_sla_breach",
      "name": "SLA Breach Warning",
      "channels": ["email", "push", "slack", "sms"],
      "subject": "SLA Breach: Ticket {{ticket_id}}",
      "body": "Ticket {{ticket_id}} is about to breach its {{sla_type}} SLA. Time remaining: {{time_remaining}}.",
      "variables": ["ticket_id", "sla_type", "time_remaining"],
      "created_at": 1708646400,
      "updated_at": 1708646400
    }
  ]
}

Was this page helpful?