Documentation Index
Fetch the complete documentation index at: https://atp.hypertext.studio/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Server-Sent Events (SSE) endpoint provides an alternative method for real-time notification delivery using HTTP-based server-push technology. This approach is beneficial for clients that cannot maintain WebSocket connections due to proxy limitations or require a simpler implementation.
Connection
Endpoint: GET /api/v1/client/events
Authentication: Requires Bearer token using user credentials
Connection Query Parameters
| Parameter | Type | Required | Description |
|---|
token | string | Yes | User authentication token (alternative to Authorization header) |
last_event_id | string | No | ID of the last received event for reconnection purposes |
types | string | No | Comma-separated list of event types to subscribe to (default: all) |
client_id | string | No | Client identifier for correlation (UUID recommended) |
version | string | No | Protocol version for compatibility (defaults to latest) |
Connection Example
// Create EventSource connection to SSE endpoint
const eventSource = new EventSource('https://atp.example.com/api/v1/client/events?token=user_token_xyz789');
// Handle connection open
eventSource.onopen = () => {
console.log('Connected to ATP notification stream via SSE');
};
// Handle notification events
eventSource.addEventListener('notification', (event) => {
const notification = JSON.parse(event.data);
console.log('Received notification:', notification);
// Store last event ID for reconnection
if (event.lastEventId) {
localStorage.setItem('last_event_id', event.lastEventId);
}
// Process notification
handleNotification(notification);
});
// Handle status update events
eventSource.addEventListener('status_update', (event) => {
const statusUpdate = JSON.parse(event.data);
console.log('Status update:', statusUpdate);
handleStatusUpdate(statusUpdate);
});
// Handle connection error
eventSource.onerror = (error) => {
console.error('SSE connection error:', error);
// Check if the connection was closed
if (eventSource.readyState === EventSource.CLOSED) {
console.log('Connection closed. EventSource will automatically attempt to reconnect.');
}
};
// Function to manually close the connection if needed
function closeConnection() {
eventSource.close();
console.log('SSE connection closed manually');
}
SSE messages are formatted according to the EventSource specification with event types and JSON data payloads:
event: notification
id: 1622145123-abc123
data: {"id":"550e8400-e29b-41d4-a716-446655440000","version":"1.0",...}
Event Types
The following event types are supported:
| Event Type | Description |
|---|
notification | New notification available for the user |
status_update | Status change for an existing notification |
error | Error condition related to the connection |
ping | Server heartbeat to maintain connection |
Notification Event
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"version": "1.0",
"timestamp": "2025-05-25T10:30:00Z",
"deadline": "2025-05-25T11:00:00Z",
"service": {
"id": "lovelace-ide",
"name": "Lovelace IDE",
"icon": "https://lovelace.dev/icon.png"
},
"context": {
"title": "Deploy to Production?",
"description": "New version 2.1.0 is ready for deployment to production servers.",
"project": "backend-api",
"metadata": {
"version": "2.1.0",
"changes": 47,
"test_coverage": "98.3%"
}
},
"actions": [
{
"id": "approve",
"label": "Approve Deployment",
"response_type": "simple",
"flags": ["irreversible"]
},
{
"id": "reject",
"label": "Reject",
"response_type": "text",
"constraints": {
"placeholder": "Reason for rejection"
}
}
]
}
Status Update Event
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "invalidated",
"reason": "The deployment was canceled by the system",
"timestamp": "2025-05-25T10:32:15Z"
}
Error Event
{
"code": "RATE_LIMIT_EXCEEDED",
"message": "Client has exceeded connection rate limit",
"request_id": "req_abc123def456"
}
Ping Event
{
"timestamp": "2025-05-25T10:31:00Z"
}
Reconnection
One of the key advantages of Server-Sent Events is the built-in reconnection mechanism provided by the browser’s EventSource implementation. When a connection is lost, the browser will automatically attempt to reconnect with exponential backoff.
The SSE protocol uses the Last-Event-ID header for resuming the stream from where it left off. When reconnecting, the client should include the last received event ID to ensure no events are missed:
// Store last event ID when receiving events
eventSource.addEventListener('notification', (event) => {
if (event.lastEventId) {
localStorage.setItem('last_event_id', event.lastEventId);
}
// Process event...
});
// When manually reconnecting, include the last event ID
function reconnect() {
const lastEventId = localStorage.getItem('last_event_id');
const url = `https://atp.example.com/api/v1/client/events?token=user_token_xyz789`;
if (lastEventId) {
url += `&last_event_id=${lastEventId}`;
}
if (eventSource) {
eventSource.close();
}
eventSource = new EventSource(url);
// Set up event listeners again...
}
Custom Reconnection Strategy
For applications that need more control over the reconnection behavior, you can implement a custom strategy:
function connectWithCustomReconnect() {
const MAX_RETRIES = 10;
const BASE_DELAY_MS = 1000;
let retryCount = 0;
let eventSource = null;
function connect() {
const lastEventId = localStorage.getItem('last_event_id');
let url = `https://atp.example.com/api/v1/client/events?token=user_token_xyz789`;
if (lastEventId) {
url += `&last_event_id=${lastEventId}`;
}
// Close existing connection if any
if (eventSource) {
eventSource.close();
}
// Create new connection
eventSource = new EventSource(url);
eventSource.onopen = () => {
console.log('Connected to ATP notification stream via SSE');
retryCount = 0; // Reset retry counter on successful connection
};
// Set up event listeners...
eventSource.onerror = (error) => {
console.error('SSE connection error:', error);
// Only handle closed connections
if (eventSource.readyState === EventSource.CLOSED) {
if (retryCount < MAX_RETRIES) {
// Calculate delay with exponential backoff and jitter
const delay = Math.min(
BASE_DELAY_MS * Math.pow(2, retryCount) + Math.random() * 1000,
60000 // Cap at 60 seconds
);
console.log(`Connection closed. Retrying in ${delay}ms...`);
retryCount++;
setTimeout(connect, delay);
} else {
console.error('Maximum retry attempts reached. Giving up.');
}
}
};
}
connect();
// Return control functions
return {
close: () => {
if (eventSource) {
eventSource.close();
}
},
reconnect: () => {
retryCount = 0;
connect();
}
};
}
const connection = connectWithCustomReconnect();
Limitations
- Maximum of 10 concurrent SSE connections per user
- Connection timeout: 120 seconds of inactivity
- Reconnection delay: Controlled by client with server-suggested 3-second initial delay
- Maximum event size: 512KB
Browser Compatibility
Server-Sent Events are supported in all modern browsers:
- Chrome 6+
- Firefox 6+
- Safari 5+
- Edge 79+
- Opera 11.5+
For older browsers or environments without native EventSource support, polyfills are available.
Advantages Over WebSockets
While WebSockets provide bidirectional communication, SSE offers several advantages for notification delivery:
- Simpler Implementation: No need to handle message framing or connection state
- Automatic Reconnection: Built-in reconnection with message resumption
- Better Proxy Support: Works over standard HTTP, avoiding firewall/proxy issues
- Event Filtering: Subscribe to specific event types
- Less Overhead: Lower connection maintenance overhead for unidirectional communication
Best Practices
- Store Last Event ID: Always persist the last event ID for reliable reconnection
- Handle Backpressure: Process events asynchronously to avoid blocking the event stream
- Implement Timeout Handling: Close and reconnect if no events are received within the expected interval
- Graceful Degradation: Fall back to polling if SSE is not supported or continuously fails
- Connection Monitoring: Track connection state and implement health checks
- Memory Management: Close EventSource when component is unmounted to prevent memory leaks