Admin API
This endpoint requires admin-level roles (platform_admin, tenant_admin, or system_admin). Accessible via the API gateway at /v1/platform/*.
Digital Signage API
Manage digital signage displays, menu boards, content playlists, and scheduling.
Overview
| Attribute | Value |
|---|---|
| Base Path | /api/v1/signage |
| Authentication | Device Token or Bearer Token |
| Required Roles | marketing, manager, restaurant_manager, tenant_admin, platform_admin, system_admin, super_admin |
Display Management
List Displays
Retrieve all digital displays.
GET /api/v1/signage/displays
Query Parameters
| Parameter | Type | Description |
|---|---|---|
location_id | uuid | Filter by location |
type | string | menu_board, promo, info, kds |
status | string | online, offline, maintenance |
Response
{
"data": [
{
"id": "display_001",
"name": "Main Menu Board 1",
"type": "menu_board",
"location_id": "loc_123",
"location_name": "Downtown",
"status": "online",
"resolution": "1920x1080",
"orientation": "landscape",
"current_content": {
"playlist_id": "pl_001",
"item_name": "Lunch Menu"
},
"hardware": {
"model": "Samsung QM55R",
"serial": "SN12345",
"firmware": "1045.3"
},
"last_heartbeat": "2026-01-24T19:29:00Z"
}
]
}
Display Types
| Type | Description |
|---|---|
menu_board | Menu display |
promo | Promotional content |
info | Information display |
kds | Kitchen display |
drive_thru | Drive-thru menu |
window | Window facing |
Register Display
Register a new display device.
POST /api/v1/signage/displays
Request Body
{
"location_id": "loc_123",
"name": "Main Menu Board 1",
"type": "menu_board",
"hardware_id": "device_serial_123",
"resolution": "1920x1080",
"orientation": "landscape"
}
Response
{
"display_id": "display_001",
"device_token": "sdt_abc123...",
"status": "pending_setup",
"setup_url": "https://signage.olympuscloud.ai/setup/display_001"
}
Get Display Status
GET /api/v1/signage/displays/{display_id}/status
Response
{
"display_id": "display_001",
"status": "online",
"current_content": {
"playlist_id": "pl_001",
"current_item": "Lunch Menu",
"next_item": "Happy Hour Promo",
"time_remaining_seconds": 45
},
"hardware_status": {
"temperature_celsius": 42,
"brightness": 80,
"volume": 50,
"storage_free_mb": 2048
},
"network": {
"ip_address": "192.168.1.50",
"connection_type": "ethernet",
"signal_strength": null
},
"metrics": {
"uptime_hours": 168,
"content_errors_24h": 0,
"cache_hit_rate": 98.5
}
}
Control Display
Send commands to display.
POST /api/v1/signage/displays/{display_id}/command
Request Body
{
"command": "restart",
"params": {}
}
Available Commands
| Command | Description |
|---|---|
restart | Restart display app |
reboot | Reboot device |
set_brightness | Adjust brightness |
set_volume | Adjust volume |
clear_cache | Clear content cache |
screenshot | Take screenshot |
play_content | Play specific content |
Content Management
List Content
Retrieve available content items.
GET /api/v1/signage/content
Query Parameters
| Parameter | Type | Description |
|---|---|---|
type | string | image, video, menu, promo, template |
category | string | Content category |
Response
{
"data": [
{
"id": "content_001",
"name": "Lunch Menu",
"type": "menu",
"category": "menus",
"duration_seconds": 30,
"resolution": "1920x1080",
"file_size_mb": 2.5,
"thumbnail_url": "https://...",
"url": "https://...",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-24T10:00:00Z"
},
{
"id": "content_002",
"name": "Happy Hour Promo",
"type": "video",
"category": "promotions",
"duration_seconds": 15,
"resolution": "1920x1080",
"file_size_mb": 45.2
}
]
}
Upload Content
Upload new content.
POST /api/v1/signage/content
Request Body (multipart/form-data)
name: "Summer Special Promo"
type: "video"
category: "promotions"
file: [binary data]
Response
{
"content_id": "content_003",
"name": "Summer Special Promo",
"status": "processing",
"processing_job_id": "job_abc"
}
Get Content
GET /api/v1/signage/content/{content_id}
Delete Content
DELETE /api/v1/signage/content/{content_id}
Menu Templates
List Menu Templates
GET /api/v1/signage/templates/menu
Response
{
"data": [
{
"id": "template_001",
"name": "Classic Menu Board",
"preview_url": "https://...",
"sections": ["header", "categories", "items", "footer"],
"customizable": {
"colors": true,
"fonts": true,
"logo": true,
"background": true
}
}
]
}
Generate Menu Display
Create menu display from template.
POST /api/v1/signage/templates/menu/generate
Request Body
{
"template_id": "template_001",
"menu_id": "menu_123",
"customization": {
"primary_color": "#FF5722",
"font_family": "Montserrat",
"logo_url": "https://...",
"show_prices": true,
"show_calories": false
},
"categories": ["appetizers", "entrees", "desserts"]
}
Playlists
List Playlists
GET /api/v1/signage/playlists
Response
{
"data": [
{
"id": "pl_001",
"name": "Lunch Rotation",
"items": [
{
"content_id": "content_001",
"name": "Lunch Menu",
"duration_seconds": 30,
"order": 1
},
{
"content_id": "content_002",
"name": "Happy Hour Promo",
"duration_seconds": 15,
"order": 2
}
],
"total_duration_seconds": 45,
"loop": true,
"assigned_displays": 3
}
]
}
Create Playlist
POST /api/v1/signage/playlists
Request Body
{
"name": "Lunch Rotation",
"items": [
{"content_id": "content_001", "duration_seconds": 30},
{"content_id": "content_002", "duration_seconds": 15}
],
"loop": true
}
Update Playlist
PUT /api/v1/signage/playlists/{playlist_id}
Assign Playlist to Display
POST /api/v1/signage/displays/{display_id}/playlist
Request Body
{
"playlist_id": "pl_001"
}
Scheduling
List Schedules
GET /api/v1/signage/schedules
Response
{
"data": [
{
"id": "sched_001",
"name": "Weekday Schedule",
"display_id": "display_001",
"rules": [
{
"playlist_id": "pl_breakfast",
"days": ["mon", "tue", "wed", "thu", "fri"],
"start_time": "06:00",
"end_time": "11:00"
},
{
"playlist_id": "pl_lunch",
"days": ["mon", "tue", "wed", "thu", "fri"],
"start_time": "11:00",
"end_time": "16:00"
},
{
"playlist_id": "pl_dinner",
"days": ["mon", "tue", "wed", "thu", "fri"],
"start_time": "16:00",
"end_time": "22:00"
}
],
"default_playlist_id": "pl_default"
}
]
}
Create Schedule
POST /api/v1/signage/schedules
Request Body
{
"name": "Weekday Schedule",
"display_id": "display_001",
"rules": [
{
"playlist_id": "pl_breakfast",
"days": ["mon", "tue", "wed", "thu", "fri"],
"start_time": "06:00",
"end_time": "11:00"
}
],
"default_playlist_id": "pl_default"
}
Emergency Messages
Broadcast Emergency
Push emergency message to displays.
POST /api/v1/signage/emergency
Request Body
{
"message": "Building evacuation in progress. Please exit calmly.",
"type": "evacuation",
"display_ids": ["display_001", "display_002"],
"duration_seconds": 0,
"override_all": true
}
Clear Emergency
DELETE /api/v1/signage/emergency
Analytics
Get Display Analytics
GET /api/v1/signage/analytics
Query Parameters
| Parameter | Type | Description |
|---|---|---|
display_id | string | Specific display |
start_date | date | Analysis start |
end_date | date | Analysis end |
Response
{
"period": {
"start": "2026-01-01",
"end": "2026-01-24"
},
"displays": {
"total": 8,
"online": 8,
"offline": 0,
"avg_uptime_percent": 99.8
},
"content": {
"total_plays": 45000,
"unique_content_items": 25,
"most_played": [
{"content_id": "content_001", "name": "Lunch Menu", "plays": 8500}
]
},
"engagement": {
"avg_dwell_time_seconds": 12.5,
"interactions": 0
}
}
Device Heartbeat
Send Heartbeat
Display sends periodic status update.
POST /api/v1/signage/displays/{display_id}/heartbeat
Request Body
{
"software_version": "2.5.1",
"uptime_seconds": 604800,
"current_content_id": "content_001",
"hardware": {
"temperature_celsius": 42,
"storage_free_mb": 2048
},
"errors": []
}
Webhooks
| Event | Description |
|---|---|
signage.display_online | Display came online |
signage.display_offline | Display went offline |
signage.content_error | Content playback error |
signage.schedule_changed | Schedule updated |
signage.emergency_broadcast | Emergency message sent |
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | invalid_content_type | Unsupported file type |
| 400 | content_too_large | File exceeds limit |
| 404 | display_not_found | Display ID not found |
| 404 | content_not_found | Content ID not found |
| 409 | display_offline | Display not reachable |
Related Documentation
- Digital Signage Guide - User guide
- Menu Boards - Menu board setup
- Content Best Practices - Content guidelines