Skip to main content

GET /api/notifications/subscribe

Establishes a Server-Sent Events (SSE) connection for receiving real-time notifications about order updates and other events.

Authentication

Requires a valid JWT access token passed as a query parameter (since EventSource API doesnโ€™t support custom headers).
GET /api/notifications/subscribe?token=YOUR_ACCESS_TOKEN
The token is passed in the URL query string, not in the Authorization header, because the browserโ€™s EventSource API cannot set custom headers.

Query parameters

token
string
required
Your JWT access token (without the โ€œBearer โ€ prefix)

Response

This endpoint returns a persistent SSE connection with Content-Type: text/event-stream. Events are sent as they occur.

Event format

Each event is sent as a JSON object with the following structure:
type
string
Event type (e.g., order_update, connected)
title
string
Human-readable event title
message
string
Event message
data
object
Event-specific data payload

Connection lifecycle

Initial connection

When you first connect, youโ€™ll receive a handshake event:
{
  "type": "connected",
  "message": "Notification stream connected."
}

Heartbeat

The server sends a heartbeat comment (: heartbeat\n\n) every 25 seconds to keep the connection alive through proxies and prevent timeouts.

Order update events

When an order status changes, youโ€™ll receive:
{
  "type": "order_update",
  "title": "Order Accepted โœ…",
  "message": "Your payment was confirmed and the store has accepted your order.",
  "data": {
    "orderId": "507f1f77bcf86cd799439011",
    "orderNumber": "CB20240115001",
    "status": "accepted"
  }
}

When order is ready for pickup

{
  "type": "order_update",
  "title": "Order Ready for Pickup ๐Ÿ””",
  "message": "Your order is ready! Head to the store and show the OTP to collect it.",
  "data": {
    "orderId": "507f1f77bcf86cd799439011",
    "orderNumber": "CB20240115001",
    "status": "ready",
    "otp": "123456"
  }
}

Example usage

JavaScript (Browser)

// Get your access token from localStorage or your auth state
const accessToken = localStorage.getItem('accessToken');

// Create EventSource connection
const eventSource = new EventSource(
  `https://api.campusbite.com/api/notifications/subscribe?token=${accessToken}`
);

// Handle connection opened
eventSource.addEventListener('open', () => {
  console.log('SSE connection established');
});

// Handle incoming messages
eventSource.addEventListener('message', (event) => {
  const notification = JSON.parse(event.data);
  console.log('Notification received:', notification);
  
  if (notification.type === 'order_update') {
    // Update UI with order status change
    updateOrderStatus(notification.data);
    
    // Show notification to user
    showNotification(notification.title, notification.message);
    
    // If order is ready, display OTP
    if (notification.data.status === 'ready' && notification.data.otp) {
      displayOtp(notification.data.otp);
    }
  }
});

// Handle errors
eventSource.addEventListener('error', (error) => {
  console.error('SSE error:', error);
  
  // EventSource will automatically try to reconnect
  // Close if you want to stop reconnection attempts
  // eventSource.close();
});

// Close connection when user logs out or navigates away
function cleanup() {
  eventSource.close();
}

React example

import { useEffect, useState } from 'react';

function useNotifications(accessToken) {
  const [notifications, setNotifications] = useState([]);
  const [connected, setConnected] = useState(false);

  useEffect(() => {
    if (!accessToken) return;

    const eventSource = new EventSource(
      `${import.meta.env.VITE_API_URL}/api/notifications/subscribe?token=${accessToken}`
    );

    eventSource.addEventListener('open', () => {
      setConnected(true);
    });

    eventSource.addEventListener('message', (event) => {
      const notification = JSON.parse(event.data);
      setNotifications((prev) => [notification, ...prev]);
    });

    eventSource.addEventListener('error', () => {
      setConnected(false);
    });

    return () => {
      eventSource.close();
    };
  }, [accessToken]);

  return { notifications, connected };
}

Notification types

Order status updates

StatusTitleWhen triggered
acceptedOrder Accepted โœ…Store confirms payment and accepts order
processingOrder Being Prepared ๐Ÿ‘จโ€๐ŸณStore starts preparing the order
readyOrder Ready for Pickup ๐Ÿ””Order is ready, OTP included
picked_upOrder Collected ๐Ÿฝ๏ธCustomer picks up order with OTP
cancelledOrder CancelledOrder is cancelled by store or system

Error responses

401 Missing token
{
  "success": false,
  "message": "Token required."
}
401 Invalid token
{
  "success": false,
  "message": "Invalid or expired token."
}
401 User not found
{
  "success": false,
  "message": "User not found."
}

Technical details

  • Protocol: Server-Sent Events (SSE) over HTTP
  • Content-Type: text/event-stream
  • Heartbeat interval: 25 seconds
  • Automatic reconnection: Handled by browserโ€™s EventSource API
  • Connection cleanup: Connection is automatically closed when user disconnects
The connection is persistent and will remain open until either the client closes it or the server restarts. The browser will automatically attempt to reconnect if the connection is lost.
Each user can have multiple SSE connections open (e.g., multiple tabs). All connections for the same user will receive the same notifications.

Build docs developers (and LLMs) love