RESTful API

API Documentation

Integrate AdCast into your own applications. All endpoints return JSON and use Bearer token authentication.

Base URL: https://ads.anettv.org/api

Authentication

All authenticated endpoints require a Bearer token in the Authorization header.

POST /api/auth/register

Create a new account and receive an API token.

Request Body

{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "securepassword123",
  "company_name": "My Digital Signage Co"
}

Response (201)

{
  "token": "1|abc123...",
  "user": { "id": 1, "name": "John Doe", "email": "john@example.com", ... },
  "tenant": { "id": 1, "name": "My Digital Signage Co", "plan": "free", ... }
}
POST /api/auth/login

Authenticate and receive a Bearer token.

Request Body

{
  "email": "john@example.com",
  "password": "securepassword123"
}

Response (200)

{
  "token": "1|abc123...",
  "user": { "id": 1, "name": "John Doe", ... },
  "tenant": { "id": 1, "name": "My Digital Signage Co", ... }
}
POST /api/auth/logout

Revoke the current access token.

Headers

Authorization: Bearer {token}

Response (200)

{
  "message": "Logged out successfully."
}
GET /api/auth/user

Get the authenticated user's profile and tenant info.

Headers

Authorization: Bearer {token}

Response (200)

{
  "user": {
    "id": 1,
    "name": "John Doe",
    "email": "john@example.com",
    "role": "tenant_admin",
    "tenant": { "id": 1, "name": "My Co", "plan": "free", ... }
  }
}

Devices

Manage your display devices. All endpoints require Bearer token authentication.

GET /api/devices

List all devices for your tenant.

Response (200)

{
  "data": [
    {
      "id": 1, "name": "Lobby Display", "uuid": "abc-123",
      "status": "online", "model": "Xiaomi Mi Box S",
      "os_version": "11", "app_version": "2.0.0",
      "last_seen_at": "2026-03-25T12:00:00Z", ...
    }
  ],
  "meta": { "current_page": 1, "last_page": 1, "total": 1 }
}
POST /api/devices/pair

Pair a device using its 6-digit pairing code.

Request Body

{
  "pairing_code": "4A7X2B",
  "name": "Lobby Display"
}

Response (200)

{
  "device": { "id": 1, "name": "Lobby Display", "uuid": "abc-123", "status": "online", ... }
}
GET /api/devices/{id}

Get detailed information about a specific device.

Response (200)

{
  "device": {
    "id": 1, "name": "Lobby Display", "uuid": "abc-123",
    "status": "online", "ip_address": "192.168.1.100",
    "storage_total_mb": 16000, "storage_used_mb": 2400,
    "wifi_signal": -45, "volume": 80, "is_locked": false, ...
  }
}
PUT /api/devices/{id}

Update device name, group, or other settings.

Request Body

{
  "name": "Lobby Display - Main Entrance",
  "device_group_id": 2
}
DELETE /api/devices/{id}

Remove a device from your account.

Response (200)

{
  "message": "Device deleted successfully."
}
POST /api/devices/{id}/command

Send a remote command to a device (reboot, set_volume, refresh, screenshot, etc.).

Request Body

{
  "type": "set_volume",
  "payload": { "volume": 50 }
}
POST /api/devices/{id}/lock

Lock the device to prevent unauthorized access.

Request Body

{
  "pin": "1234"
}
POST /api/devices/{id}/unlock

Unlock a locked device.

Response (200)

{
  "message": "Device unlocked."
}

Content

Upload and manage your media content (videos, images, YouTube URLs, web pages).

GET /api/content

List all content items. Supports filtering by type and status.

Query Parameters

?type=video&status=active&search=promo&per_page=20

Response (200)

{
  "data": [
    {
      "id": 1, "name": "Summer Promo", "type": "video",
      "file_size_mb": 12.5, "duration": 30, "status": "active",
      "download_url": "https://...", "thumbnail_url": "https://...", ...
    }
  ]
}
POST /api/content

Upload new content. Use multipart/form-data for file uploads, or provide a source_url for YouTube/web content.

Request Body (multipart/form-data)

name: "Summer Promo Video"
type: "video"            // video, image, youtube, web, livestream
file: (binary file)      // for video/image uploads
source_url: ""           // for youtube/web content
duration: 30             // display duration in seconds

Response (201)

{
  "content": { "id": 5, "name": "Summer Promo Video", "type": "video", ... }
}
GET /api/content/{id}

Get details of a specific content item.

PUT /api/content/{id}

Update content name, duration, or other metadata.

Request Body

{
  "name": "Updated Name",
  "duration": 15
}
DELETE /api/content/{id}

Delete a content item and its associated file.

Response (200)

{
  "message": "Content deleted successfully."
}

Playlists

Create and manage playlists that organize your content for playback on devices.

GET /api/playlists

List all playlists.

Response (200)

{
  "data": [
    {
      "id": 1, "name": "Lobby Playlist", "transition": "fade",
      "is_default": true, "items_count": 5, ...
    }
  ]
}
POST /api/playlists

Create a new playlist.

Request Body

{
  "name": "Morning Playlist",
  "transition": "fade",
  "is_default": false
}
GET /api/playlists/{id}

Get a playlist with all its items and content details.

PUT /api/playlists/{id}

Update playlist name, transition, or default status.

DELETE /api/playlists/{id}

Delete a playlist.

Response (200)

{
  "message": "Playlist deleted successfully."
}

Schedules

Schedule playlists to play on specific devices, groups, or locations at specific times.

GET /api/schedules

List all schedules for your tenant.

POST /api/schedules

Create a new schedule with optional conditional playback.

Request Body

{
  "playlist_id": 1,
  "schedulable_type": "device",
  "schedulable_id": 5,
  "days_of_week": [1, 2, 3, 4, 5],
  "start_time": "09:00",
  "end_time": "17:00",
  "start_date": "2026-04-01",
  "end_date": "2026-06-30",
  "priority": 10,
  "is_active": true,
  "conditions": [
    {"type": "weather", "operator": "gt", "value": "30", "unit": "celsius"},
    {"type": "day_type", "operator": "eq", "value": "weekday"},
    {"type": "time_range", "operator": "between", "value": "09:00-17:00"}
  ]
}
PUT /api/schedules/{id}

Update an existing schedule.

DELETE /api/schedules/{id}

Delete a schedule.

Response (200)

{
  "message": "Schedule deleted successfully."
}

Device Player API

These endpoints are used by the AdCast Player app running on devices. They do not require Bearer token authentication -- they use the device UUID for identification.

POST /api/device/register

Register a new device or update an existing device. Returns a pairing code for the dashboard.

Request Body

{
  "uuid": "unique-device-id-abc123",
  "model": "Xiaomi Mi Box S",
  "os_version": "11",
  "app_version": "2.0.0",
  "license_key": "ADCAST-XXXX-YYYY"
}

Response (200)

{
  "device_id": 1,
  "pairing_code": "4A7X2B",
  "paired": false,
  "device_name": null,
  "is_locked": false,
  "lock_pin": null,
  "license_activated": false
}
POST /api/device/heartbeat

Send periodic heartbeat with device status. Returns pending commands, emergency alerts, and app updates.

Request Body

{
  "uuid": "unique-device-id-abc123",
  "ip_address": "192.168.1.100",
  "wifi_signal": -45,
  "storage_total_mb": 16000,
  "storage_used_mb": 2400,
  "storage_free_mb": 13600,
  "screen_on": true,
  "volume": 80,
  "uptime_seconds": 86400,
  "current_content": "Summer Promo"
}

Response (200)

{
  "status": "ok",
  "has_update": true,
  "is_locked": false,
  "lock_pin": null,
  "has_pending_commands": false,
  "pending_commands": [],
  "emergency_alerts": [],
  "app_update": null
}
GET /api/device/playlist?uuid={uuid}

Get the active playlist for the device based on current schedule. Includes content download URLs and cleanup instructions.

Response (200)

{
  "playlist": {
    "id": 1, "name": "Lobby Playlist", "transition": "fade",
    "items": [
      {
        "id": 1, "content_id": 5, "name": "Summer Promo",
        "type": "video", "download_url": "https://...",
        "duration": 30, "file_hash": "abc123", "order": 1
      }
    ]
  },
  "content_to_download": [ ... ],
  "content_to_delete": [3, 7],
  "show_watermark": false
}
GET /api/device/content/{id}/download?uuid={uuid}

Download a content file for local caching. Returns binary file data or redirects to URL.

Response

Binary file download or 302 redirect to source URL.

Rate Limiting

API requests are rate-limited to 60 requests per minute per token. Device player API endpoints (heartbeat, playlist) have higher limits. If you exceed the limit, you'll receive a 429 Too Many Requests response.

Error Codes

Code Meaning
200Success
201Created successfully
401Unauthorized - invalid or missing token
403Forbidden - insufficient permissions
404Resource not found
422Validation error - check the errors field
429Rate limit exceeded