Skip to main content
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

AttributeValue
Base Path/api/v1/signage
AuthenticationDevice Token or Bearer Token
Required Rolesmarketing, 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

ParameterTypeDescription
location_iduuidFilter by location
typestringmenu_board, promo, info, kds
statusstringonline, 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

TypeDescription
menu_boardMenu display
promoPromotional content
infoInformation display
kdsKitchen display
drive_thruDrive-thru menu
windowWindow 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

CommandDescription
restartRestart display app
rebootReboot device
set_brightnessAdjust brightness
set_volumeAdjust volume
clear_cacheClear content cache
screenshotTake screenshot
play_contentPlay specific content

Content Management

List Content

Retrieve available content items.

GET /api/v1/signage/content

Query Parameters

ParameterTypeDescription
typestringimage, video, menu, promo, template
categorystringContent 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}

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

ParameterTypeDescription
display_idstringSpecific display
start_datedateAnalysis start
end_datedateAnalysis 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

EventDescription
signage.display_onlineDisplay came online
signage.display_offlineDisplay went offline
signage.content_errorContent playback error
signage.schedule_changedSchedule updated
signage.emergency_broadcastEmergency message sent

Error Responses

StatusCodeDescription
400invalid_content_typeUnsupported file type
400content_too_largeFile exceeds limit
404display_not_foundDisplay ID not found
404content_not_foundContent ID not found
409display_offlineDisplay not reachable

  • Digital Signage Guide - User guide
  • Menu Boards - Menu board setup
  • Content Best Practices - Content guidelines