Skip to main content
Notifications are in-app messages for the signed-in user, with optional email delivery. They exist for events someone has to act on, not as a feed of everything that happens — that is what the audit trails are for.

Kinds

The last exclusion is deliberate: the admin who just suspended someone does not need telling they did it. group.membership_changed is emitted once per permission change, from the before/after state of PUT /groups/{id}/members/{userID}/permissions. That endpoint exists partly for this — reconciling permissions in one call rather than several /grants calls avoids a burst of notifications for what is really one decision.

Reading them

Mark one read with PATCH /notifications/{id} and {"read": true}, or clear the lot with POST /notifications/read-all. Only true is accepted — there is no marking something unread. Each notification carries an optional resource (kind and id) and action (label and href), so a client can link straight to the thing needing attention.

Email

Email is per-user opt-in through the profile:
Sends go through the outbox and are processed per recipient, so a retry re-sends only the deliveries that actually failed rather than spamming everyone who already received it. Email needs RESEND_API_KEY and CUSTOS_EMAIL_FROM. Without them the control plane falls back to logging, which is what makes development workable — see Configuration.

Retention

Notifications and their email delivery records are purged after 30 days, swept daily. Audit trails are not affected; notifications are a to-do list, not the record.