API reference
Notifications
Push a notification into a user's IntelligenceBox desktop app — a title, a description, an icon, and a deep link that opens the right screen when clicked. Notifications are stored before they are delivered, so one sent while the app was closed reappears in the bell on the next launch instead of vanishing.
Delivery model
Every notification is written to the user’s feed first, then emitted over WebSocket to any connected app. If nobody is connected, the row is still there — this is what makes the API usable for build failures, nightly jobs and anything else that fires outside working hours.Send a notification#
/api/public/notificationsAPI keyCreates and delivers a notification. Returns the stored notification, including its id.
curl -X POST BOX_URL/api/public/notifications \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Deploy finished",
"description": "api-gateway v2.4.1 is live in production.",
"type": "success",
"category": "backgroundTasks",
"icon": "Rocket",
"name": "CI pipeline",
"deepLink": "/inter/chat/deploy-log-2f8a"
}'Request body
titlestringrequired- The headline. Shown as the toast title and the row title in the bell. Max 200 characters.
descriptionstring- The body text, shown under the title.
bodyis accepted as an alias. Max 2000 characters. type"info" | "success" | "error"- Drives the accent colour and icon tone. Errors also hold the toast on screen longer.Default:
"info". categorystring- Groups the notification and picks its default glyph. See categories.Default:
"system". deepLinkstring- In-app route opened when the notification is clicked, e.g.
/calendar. Must start with/— see deep links. iconstring- A Lucide icon name in PascalCase, e.g.
Rocket,AlertTriangle,Package. namestring- Who the notification is from, e.g. "CI pipeline". Rendered next to the icon.
senderobject- Full control over the leading visual — see sender. Takes precedence over
iconandname. previewstring- Short secondary line. Preferred over description when both are set.
readboolean- Create it already read. It lands in history without raising the unread badge — useful for audit-trail entries.Default:
false. dedupeKeystring- Collapses repeats: a second send with the same key refreshes the existing row instead of stacking a new one.
resurfaceboolean- Only meaningful with
dedupeKey. Setfalsefor a persistent state (“sync is paused”) so it is announced once and stays quiet on every later identical send.Default:true. silentToastboolean- Keep the OS popup and the bell row, skip the in-app toast.Default:
false. silentboolean- Persist only. The row appears in the bell with no popup and no toast.Default:
false. chatIdstring- Opens this conversation on click and adds an "Open chat" action to the toast.
userIdstring- Deliver to another user instead of the key owner. Requires an organization context — see sending to someone else.
metadataobject- Arbitrary JSON echoed back when the notification is read. Max 8 KB serialised.
Response
{
"delivered": true,
"persisted": true,
"notification": {
"id": "5c1e0f2a-9d84-4a1b-8f3c-2b7e0a6d1f45",
"title": "Deploy finished",
"description": "api-gateway v2.4.1 is live in production.",
"type": "success",
"category": "backgroundTasks",
"deepLink": "/inter/chat/deploy-log-2f8a",
"chatId": null,
"icon": "Rocket",
"sender": { "kind": "system", "name": "CI pipeline", "icon": "Rocket" },
"read": false,
"seen": false,
"createdAt": "2026-08-03T09:14:22.401Z"
}
}201Created and delivered.202Delivered live but not stored (persisted: false). The user sees it now; it will not be in the bell later.400Validation failed — check details for the offending field.403Recipient is outside the organization workspace.
Icon, name and avatar#
The leading visual is picked from the sender object. Four kinds, each rendering differently.
kind"system" | "user" | "assistant" | "email"systemrendersiconas a glyph;userandassistantrenderimageUrlas an avatar;emailrenders sender initials.Default:"system".namestring- Display name shown beside the notification.
imageUrlstring- Absolute URL to an avatar image. Used by the user and assistant kinds.
iconstring- Lucide icon name, used when there is no image.
colorstring- Hex tint for the glyph background, e.g. #3B82F6.
emailstring- Sender address — drives the initials fallback for the email kind.
{
"title": "Marco Rossi mentioned you",
"description": "\"can you review the Q3 numbers?\"",
"category": "messaging",
"deepLink": "/messaggi",
"sender": {
"kind": "user",
"name": "Marco Rossi",
"imageUrl": "https://example.com/avatars/marco.jpg"
}
}Shorthand
For the common system case you can skip the object entirely and sendicon and name at the top level. They are folded into a system sender for you.Deep links#
Where clicking the notification takes the user. Any in-app route works; these are the ones you will reach for.
| Route | Opens |
|---|---|
/inter/chat/:chatId | A specific conversation |
/dc/vector/:vectorId | A folder and its documents |
/assistants | The assistant list |
/calendar | The calendar |
/email | The unified inbox |
/messaggi | Messaging |
/messaggi?channel=:id | One messaging channel |
/contacts | The address book |
/work | Work management |
/recordings | Audio recordings |
/workbox | Workbox automations |
/settings | Settings |
In-app routes only
deepLink must start with /. Absolute URLs are rejected with a 400: the app hands the value to its own router, so an https:// value would be a dead click at best.When several targets are present the most specific one wins: chatId beats deepLink. A chatId also adds an explicit “Open chat” button to the toast.
Categories#
The category decides the default glyph, the label on the bell row, and which user preference can mute it.
| Category | Use it for | Mutable |
|---|---|---|
system | Anything that does not fit elsewhere | No |
backgroundTasks | Jobs, builds, imports, long-running work | Yes |
chat | AI runs and completions | Yes |
calendar | Reminders and events | Yes |
email | Mail activity | Yes |
messaging | Messages and mentions | No |
scheduler | Scheduled runs | Yes |
contacts | Contact enrichment and sync | Yes |
transcription | Audio transcription | Yes |
misconduct | Security and moderation | Yes |
appUpdates | App update availability | Yes |
Mutable categories can be switched off by the user
Categories marked mutable map onto a toggle in Settings → Notifications. If the user has turned one off, your notification is accepted but not shown. For alerts that must always arrive, usesystem or messaging — neither is user-gated.Avoiding notification spam#
Two knobs for jobs that run on a schedule and keep reporting the same thing.
Refresh one row instead of stacking
A build that reports progress every minute should not leave sixty rows in the bell. Give every send the same dedupeKey and each one updates the existing row in place, marking it unread again.
{
"title": "Indexing 340/1200 documents",
"category": "backgroundTasks",
"dedupeKey": "index-run:2026-08-03"
}Announce a persistent state once
A condition that is still true — a paused sync, an expired credential — should be announced once, not on every poll. Add resurface: false: the first send notifies, and every later identical send is silently absorbed.
{
"title": "SharePoint sync paused",
"description": "Credentials expired — reconnect in Settings.",
"type": "error",
"dedupeKey": "sync-paused:sharepoint",
"resurface": false
}Sending to someone else#
By default a notification goes to the user who owns the API key. To notify a colleague, send their userId together with an organization context — both accounts must belong to the same organization workspace.
curl -X POST BOX_URL/api/public/notifications \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORG_ID" \
-H "Content-Type: application/json" \
-d '{
"title": "Invoice awaiting approval",
"description": "INV-2026-0412 from Acme Srl — €12,480.",
"userId": "8f2c1d40-33ab-4e7e-9c15-6a0b2e91d774",
"deepLink": "/work"
}'403Either no organization header was sent, or the recipient is not part of that workspace.
List notifications#
/api/public/notificationsAPI keyNotifications for the key owner, newest first.
limitinteger- How many to return, 1–200.Default:
50. offsetinteger- Rows to skip, for paging.Default:
0. unreadOnlyboolean- Return only unread notifications.
categorystring- Filter to one category.
curl "BOX_URL/api/public/notifications?unreadOnly=true&limit=20" \
-H "x-api-key: YOUR_API_KEY"{
"notifications": [ /* … */ ],
"unreadCount": 3,
"pagination": { "total": 41, "limit": 20, "offset": 0, "hasMore": true }
}Unread count#
/api/public/notifications/unread-countAPI keyJust the number, for a badge somewhere else.
{ "count": 3 }Get one notification#
/api/public/notifications/:idAPI keyThe full stored notification, including its metadata.
Mark read or unread#
/api/public/notifications/:idAPI keyreadboolean- Mark it read (which also marks it seen) or return it to unread.
seenboolean- Record that it was delivered without clearing the unread badge.
curl -X PATCH BOX_URL/api/public/notifications/5c1e0f2a-9d84-4a1b-8f3c-2b7e0a6d1f45 \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "read": true }'Mark everything read#
/api/public/notifications/read-allAPI key{ "updated": 12 }Delete a notification#
/api/public/notifications/:idAPI keyRemoves it from the feed permanently.
{ "success": true }Recipes#
Alert on a failed job, with a link to the logs
curl -X POST BOX_URL/api/public/notifications \
-H "x-api-key: $BOX_KEY" -H "Content-Type: application/json" \
-d '{
"title": "Nightly import failed",
"description": "12 of 340 invoices could not be parsed.",
"type": "error",
"category": "backgroundTasks",
"icon": "AlertTriangle",
"name": "Invoice importer",
"deepLink": "/dc/vector/'"$FOLDER_ID"'",
"dedupeKey": "import-failure:invoices"
}'File a quiet audit entry
silent plus read: true writes to the history without a popup, a toast, or an unread badge — a log line the user can find if they go looking.
{
"title": "Contract archived",
"description": "MSA-Acme-2026.pdf moved to Legal / Archive.",
"category": "system",
"silent": true,
"read": true,
"metadata": { "documentId": "b71f…", "actor": "retention-bot" }
}Related: run an assistant and notify the user when it finishes, or look up the recipient behind your API key.