Desktop Notifications Over HTTP.
Send Linux desktop notifications to any container display with a single HTTP POST. The Notification Server calls notify-send on your container's X11 display — trigger, fetch history, or stream live.
# Send a notification to display 0
curl -X POST ".../notify"
-d '["display":"0","summary":"Build Complete","urgency":"normal"]'
# Response
["message":"Notification sent successfully","success":true]
Three Steps. One HTTP Call Each.
Every notification follows the same lifecycle: trigger it, fetch the history or stream it live, then dismiss it when done.
Trigger
POST /notify sends a notify-send call to the target X11 display. Supply display, summary, and optionally urgency, body, expire_time, or icon.
# Fire a notification
POST /notify
{"display":"0",
"summary":"Build Complete",
"urgency":"normal"}
'{'"success":true'}'
Fetch or Stream
GET /[display] retrieves notification history with optional limit, since, username, and session filters. Connect via WebSocket to /stream?displays=0 for real-time push updates.
# Poll history
curl ".../0?limit=50"
# Or open a WebSocket
new WebSocket(
"wss://.../stream?displays=0"
)
Dismiss
POST /dismiss marks notification IDs as dismissed — they are filtered from subsequent GET responses. DELETE /dismiss clears the dismissed state, making them visible again.
# Dismiss by ID
POST /dismiss
{"displayId":"0",
"notificationIds":[10,11,12]}
# Clear dismissed state
DELETE /dismiss?displayId=0
low. normal. critical.
Three urgency levels map directly to notify-send behavior. Pick the right one and the notification daemon handles the rest.
Dismisses quickly. Set expire_time: 3000 for background tasks, telemetry, or informational pings that should not interrupt focus.
"urgency": "low",
"expire_time": 3000
Standard. Default when urgency is omitted. The notification daemon shows it at the configured timeout and dismisses automatically.
"urgency": "normal"
// default — omit to use this
Persistent — requires manual dismissal. Set expire_time: 0 for system failures, build errors, or anything that needs immediate action.
"urgency": "critical",
"expire_time": 0
Fetch History or Stream Live.
Two read channels serve different needs: REST for audit logs and one-shot queries, WebSocket for dashboards and real-time monitors.
Pull notification history for a display. Filter by limit, since timestamp, username, or session ID. Use for audit logs, one-shot queries, and batch processing.
# get last 50 for display 0
curl ".../0?limit=50"
# time-filtered
curl ".../0?since=1749025000000"
JSON array of notification objects with id, summary, urgency, timestamp, and icon_url.
Subscribe to one or more displays with displays=0,:1,2 or displays=all. Receives push messages as they arrive. Use for dashboards and real-time monitoring.
# open a WebSocket
const ws = new WebSocket(
"wss://.../stream?displays=0"
)
# on message
ws.onmessage = (e) => {
const msg = JSON.parse(e.data)
// msg.type === 'notification'
}
[ type: "notification", data: [ id, summary, urgency, timestamp ] ] pushed on every new notification.
From Build Pipelines to ML Jobs.
Anywhere a long-running process needs to signal completion or failure, one HTTP POST is all it takes.
CI/CD Alerts
Long-running builds complete. HTTP POST triggers a notification on the container display — visible in any active display session.
System Monitoring
Server alerts route to a desktop notification on the container's X11 display, visible in any active display session.
Long-Running Tasks
Data exports, video rendering, ML model training, backup completion — notify when done without polling.
Automated Workflows
Cron jobs, scheduled tasks, and automation scripts notify the container display on completion or failure.
8 Endpoints. One Notification Server.
Trigger, fetch, stream, and dismiss desktop notifications — plus icons and health monitoring — all over plain HTTP.
Trigger
{count, plural, =1 {# endpoint} other {# endpoints}'}POST .../api/v1/notifications/notify → {"success":true}
Fetch & Stream
{count, plural, =1 {# endpoint} other {# endpoints}'}GET .../api/v1/notifications/{display}?limit=50&since=...
Icons
{count, plural, =1 {# endpoint} other {# endpoints}'}GET .../api/v1/notifications/icons/{iconId} → image/png
Health & Metrics
{count, plural, =1 {# endpoint} other {# endpoints}'}GET .../api/v1/notifications/health → {"status":"UP"}
Notifications Are One HTTP POST Away.
Any script, service, or automation that can make an HTTP request can send a desktop notification to your container display.