The Notifications facade
Everything goes through one facade, RoundlyConsulting\Notifications\Facades\Notifications, sugar over the NotificationsManager singleton. There is no global alias — it is one letter from Laravel’s own Notification facade — so always import it:
use RoundlyConsulting\Notifications\Facades\Notifications; // no global alias — always import it
// Types — registered once, read for a settings screen
Notifications::define('comment.posted')->category('comments')->window('PT10M')->register();
Notifications::types()->all();
// Send — flat, fluent, or about one subject
Notifications::send('request.awaiting_approval', $request, $approvers, ['reference' => 'PR-9']);
Notifications::type('request.awaiting_approval')->about($request)->to($approvers)->once("request:{$request->id}")->send();
Notifications::for($contract)->send('contract.expiring', Recipients::owner());
// One recipient's inbox and preferences
Notifications::inbox($user)->in($company)->unread()->paginate();
Notifications::preferences($user)->mute('comment.posted');
// One subject's reminders, acknowledgement and revocation
Notifications::for($task)->remind('task.due', Reminder::before('deadline', 'PT1H'), to: $task->assignee);
Notifications::for($contract)->acknowledge('contract.expiring', by: $user);
Notifications::for($request)->revoke($formerMember);
// The time-driven work the scheduler runs
Notifications::sweep();
Notifications::prune();Manager methods
| Method | Returns | Does |
|---|---|---|
send($type, $subject, $recipients, $data = [], $actor = null, $context = null, $idempotencyKey = null) | SendResult | Notify recipients of one event — inbox, mail, preferences, de-dup, quiet hours, digests and access per recipient. |
sendNotification(SendNotificationData $data) | SendResult | The send as a DTO — what the builder and the raw action use. |
type($type) | PendingNotification | The fluent send: about, to, by, with, in, once, escalate, send. |
for(Model $subject) | SubjectHandle | Everything about one subject: sends, reminders, acknowledgement, revocation. |
inbox(Model $recipient) | InboxHandle | One recipient’s inbox — immutable filters, reads, counts, mutations. |
preferences(Model $recipient) | PreferencesHandle | One user’s channel, category, digest, quiet-hours and timezone preferences. |
register(string ...$types) / registerType(NotificationType $type) | void | Register class types or a type instance. |
define(string $key) | TypeBuilder | A type without a class. |
types() | TypesAccessor | all(), categories(), find(), has(), get() — for a settings screen. |
reminders() | RemindersAccessor | fireDue(), backfill($type), acknowledge($subject, $type, $by). |
digests() | DigestsAccessor | sendDue(), preview($user). |
deliveries() | DeliveriesAccessor | dispatchDue(). |
interop() | InteropAccessor | map(), suppress(), mapped(), suppressed(). |
inboxMessage(Model $recipient, InboxMessage $message) | ?InboxItem | Write a Laravel inbox-channel message into a recipient’s inbox. |
sweep(?array $only = null) | SweepReport | Due mail, digests, reminders, escalations, stale claims. |
prune() | PruneReport | Delete old rows (see Commands). |
Notifications::fake() | NotificationsFake | Facade only — the record-only fake (see Testing). |
perform() and applyInterop() are public on the manager but internal: perform() is the single funnel every handle, builder, channel and model trait runs its action through — the hook the fake records with — and applyInterop() is what the interop listener calls. Don’t call them from app code.
Notifications::for($subject)
| Method | Returns | Does |
|---|---|---|
send($type, $recipients, $data = [], $actor = null, $context = null, $idempotencyKey = null) | SendResult | A send about this subject. |
type($type) | PendingNotification | The fluent send, subject pre-filled. |
remind($type, ReminderRule $rule, $to, array $data = []) | list<NotificationReminder> | An ad-hoc reminder. |
reminders() | SubjectReminders | schedule($type, $to), sync(?$type), cancel(?$type), pending(?$type), all(?$type). |
acknowledge(?string $type = null, ?Model $by = null) | int | Acknowledge the subject’s open reminders and stop their escalations. |
revoke(?Model $recipient = null) | int | Remove a recipient’s (or everyone’s) items about the subject and cancel their pending mail. |
subject() | Model | The subject. |
Notifications::inbox($recipient)
Handles are immutable — each filter returns a copy:
| Method | Returns | Does |
|---|---|---|
unread() / read() / archived() / withArchived() | InboxHandle | Status filters; the default is active (not archived). |
in(Model|string $context) / withoutContext() / allContexts() | InboxHandle | One context (a model or a key like company:3), only items without one, or every context (the default). |
category($category) / type($type) / since(CarbonInterface) | InboxHandle | Narrow by category, type or recent activity. |
latest() | InboxHandle | Newest activity first — the default order. |
paginate(?int $perPage) / cursorPaginate(?int $perPage) | LengthAwarePaginator / CursorPaginator | Pages that eager-load actors and subjects; perPage clamped to inbox.max_per_page. |
get(?int $limit) / first() | Collection / ?InboxItem | A capped list; the newest item. |
find($item) | InboxItem | By model or id, inside this inbox only — anything else throws InboxItemNotFoundException. |
unreadCount() / counts() | int / InboxCounts | Unread count; unread, total and per-context counts. |
markRead($item) / markUnread($item) | InboxHandle | Read state; markRead() also acknowledges an acknowledgedOnRead() reminder. |
markAllRead(in: null, category: null) | int | One UPDATE within every filter of the handle; an explicit argument replaces the filter of its kind. |
archive($item) / unarchive($item) / delete($item) | InboxHandle | Archive, restore from the archive, soft-delete. |
recipient() | Model | The inbox owner. |
Notifications::preferences($user)
| Method | Returns | Does |
|---|---|---|
mute($type, ?Channel $channel = null) | PreferencesHandle | Mail only — or every mutable channel with inbox muting on, or one channel. |
unmute($type, ?Channel $channel = null) | PreferencesHandle | Clear the override: back to the category and type default. |
set($type, Channel $channel, bool $enabled) | PreferencesHandle | An explicit on or off. |
muteCategory($category, ?Channel) / unmuteCategory($category, ?Channel) | PreferencesHandle | A whole category; an unused category throws. |
digest(DigestFrequency $frequency, ?string $time = null) | PreferencesHandle | Off, daily or weekly, at an optional local time. |
quietHours(?string $start, ?string $end = null) | PreferencesHandle | Local HH:MM; null clears them. |
timezone(?string $timezone) | PreferencesHandle | An IANA id; null clears it. |
update(PreferencesUpdate $update) | PreferencesHandle | Several changes, all or nothing. |
reset() | PreferencesHandle | Every type and category override forgotten (digest, quiet hours and timezone kept). |
matrix() / overview() | list<PreferenceRow> / PreferencesOverview | The settings-screen data, translated. |
enabled($type, Channel) / muted($type) | bool | The effective state of a channel; whether mail is off. |
digestPreference() / quietHoursPreference() / resolvedTimezone() | DigestPreferenceData / ?QuietHours / string | The effective digest, quiet hours and timezone. |
user() | Model | The user. |
Builders, DTOs and enums
- Builders: PendingNotification (about, to, by, with, in, once, escalate, data, send), TypeBuilder (see Notification types), the reminder rules Reminder, ReminderRule and EscalationRule, and Context (of, key).
- DTOs (final readonly): SendNotificationData, SendResult, RecipientOutcome, TypeDefinition, CategoryDefinition, PreferenceRow, ChannelPreference, PreferencesOverview, PreferencesUpdate, DigestPreferenceData, QuietHours, InboxCounts, ContextCount, ContextReference, ReminderReference, SweepReport, PruneReport, FiredReminders.
- Enums: Channel (inbox, mail), Priority (low, normal, urgent), DigestFrequency (off, daily, weekly), MailStrategy (leading, trailing), DeliveryStatus, DigestRunStatus, ReminderStatus (pending, firing, sent, cancelled, skipped), ReminderKind, InboxOutcome, MailOutcome, CancelReason and NotificationOperation. The user-facing ones carry translated labels.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.