Real-Time Streams
The Streaming API provides real-time updates using Server-Sent Events (SSE). This lightweight protocol allows you to receive push notifications for order updates without the overhead of WebSockets or constant polling.
Overview
Server-Sent Events (SSE) is a standard allowing servers to push data to web clients over HTTP. Our implementation provides:
- Real-time order status updates
- Automatic reconnection handling
- Minimal bandwidth usage
- Simple client implementation
Order Stream
Subscribe to real-time order updates for your entity. Updates are pushed immediately when order status changes occur.
Endpoint
GET https://api.paperinvest.io/v1/orders/stream
Query Parameters
Parameter | Type | Description | Required |
---|---|---|---|
accountId | String | Filter updates for specific account (optional) | No |
Connection Examples
JavaScript
// Browser/Node.js example
const eventSource = new EventSource(
'https://api.paperinvest.io/v1/orders/stream?accountId=550e8400-e29b-41d4-a716-446655440000',
{
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
}
);
// Handle order updates
eventSource.addEventListener('order-update', (event) => {
const order = JSON.parse(event.data);
console.log('Order update:', order);
updateOrderUI(order);
});
// Handle heartbeat
eventSource.addEventListener('heartbeat', (event) => {
console.log('Connection alive');
});
// Handle errors
eventSource.addEventListener('error', (event) => {
if (event.data) {
const error = JSON.parse(event.data);
console.error('Stream error:', error.message);
}
});
// Handle connection errors
eventSource.onerror = (error) => {
console.error('Connection error:', error);
// EventSource will automatically reconnect
};
// Clean up when done
// eventSource.close();
Event Types
The stream emits different event types to handle various scenarios:
Event Type | Description | Frequency |
---|---|---|
order-update | Order status change or fill update | On order changes |
heartbeat | Keep-alive signal | Every 30 seconds |
error | Stream error notification | On errors |
Order Update Payload
Each order-update
event contains essential order information. For complete order details, use the Get Order endpoint.
Order Update Event
{
"orderId": "123e4567-e89b-12d3-a456-426614174000",
"accountId": "550e8400-e29b-41d4-a716-446655440000",
"portfolioId": "8b72f1a5-c2e4-48d9-b5a3-1c7e5d3f9e8a",
"brokerId": "default",
"symbol": "AAPL",
"side": "BUY",
"status": "FILLED",
"quantity": 100,
"filledQuantity": 100,
"outstandingQuantity": 0,
"limitPrice": 150.00,
"createdAt": "2025-01-15T10:30:00Z"
}
Event Stream Format
SSE events follow a specific text-based format. Each event consists of fields separated by newlines:
Field | Description | Example |
---|---|---|
id | Unique identifier for the event (optional) | 123e4567-e89b-12d3-a456-426614174000 |
event | Event type name | order-update, heartbeat, error |
data | JSON payload containing event details | {"orderId":"...","status":"FILLED"...} |
retry | Reconnection time in milliseconds (optional) | 5000 |
Example Event Stream
SSE Event Stream
id: 123e4567-e89b-12d3-a456-426614174000
event: order-update
data: {"orderId":"123e4567-e89b-12d3-a456-426614174000","symbol":"AAPL","status":"FILLED","filledQuantity":100,"outstandingQuantity":0}
event: heartbeat
data: {"timestamp":"2025-01-15T10:30:30Z"}
id: 456e7890-e89b-12d3-a456-426614174111
event: order-update
data: {"orderId":"456e7890-e89b-12d3-a456-426614174111","symbol":"MSFT","status":"ACTIVE","filledQuantity":0,"outstandingQuantity":50}
Connection Management
Authentication
The streaming endpoint uses the same JWT token authentication as other API endpoints. Include your bearer token in the Authorization header.
Reconnection
SSE connections automatically reconnect on network interruptions. The EventSource API handles this transparently, using the last event ID to resume where it left off.
Connection Details
- Heartbeat interval: 30 seconds
- Automatic deduplication: Updates within 100ms are deduplicated
Best Practices
- Implement Error Handling: Always handle connection errors and stream errors separately
- Monitor Heartbeats: Use heartbeats to detect stale connections
- Efficient Updates: Process updates efficiently to avoid blocking the event loop
- Resource Cleanup: Close connections when no longer needed
Connection Management
class OrderStreamManager {
constructor(token, accountId) {
this.token = token;
this.accountId = accountId;
this.eventSource = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
}
connect() {
const url = new URL('https://api.paperinvest.io/v1/orders/stream');
if (this.accountId) {
url.searchParams.append('accountId', this.accountId);
}
this.eventSource = new EventSource(url, {
headers: {
'Authorization': `Bearer ${this.token}`
}
});
this.eventSource.addEventListener('order-update', (event) => {
this.handleOrderUpdate(JSON.parse(event.data));
});
this.eventSource.addEventListener('heartbeat', () => {
this.lastHeartbeat = Date.now();
});
this.eventSource.onerror = (error) => {
console.error('SSE Error:', error);
this.handleReconnect();
};
// Monitor heartbeats
this.heartbeatInterval = setInterval(() => {
if (Date.now() - this.lastHeartbeat > 60000) {
console.warn('No heartbeat for 60s, reconnecting...');
this.reconnect();
}
}, 10000);
}
handleOrderUpdate(order) {
// Process order update
console.log('Order update:', order);
}
handleReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
setTimeout(() => this.connect(), 1000 * this.reconnectAttempts);
} else {
console.error('Max reconnection attempts reached');
}
}
disconnect() {
if (this.eventSource) {
this.eventSource.close();
clearInterval(this.heartbeatInterval);
}
}
}
// Usage
const streamManager = new OrderStreamManager(
'YOUR_JWT_TOKEN',
'550e8400-e29b-41d4-a716-446655440000'
);
streamManager.connect();
See Also
- Orders API - Complete order management endpoints
- Authentication - How to obtain JWT tokens
- Rate Limiting - API usage limits