The EyeOTmonitor API provides secure access to device monitoring data. This RESTful API uses JWT (JSON Web Token) authentication and supports account-based access control to ensure users can only access devices within their authorized accounts.
Production: https://api-c.eyeotmonitor.net/customer
All API requests require authentication. First, obtain a JWT token by logging in with your credentials.
Endpoint: POST /v1/auth/login
Request:
{
"username": "your_username",
"password": "your_password"
}
Response:
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires": "2025-07-16T10:30:00Z",
"accounts": [
{
"AccountId": "921184C4-5CF0-461D-8889-50E304170076",
"AccountName": "Gotham Pizza"
},
{
"AccountId": "980e4567-e89b-12d3-a456-426614174000",
"AccountName": "City of Metropolis"
}
]
}
}
Important Notes:
- Save the
token
for use in subsequent API calls - Note the
accounts
array - you can only access devices within these accounts - The token expires at the specified
expires
timestamp
Include the JWT token in the Authorization
header for all subsequent requests:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Retrieve metadata for all devices within a specific account.
Endpoint: GET /v1/devices
Required Query Parameters:
accountId
- The account ID to filter devices by (must be one of your authorized accounts)
Request:
GET /v1/devices?accountId=921184C4-5CF0-461D-8889-50E30417007
Authorization: Bearer your_jwt_token_here
Response:
{
"success": true,
"data": [
{
"DeviceId": "device-123",
"Name": "Outside Cam 01",
"ModelName": "Axis 360",
"SerialNumber": "TS001234",
"IPAddress": "192.168.1.100",
"MacAddress": "00:1B:44:11:3A:B7",
"Description": "Main facility monitoring",
"TypeId": 1,
"TypeName": "Axis Digital Camera",
"Status": "Online",
"StatusId": 1,
"LastStatusUpdate": "2025-07-15T14:30:00Z",
"AccountId": "921184C4-5CF0-461D-8889-50E30417007"
},
{
"DeviceId": "device-456",
"Name": "Indoor Cam",
"ModelName": "Axis 360",
"SerialNumber": "PM002345",
"IPAddress": "192.168.1.101",
"MacAddress": "00:1B:44:11:3A:B8",
"Description": "Secondary monitoring station",
"TypeId": 2,
"TypeName": "Axis Digital Camera",
"Status": "Offline",
"StatusId": 2,
"LastStatusUpdate": "2025-07-15T12:15:00Z",
"AccountId": "921184C4-5CF0-461D-8889-50E30417007"
}
]
}
Retrieve detailed metadata for a specific device.
Endpoint: GET /v1/devices/{deviceId}
Path Parameters:
deviceId
- The unique identifier of the device
Required Query Parameters:
accountId
- The account ID that owns the device
Request:
GET /v1/devices/device-123?accountId=921184C4-5CF0-461D-8889-50E30417007
Authorization: Bearer your_jwt_token_here
Response:
{
"success": true,
"data": {
"DeviceId": "device-123",
"Name": "Outside Cam 01",
"ModelName": "Axis 360",
"SerialNumber": "TS001234",
"IPAddress": "192.168.1.100",
"MacAddress": "00:1B:44:11:3A:B7",
"Description": "Main facility monitoring",
"TypeId": 1,
"TypeName": "Axis Digital Camera",
"Status": "Online",
"StatusId": 1,
"LastStatusUpdate": "2025-07-15T14:30:00Z",
"AccountId": "921184C4-5CF0-461D-8889-50E30417007"
}
}
Retrieve notifications and events for devices within a specific account from a specified date.
Endpoint: GET /v1/notifications-events
Required Query Parameters:
accountId
- The account ID to filter notifications and events by (must be one of your authorized accounts)from
- Start date for the query (ISO 8601 format: YYYY-MM-DDTHH:mm:ssZ)
Optional Query Parameters:
pageSize
- Number of results to return (default: 100, max: 1000)cursorId
- Cursor ID for pagination (use nextCursorId from previous response)
Request:
GET /v1/notifications-events?accountId=921184C4-5CF0-461D-8889-50E30417007&from=2025-07-28T00:00:00Z&pageSize=100
Authorization: Bearer your_jwt_token_here
Request with Cursor Pagination:
GET /v1/notifications-events?accountId=921184C4-5CF0-461D-8889-50E30417007&from=2025-07-28T00:00:00Z&pageSize=100&cursorId=12345
Authorization: Bearer your_jwt_token_here
Response:
{
"success": true,
"data": {
"notifications": [
{
"title": "Axis 360: Down state",
"message": "",
"severityLevelId": 50,
"severityLevel": "Critical",
"notificationEventId": 56,
"notificationEventName": "DeviceServiceStatusDown",
"deviceIdentifier": "3742d75e-7222-4a59-aae0-e20d62b70da8",
"timestamp": "2025-07-29T21:00:47.72",
"additionalDataJSON": "{}"
},
{
"title": "Camera Connection Lost",
"message": "Device connection timeout",
"severityLevelId": 30,
"severityLevel": "Warning",
"notificationEventId": 42,
"notificationEventName": "DeviceConnectionLost",
"deviceIdentifier": "8a2b4c6d-1234-5678-9012-3456789abcde",
"timestamp": "2025-07-29T20:45:12.34",
"additionalDataJSON": "{\"connectionType\":\"TCP\"}"
}
],
"nextCursorId": 12340
}
}
Response Fields:
notifications
- Array of notification and event objectsnextCursorId
- Cursor ID for the next page of results (null if no more results)
Pagination:
- Use the
nextCursorId
from the response to fetch the next page of results - Pass it as the
cursorId
parameter in subsequent requests - When
nextCursorId
is null, there are no more results to fetch
The API implements strict account-based access control:
- Account Validation: You can only access devices within accounts you're authorized for
- Required Parameters: The
accountId
parameter is required for all device operations - Access Denied: Attempting to access devices in unauthorized accounts returns a 403 Forbidden error
Status Code | Description | Example Response |
---|---|---|
400 | Bad Request - Missing required parameters | {"success": false, "message": "Account ID is required"} |
401 | Unauthorized - Invalid or missing token | {"success": false, "message": "Invalid or missing authentication token"} |
403 | Forbidden - Access denied to account | {"success": false, "message": "Access denied to account 'invalid-account-id'"} |
404 | Not Found - Device not found | {"success": false, "message": "Device with ID 'device-123' not found for account 'account-id'"} |
500 | Internal Server Error | {"success": false, "message": "An error occurred while retrieving devices"} |
All error responses follow this structure:
{
"success": false,
"message": "Error description here"
}
import requests
import json
class EyeOTClient:
def __init__(self, base_url):
self.base_url = base_url
self.token = None
self.accounts = []
def login(self, username, password):
"""Authenticate and get JWT token"""
response = requests.post(
f"{self.base_url}/v1/auth/login",
json={"username": username, "password": password},
headers={"Content-Type": "application/json"}
)
if response.status_code == 200:
data = response.json()['data']
self.token = data['token']
self.accounts = data['accounts']
return True
else:
raise Exception(f"Authentication failed: {response.text}")
def get_devices(self, account_id):
"""Get all devices for an account"""
headers = {"Authorization": f"Bearer {self.token}"}
params = {"accountId": account_id}
response = requests.get(
f"{self.base_url}/v1/devices",
headers=headers,
params=params
)
if response.status_code == 200:
return response.json()['data']
else:
raise Exception(f"Failed to get devices: {response.text}")
def get_device(self, device_id, account_id):
"""Get specific device by ID"""
headers = {"Authorization": f"Bearer {self.token}"}
params = {"accountId": account_id}
response = requests.get(
f"{self.base_url}/v1/devices/{device_id}",
headers=headers,
params=params
)
if response.status_code == 200:
return response.json()['data']
else:
raise Exception(f"Failed to get device: {response.text}")
def get_notifications_and_events(self, account_id, from_date, page_size=None, cursor_id=None):
"""Get notifications and events for an account from specified date"""
headers = {"Authorization": f"Bearer {self.token}"}
params = {
"accountId": account_id,
"from": from_date
}
if page_size is not None:
params["pageSize"] = page_size
if cursor_id is not None:
params["cursorId"] = cursor_id
response = requests.get(
f"{self.base_url}/v1/notifications-events",
headers=headers,
params=params
)
if response.status_code == 200:
return response.json()['data']
else:
raise Exception(f"Failed to get notifications and events: {response.text}")
def get_all_notifications_and_events(self, account_id, from_date, page_size=100):
"""Get all notifications and events using cursor pagination"""
all_notifications = []
cursor_id = None
while True:
response = self.get_notifications_and_events(
account_id, from_date, page_size, cursor_id
)
notifications = response.get('notifications', [])
all_notifications.extend(notifications)
cursor_id = response.get('nextCursorId')
if cursor_id is None:
break # No more pages
return all_notifications
# Usage example
client = EyeOTClient("https://api-c.eyeotmonitor.net/customer")
# Login
client.login("your_username", "your_password")
# Get first account ID
account_id = client.accounts[0]['AccountId']
# Get all devices for the account
devices = client.get_devices(account_id)
print(f"Found {len(devices)} devices")
# Get specific device
if devices:
device = client.get_device(devices[0]['DeviceId'], account_id)
print(f"Device: {device['Name']}")
# Get notifications and events from 7 days ago
from datetime import datetime, timedelta
from_date = datetime.utcnow() - timedelta(days=7)
# Get first page of notifications and events
notifications_events = client.get_notifications_and_events(
account_id,
from_date.isoformat() + 'Z',
page_size=50
)
print(f"Found {len(notifications_events['notifications'])} notifications in first page")
print(f"Next cursor ID: {notifications_events.get('nextCursorId')}")
# Get all notifications and events using pagination
all_notifications = client.get_all_notifications_and_events(
account_id,
from_date.isoformat() + 'Z'
)
print(f"Found {len(all_notifications)} total notifications")
class EyeOTClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.token = null;
this.accounts = [];
}
async login(username, password) {
const response = await fetch(`${this.baseUrl}/v1/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
if (response.ok) {
const result = await response.json();
this.token = result.data.token;
this.accounts = result.data.accounts;
return true;
} else {
throw new Error(`Authentication failed: ${await response.text()}`);
}
}
async getDevices(accountId) {
const url = new URL(`${this.baseUrl}/v1/devices`);
url.searchParams.append('accountId', accountId);
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${this.token}`
}
});
if (response.ok) {
const result = await response.json();
return result.data;
} else {
throw new Error(`Failed to get devices: ${await response.text()}`);
}
}
async getDevice(deviceId, accountId) {
const url = new URL(`${this.baseUrl}/v1/devices/${deviceId}`);
url.searchParams.append('accountId', accountId);
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${this.token}`
}
});
if (response.ok) {
const result = await response.json();
return result.data;
} else {
throw new Error(`Failed to get device: ${await response.text()}`);
}
}
async getNotificationsAndEvents(accountId, fromDate, pageSize = null, cursorId = null) {
const url = new URL(`${this.baseUrl}/v1/notifications-events`);
url.searchParams.append('accountId', accountId);
url.searchParams.append('from', fromDate);
if (pageSize !== null) {
url.searchParams.append('pageSize', pageSize);
}
if (cursorId !== null) {
url.searchParams.append('cursorId', cursorId);
}
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${this.token}`
}
});
if (response.ok) {
const result = await response.json();
return result.data;
} else {
throw new Error(`Failed to get notifications and events: ${await response.text()}`);
}
}
async getAllNotificationsAndEvents(accountId, fromDate, pageSize = 100) {
const allNotifications = [];
let cursorId = null;
while (true) {
const response = await this.getNotificationsAndEvents(
accountId, fromDate, pageSize, cursorId
);
const notifications = response.notifications || [];
allNotifications.push(...notifications);
cursorId = response.nextCursorId;
if (cursorId === null) {
break; // No more pages
}
}
return allNotifications;
}
}
// Usage example
(async () => {
const client = new EyeOTClient('https://api-c.eyeotmonitor.net/customer');
// Login
await client.login('your_username', 'your_password');
// Get first account ID
const accountId = client.accounts[0].AccountId;
// Get all devices
const devices = await client.getDevices(accountId);
console.log(`Found ${devices.length} devices`);
// Get specific device
if (devices.length > 0) {
const device = await client.getDevice(devices[0].DeviceId, accountId);
console.log(`Device: ${device.Name}`);
}
// Get notifications and events from 7 days ago
const fromDate = new Date();
fromDate.setDate(fromDate.getDate() - 7);
// Get first page of notifications and events
const notificationsEvents = await client.getNotificationsAndEvents(
accountId,
fromDate.toISOString(),
50 // pageSize
);
console.log(`Found ${notificationsEvents.notifications.length} notifications in first page`);
console.log(`Next cursor ID: ${notificationsEvents.nextCursorId}`);
// Get all notifications and events using pagination
const allNotifications = await client.getAllNotificationsAndEvents(
accountId,
fromDate.toISOString()
);
console.log(`Found ${allNotifications.length} total notifications`);
})();
Login:
curl -X POST "https://api-c.eyeotmonitor.net/customer/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{
"username": "your_username",
"password": "your_password"
}'
Get Devices:
curl -X GET "https://api-c.eyeotmonitor.net/customer/v1/devices?accountId=894184C4-5CF0-461D-8889-50E304170076" \
-H "Authorization: Bearer your_jwt_token_here"
Get Specific Device:
curl -X GET "https://api-c.eyeotmonitor.net/customer/v1/devices/device-123?accountId=894184C4-5CF0-461D-8889-50E304170076" \
-H "Authorization: Bearer your_jwt_token_here"
Get Notifications and Events:
curl -X GET "https://api-c.eyeotmonitor.net/customer/v1/notifications-events?accountId=894184C4-5CF0-461D-8889-50E304170076&from=2025-07-23T00:00:00Z&pageSize=100" \
-H "Authorization: Bearer your_jwt_token_here"
Get Notifications and Events with Cursor Pagination:
curl -X GET "https://api-c.eyeotmonitor.net/customer/v1/notifications-events?accountId=894184C4-5CF0-461D-8889-50E304170076&from=2025-07-23T00:00:00Z&pageSize=100&cursorId=12345" \
-H "Authorization: Bearer your_jwt_token_here"
- Secure Token Storage: Store JWT tokens securely and never expose them in logs or URLs
- Token Expiration: Check token expiration and re-authenticate when necessary
- HTTPS Only: Always use HTTPS for API communication
- Account Validation: Verify you have access to an account before making requests
- Token Reuse: Reuse JWT tokens for multiple requests until they expire
- Account Caching: Cache the list of authorized accounts to avoid repeated login calls
- Error Handling: Implement proper error handling and retry logic
- Rate Limiting: Be mindful of API rate limits (contact support for specific limits)
- Pagination: Use cursor-based pagination for large datasets to efficiently retrieve all results
- Page Size: Choose appropriate page sizes (typically 100-500) to balance memory usage and API calls
- Check Response Status: Always check HTTP status codes before processing responses
- Parse Error Messages: Use the
message
field in error responses for user-friendly error handling - Retry Logic: Implement exponential backoff for transient errors (5xx status codes)
- Graceful Degradation: Handle cases where devices or accounts may not be available
- Support for notifications and events retrieval
- Initial release with device management endpoints
- JWT authentication implementation
- Account-based access control
- Support for device metadata retrieval
Note: This documentation assumes you have valid credentials and authorized access to at least one account. Contact your us at support@eyeotomonitor.com if you have any questions.