Skip to main content

Notifications

In-app notifications, email alerts, user preferences, and real-time delivery.

Base path:

/api/v1/{workspace_id}/notifications/

List notifications​

GET /api/v1/{workspace_id}/notifications/
Authorization: Bearer <token>

Unread count​

GET /api/v1/{workspace_id}/notifications/unread-count/

Mark read / archive​

POST /api/v1/{workspace_id}/notifications/mark-all-read/
PATCH /api/v1/{workspace_id}/notifications/{notification_id}/read/
PATCH /api/v1/{workspace_id}/notifications/{notification_id}/archive/
DELETE /api/v1/{workspace_id}/notifications/{notification_id}/

Preferences​

GET /api/v1/{workspace_id}/notifications/preferences/
PATCH /api/v1/{workspace_id}/notifications/preferences/

In-app (App) and Email channels are independent per category.

ChannelFieldDefault (no saved row)
App (bell + WebSocket)in_app_enabledtrue
Email (Resend)email_enabledfalse

GET response shape​

{
"daily_digest_enabled": true,
"categories": [
{
"category": "lead",
"in_app_enabled": true,
"email_enabled": false
}
]
}

Categories: task, lead, demo_booking, event, expense, admin.

PATCH example​

{
"daily_digest_enabled": true,
"categories": [
{
"category": "task",
"in_app_enabled": true,
"email_enabled": true
},
{
"category": "lead",
"in_app_enabled": false,
"email_enabled": true
}
]
}

Daily digest​

When daily_digest_enabled is true, a morning email is sent (via Celery Beat) listing overdue and due-today tasks assigned to the user in that workspace. No digest is sent if there are no matching tasks.

WebSocket (real-time in-app)​

wss://events.pana.space/ws/notifications/?token=<access_token>

Used by the web app for live in-app notification updates when in_app_enabled is on.

Mobile push (FCM)​

The FCM token identifies an app install, not a user. The backend stores which user is logged in on that install. A push is sent only when an in-app notification is created or updated (in_app_enabled is on). Registering a device does not replay the inbox.

Mobile implementation steps, payloads, and responses: Mobile push (FCM).

Requires FIREBASE_CREDENTIALS_JSON or FIREBASE_CREDENTIALS_PATH on the backend. Without it, register and unregister still succeed and pushes are skipped.

Register (after login, and on token refresh)​

POST /api/v1/devices/
Authorization: Bearer <token>
Content-Type: application/json

{ "fcm_token": "<firebase token>", "platform": "ios" }

platform is ios or android. If this token was stored for another user, it is reassigned to the current user.

Unregister (on logout)​

DELETE /api/v1/devices/
Authorization: Bearer <token>
Content-Type: application/json

{ "fcm_token": "<firebase token>" }

Deletes the row only when it belongs to the current user.

Push data includes notification_id, workspace_id, category, verb, target_url, target_type, and target_id. A token Firebase reports as unregistered is removed.

Email delivery​

When email_enabled is true for a category, the platform sends a transactional email (React Email + Resend) when that notification fires. Requires RESEND_API_KEY on the backend.

Emails include a link back to the relevant record in the app and a link to notification settings.

Webhooks​

The same domain events that create notifications can trigger outbound developer webhooks. See Webhooks.