Poll Events
Retrieve monitoring events efficiently for real-time alerting and analytics systems.
Overview
Event polling enables continuous monitoring of asset activities without missing events. The API supports both historical queries and incremental polling for real-time systems.
Use Case
A fleet management system needs to:
- Retrieve new events since last poll
- Process events in order for accurate tracking
- Build real-time dashboards showing asset activities
- Trigger alerts based on event patterns
Polling Strategy
Example 1: Basic Event Polling
Poll for new events since last check.
- cURL
- JavaScript
curl -X GET https://api.magiclane.net/api/v1/poll_monitor_events \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"p_last_poll_timestamp": 1754810032,
"p_limit": 100,
"p_sort_order": "asc"
}'
const pollEvents = async (lastTimestamp, limit = 100) => {
const response = await fetch(
'https://api.magiclane.net/api/v1/poll_monitor_events',
{
method: 'GET',
headers: {
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
p_last_poll_timestamp: lastTimestamp,
p_limit: limit,
p_sort_order: 'asc' // Oldest first for sequential processing
})
}
);
const data = await response.json();
console.log(`Retrieved ${data.data.monitor_events.length} events`);
return data;
};
// Example usage
const events = await pollEvents(1754810032, 100);
Response Structure
{
"data": {
"monitor_events": [
{
"asset_id": "vehicle_101",
"event_type": "enter",
"monitor_id": "delivery_zone_monitor",
"geofence_id": "downtown_delivery_zone",
"event_location": {
"lat": 45.647265,
"lon": 25.612887
},
"event_timestamp": 1754810100,
"previous_location": {
"lat": 45.646980,
"lon": 25.611922
}
},
{
"asset_id": "truck_205",
"event_type": "speeding",
"monitor_id": "fleet_speed_monitor",
"event_location": {
"lat": 45.648579,
"lon": 25.614076
},
"event_timestamp": 1754810150
}
]
}
}
Example 2: Continuous Polling Loop
Implement a continuous event monitoring system.
- JavaScript
class EventPoller {
constructor(apiKey, pollInterval = 30000) {
this.apiKey = apiKey;
this.pollInterval = pollInterval; // 30 seconds
this.lastTimestamp = Math.floor(Date.now() / 1000);
this.isRunning = false;
}
async poll() {
try {
const response = await fetch(
'https://api.magiclane.net/api/v1/poll_monitor_events',
{
method: 'GET',
headers: {
'Authorization': this.apiKey,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
p_last_poll_timestamp: this.lastTimestamp,
p_limit: 5000,
p_sort_order: 'asc'
})
}
);
const data = await response.json();
const events = data.data.monitor_events;
if (events.length > 0) {
// Process events
await this.processEvents(events);
// Update last timestamp to newest event
this.lastTimestamp = Math.max(
...events.map(e => e.event_timestamp)
);
console.log(`Processed ${events.length} events. Last timestamp: ${this.lastTimestamp}`);
} else {
console.log('No new events');
}
return events;
} catch (error) {
console.error('Polling error:', error);
throw error;
}
}
async processEvents(events) {
for (const event of events) {
// Handle different event types
switch (event.event_type) {
case 'enter':
await this.handleEntry(event);
break;
case 'exit':
await this.handleExit(event);
break;
case 'speeding':
await this.handleSpeeding(event);
break;
case 'idle':
await this.handleIdle(event);
break;
}
}
}
async handleEntry(event) {
console.log(`Asset ${event.asset_id} entered ${event.geofence_id}`);
// Send notification, update database, etc.
}
async handleExit(event) {
console.log(`Asset ${event.asset_id} exited ${event.geofence_id}`);
}
async handleSpeeding(event) {
console.log(`Asset ${event.asset_id} speeding detected`);
// Send alert
}
async handleIdle(event) {
console.log(`Asset ${event.asset_id} idle detected`);
}
start() {
if (this.isRunning) return;
this.isRunning = true;
console.log(`Event poller started (interval: ${this.pollInterval}ms)`);
this.intervalId = setInterval(async () => {
if (this.isRunning) {
await this.poll();
}
}, this.pollInterval);
}
stop() {
this.isRunning = false;
if (this.intervalId) {
clearInterval(this.intervalId);
console.log('Event poller stopped');
}
}
}
// Usage
const poller = new EventPoller('YOUR_API_KEY', 30000);
poller.start();
// Stop after 1 hour
setTimeout(() => {
poller.stop();
}, 3600000);
Sort Order Strategy
ASC (Ascending) - For Polling
{
p_sort_order: 'asc' // Oldest events first
}
✅ Best for: Sequential processing, avoiding duplicates
- Events processed in chronological order
- Easier to track last processed timestamp
- Recommended for continuous polling
DESC (Descending) - For Display
{
p_sort_order: 'desc' // Newest events first
}
✅ Best for: Dashboards, recent activity views
- Shows most recent events first
- Good for UI displays
- Not recommended for polling loops
Limit Guidelines
| Limit | Use Case | Polling Interval |
|---|---|---|
| 100 | Low-traffic systems | 60 seconds |
| 1,000 | Medium traffic | 30 seconds |
| 5,000 | High traffic | 15-30 seconds |
| 10,000 | Maximum (batch processing) | As needed |
Example 3: Event Analytics
Analyze polled events for insights.
- JavaScript
class EventAnalytics {
constructor(apiKey) {
this.apiKey = apiKey;
this.events = [];
}
async pollAndAnalyze(startTimestamp, endTimestamp) {
let currentTimestamp = startTimestamp;
while (currentTimestamp < endTimestamp) {
const response = await fetch(
'https://api.magiclane.net/api/v1/poll_monitor_events',
{
method: 'GET',
headers: {
'Authorization': this.apiKey,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
p_last_poll_timestamp: currentTimestamp,
p_limit: 10000,
p_sort_order: 'asc'
})
}
);
const data = await response.json();
const events = data.data.monitor_events;
if (events.length === 0) break;
this.events.push(...events);
currentTimestamp = Math.max(...events.map(e => e.event_timestamp));
}
return this.analyze();
}
analyze() {
const stats = {
total_events: this.events.length,
by_type: {},
by_asset: {},
by_monitor: {},
time_range: {
start: Math.min(...this.events.map(e => e.event_timestamp)),
end: Math.max(...this.events.map(e => e.event_timestamp))
}
};
// Count by event type
this.events.forEach(event => {
stats.by_type[event.event_type] =
(stats.by_type[event.event_type] || 0) + 1;
stats.by_asset[event.asset_id] =
(stats.by_asset[event.asset_id] || 0) + 1;
stats.by_monitor[event.monitor_id] =
(stats.by_monitor[event.monitor_id] || 0) + 1;
});
// Find most active asset
stats.most_active_asset = Object.entries(stats.by_asset)
.sort((a, b) => b[1] - a[1])[0];
return stats;
}
}
// Usage
const analytics = new EventAnalytics('YOUR_API_KEY');
const stats = await analytics.pollAndAnalyze(
1754810000, // Start time
1754820000 // End time
);
console.log(stats);
/* Output:
{
total_events: 245,
by_type: {
enter: 98,
exit: 97,
speeding: 35,
idle: 15
},
by_asset: {
vehicle_101: 82,
truck_205: 76,
bike_301: 87
},
most_active_asset: ['bike_301', 87]
}
*/
Handling Event Bursts
When many events occur simultaneously:
- JavaScript
async function handleEventBurst(lastTimestamp) {
const batchSize = 5000;
let allEvents = [];
let currentTimestamp = lastTimestamp;
let hasMore = true;
while (hasMore) {
const response = await fetch(
'https://api.magiclane.net/api/v1/poll_monitor_events',
{
method: 'GET',
headers: {
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
p_last_poll_timestamp: currentTimestamp,
p_limit: batchSize,
p_sort_order: 'asc'
})
}
);
const data = await response.json();
const events = data.data.monitor_events;
if (events.length === 0) {
hasMore = false;
} else {
allEvents.push(...events);
if (events.length < batchSize) {
hasMore = false;
} else {
// More events might exist, update timestamp and continue
currentTimestamp = Math.max(...events.map(e => e.event_timestamp));
}
}
}
return allEvents;
}
Error Handling Example
- JavaScript
async function pollWithRetry(lastTimestamp, maxRetries = 3) {
let retries = 0;
while (retries < maxRetries) {
try {
const response = await fetch(
'https://api.magiclane.net/api/v1/poll_monitor_events',
{
method: 'GET',
headers: {
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
p_last_poll_timestamp: lastTimestamp,
p_limit: 1000,
p_sort_order: 'asc'
})
}
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
retries++;
console.error(`Poll attempt ${retries} failed:`, error);
if (retries < maxRetries) {
// Exponential backoff
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, retries)));
} else {
throw error;
}
}
}
}
Real-Time Dashboard Example
- JavaScript
class RealtimeDashboard {
constructor(apiKey) {
this.apiKey = apiKey;
this.lastTimestamp = Math.floor(Date.now() / 1000) - 3600; // Last hour
this.stats = {
entries: 0,
exits: 0,
speeding: 0,
idle: 0
};
}
async update() {
const events = await this.pollEvents();
this.updateStats(events);
this.render();
}
async pollEvents() {
const response = await fetch(
'https://api.magiclane.net/api/v1/poll_monitor_events',
{
method: 'GET',
headers: {
'Authorization': this.apiKey,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
p_last_poll_timestamp: this.lastTimestamp,
p_limit: 100,
p_sort_order: 'asc'
})
}
);
const data = await response.json();
return data.data.monitor_events;
}
updateStats(events) {
events.forEach(event => {
if (event.event_type === 'enter') this.stats.entries++;
if (event.event_type === 'exit') this.stats.exits++;
if (event.event_type === 'speeding') this.stats.speeding++;
if (event.event_type === 'idle') this.stats.idle++;
});
if (events.length > 0) {
this.lastTimestamp = Math.max(...events.map(e => e.event_timestamp));
}
}
render() {
console.log('Dashboard Stats:');
console.log(`Entries: ${this.stats.entries}`);
console.log(`Exits: ${this.stats.exits}`);
console.log(`Speeding: ${this.stats.speeding}`);
console.log(`Idle: ${this.stats.idle}`);
}
start(interval = 30000) {
setInterval(() => this.update(), interval);
}
}
// Usage
const dashboard = new RealtimeDashboard('YOUR_API_KEY');
dashboard.start(30000); // Update every 30 seconds
Notes
- Use
ascsort order for polling - Store last timestamp persistently
- Process events in batches
- Use appropriate poll intervals (30-60s)
- Implement retry logic
- Don't use
descfor continuous polling