Notifications
The alerts feed - every action, every block, every depeg drift - and the shape of a Notification.
Notifications are Botanary's general alerts feed - its own tag description puts it plainly: "every action, every block, every depeg drift."
Endpoints
GET /notificationslists them, with an optionalunreadOnlyboolean query param (defaultfalse). It returns a plain array ofNotification.POST /notifications/{notificationId}/readmarks one as read, returning the updated notification (404if the id doesn't exist).POST /notifications/read-allmarks every notification read at once, returning204.
On the backend, all three are thin: the controller resolves the caller's signer address and delegates straight to the notifications service - list, mark-all-read, or mark-one-read.
The Notification shape
Required fields: id, tone, title, body, createdAt, read. Optional fields: timeLabel
(nullable), relatedType (nullable - links a notification back to a delegation, an activity event, or
a depeg event), relatedId (nullable), and action (nullable) - a NotificationAction of
{ label, target }, where target is a frontend deep-link key.
A real example from the contract: a notification titled "Action blocked," body "Uniswap tried to spend 120 USDC - over the 50 USDC per-action cap." - the kind of alert that surfaces a rules decline (see Rules & AgentGuard) directly in the feed rather than leaving you to go find it in the activity log.
Reading the feed on the frontend
The topbar notification popover marks a notification read then, if it carries an action.target,
navigates there - so an alert can double as a deep link into whatever it's actually about:
const markAll = $api.useMutation('post', '/notifications/read-all');
const markOne = $api.useMutation('post', '/notifications/{notificationId}/read');
const invalidate = () => queryClient.invalidateQueries({ queryKey: ['get', '/notifications'] });
const onMarkAll = () => markAll.mutate({}, { onSuccess: invalidate });Both mutations invalidate the notifications query on success, so the popover's own list stays in sync with whatever you just marked read.
TODO: whether notifications are poll-only or delivered through a push channel isn't confirmed in v1 - verify before documenting. What's confirmed today is the pattern above: mutate, then invalidate the list query, is how the frontend keeps the feed current.