---
title: "Keep every notification type in one · Agent Wranglers"
url: https://agentwranglers.se/playbook/notifications/channels-and-preferences/notification-catalogue
updated: 2026-10-20
licence: "All rights reserved"
---

# Keep every notification type in one catalogue

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Channels and preferences](https://agentwranglers.se/playbook/notifications/channels-and-preferences)
- Rule: Define every notification type once, in code, with its category, allowed channels, default channels and urgency. Sending code accepts only types from that catalogue.
- How: Give each type a stable ID, such as `order.shipped`. Mark it `transactional` or `marketing`, list the channels it may use, and say which are on by default. Add an urgency of `critical`, `normal` or `low`, which quiet hours and batching read later. Generate the settings page from the same catalogue, so a new type always gets a switch. Reject an unknown type at the send call, not in production logs.
- Check: A unit test sends a type missing from the catalogue and expects an error. A second test confirms every catalogue entry has a category, an urgency and at least one channel.

Example:

```js
export const NOTIFICATIONS = {
  'order.shipped':   { category: 'transactional', urgency: 'normal',   channels: ['inapp', 'push', 'email'], defaults: ['inapp', 'push'] },
  'login.new-device': { category: 'transactional', urgency: 'critical', channels: ['inapp', 'push', 'email'], defaults: ['inapp', 'email'] },
  'weekly.offers':   { category: 'marketing',     urgency: 'low',      channels: ['email', 'push'],          defaults: [] },
};

export function notificationType(id) {
  const type = NOTIFICATIONS[id];
  if (!type) throw new Error(`Unknown notification type: ${id}`);
  return type;
}
```

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class NotificationType:
    category: str
    urgency: str
    channels: tuple[str, ...]
    defaults: tuple[str, ...]

NOTIFICATIONS = {
    "order.shipped": NotificationType("transactional", "normal", ("inapp", "push", "email"), ("inapp", "push")),
    "login.new-device": NotificationType("transactional", "critical", ("inapp", "push", "email"), ("inapp", "email")),
    "weekly.offers": NotificationType("marketing", "low", ("email", "push"), ()),
}

def notification_type(type_id: str) -> NotificationType:
    if type_id not in NOTIFICATIONS:
        raise ValueError(f"Unknown notification type: {type_id}")
    return NOTIFICATIONS[type_id]
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers notifications playbook: https://agentwranglers.se/playbook/notifications/channels-and-preferences/notification-catalogue`.

- Next: [Ask before any marketing message](https://agentwranglers.se/playbook/notifications/channels-and-preferences/marketing-consent)
- [Channels and preferences](https://agentwranglers.se/playbook/notifications/channels-and-preferences)
