Documentation / Integrations & content creation / API for connecting your system

API for connecting your system

Introduction and orientation

How to manage media, campaigns and reports directly from your own system without signing in to the administration.

What the API is for

The API connects the customer’s own system — for example an e-shop, an advertising campaign planner or an internal catalogue — directly to device content management. Your system can upload media, create and start campaigns and retrieve their results without anyone having to sign in to the administration and perform these operations manually.

The interface is the same one used by the web administration. The API therefore supports the same operations as the administration, within the permissions of the signed-in user.

When to use the API

For occasionally uploading a few media files and starting a campaign manually, the administration is the better choice: the campaign wizard shows a preview and checks media formats and device capacity. The API makes sense once manual work starts to slow you down.

You need toRecommended approach
Upload a few media files and start a campaignAdministration
Update content regularly, but manuallyAdministration
Upload media in bulk from your own systemAPI
Create campaigns automatically from your own schedulerAPI
Pull campaign results into your own reportingAPI

The interface is not versioned and may change as the platform evolves. Notify your software provider before deploying an integration and verify that it still works after system updates.

Who this guide is for and who is responsible

  • The platform provider operates the interface, provides the administration address and sets the Company’s playback mode.
  • The customer decides on the scope of the integration and creates a dedicated user with the required permissions in their Company — see Create a user and first sign-in.
  • The integration developer connects the customer’s system to the interface. The technical instructions and code examples in this guide are intended for that developer. If you develop the integration yourself, you also fulfil this role.

Technical reference

Technical guide for integration developers

Start with the shared calling conventions and sign-in. Then follow the workflow from uploading a media file to starting a campaign, and see the overview of available endpoints.

Shared calling conventions

  • Address: the interface runs at the same address as your administration; all paths start with /api/. In the examples the address is replaced with https://admin.example.org. If a test environment is available, your provider will give you its address.
  • Sign-in: every request carries the credentials using HTTP Basic Auth. No sessions or tokens are used.
  • Data format: request bodies and responses are JSON. The exception is file upload, where the body consists of the raw binary data.
  • Identifiers and values: identifiers are integers. Date and time use the format YYYY-MM-DDTHH:MM:SS, display durations are in milliseconds (10000 = 10 s).
  • Result: success is confirmed by status 200. It means the request was accepted, not that content is already playing on the devices.

Sign-in

The login is not an e-mail address but an eight-character code generated by the system when the user was created, for example A1B2C3D4. Create a dedicated user with the minimum necessary permissions for the integration; its access can then be revoked at any time without affecting other users.

curl -u "A1B2C3D4:your-password" https://admin.example.org/api/public/login

The password is sent with every request. Store it as a secret, for example in an environment variable or a password vault — never in source code, a repository or logs.

The following examples assume these variables are set:

export API="https://admin.example.org"
export AUTH="A1B2C3D4:your-password"

The examples use curl because it does not depend on a programming language. The interface is plain HTTP, so it can be called from any language or tool that supports Basic Auth, for example Python, JavaScript, PHP, Postman or Make.

Workflow: from a file to a running campaign

  1. Get the Company identifier. You will use it in all further calls.
  2. Upload a media file. The response returns its identifier.
  3. Load a campaign template. The server pre-fills it with the Company settings and the list of locations and devices.
  4. Edit the template — name, period, target devices and visual.
  5. Create the campaign. It is created as a draft and does not play yet.
  6. Activate the campaign. The system prepares a new playback plan and sends it to the devices.
  7. Monitor the results in the campaign report.

1. Company identifier

curl -u "$AUTH" "$API/api/public/login"

Response (shortened):

{
  "id": 1715714421868,
  "name": "Integration – e-shop",
  "login": "A1B2C3D4",
  "company": { "id": 1698234512001, "name": "Advertising Agency Ltd." },
  "permission": {
    "resource": 12,
    "device_layer_top": 12,
    "report_layer_top": 4
  }
}

Store the value of company.id; the examples use it as the variable COMPANY. The permission section lists the user’s permissions; their meaning is described under Permissions.

2. Uploading a media file

The file is sent as the binary request body using PUT; its properties are given in headers.

curl -u "$AUTH" -X PUT \
  "$API/api/resource/single/$COMPANY" \
  -H "file-type: IMAGE" \
  -H "file-mime: image/jpeg" \
  -H "file-name: summer-sale.jpg" \
  -H "file-suffix: jpg" \
  --data-binary @summer-sale.jpg
HeaderContent
file-typeMedia type according to the Media types table, for example IMAGE.
file-mimeMIME type of the file, for example image/jpeg, video/mp4 or application/pdf.
file-nameMedia name shown in the administration; the server removes any extension. URL-encode names containing non-ASCII characters (encodeURIComponent).
file-suffixFile extension without the dot.

The same call in Python:

import requests

with open("summer-sale.jpg", "rb") as f:
    r = requests.put(
        f"{API}/api/resource/single/{COMPANY}",
        auth=("A1B2C3D4", "your-password"),
        headers={
            "file-type": "IMAGE",
            "file-mime": "image/jpeg",
            "file-name": "summer-sale.jpg",
            "file-suffix": "jpg",
        },
        data=f,
    )
r.raise_for_status()
resource_id = r.json()["id"]

The response contains the media identifier (id) and its type (type); you will use both values in the campaign visual.

{
  "id": 1724832015443,
  "type": 2,
  "name": "summer-sale",
  "width": 1920,
  "height": 1080,
  "duration": 0,
  "aspectRatio": 32
}
  • Size: regular files up to approximately 1.1 GB, video with transparency up to approximately 2.1 GB. The server rejects larger files with 413.
  • Video preparation: video is converted in the background after upload. It is ready once the media detail (GET /api/resource/single/{companyId}/{id}) contains a value in dt_ready. For images, preparation is practically immediate.
  • Missing header: without file-mime, file-name or file-suffix the server returns 204 and does not create the media file. Always check that the response contains id before continuing.

3. Campaign template

Do not assemble the campaign by hand. Request a template that the server pre-fills with a default period (one month from today), the Company settings and the list of all locations and devices. Every device in it is marked isActive: false.

curl -u "$AUTH" "$API/api/campaign/company/$COMPANY" > campaign.json

Template example (shortened):

{
  "id": -1,
  "groupId": -1,
  "state": 2,
  "name": "",
  "start": "2026-11-01T10:00:00",
  "end": "2026-12-01T10:00:00",
  "isCommercial": true,
  "isNonCommercial": false,
  "settings": {
    "type": 2,
    "companyCount": 10,
    "companyDuration": 10000,
    "campaignCount": 1,
    "campaignDuration": 10000
  },
  "locations": [
    {
      "id": 1698234512100,
      "name": "City Mall",
      "days": [ { "day": 1, "start": "09:00", "end": "21:00" } ],
      "devices": [
        {
          "id": 1698234512201,
          "name": "Entrance A",
          "screenRatio": 32,
          "isHorizontal": true,
          "isActive": false
        }
      ]
    }
  ],
  "visuals": []
}

The value of settings.type determines the Company’s playback mode: 2 = SLOT, 4 = IMPRESSION. The mode is set by the provider and cannot be changed via the API.

4. Editing the template

  • name: campaign name shown in the administration and reports.
  • start, end: start and end of the campaign.
  • isActive: set to true for the devices on which the campaign should play.
  • visuals: add a visual with the uploaded media file.
"visuals": [
  {
    "id": 1,
    "name": "Main visual",
    "isPrimary": true,
    "isCustom": true,
    "res": [
      {
        "id": 1,
        "conditionId": 0,
        "resourceId": 1724832015443,
        "name": "summer-sale",
        "duration": 10000,
        "type": 2
      }
    ]
  }
]
FieldMeaning
idAny number unique within the campaign; the server renumbers it on creation.
isPrimarytrue for the main visual, false for the others.
isCustomtrue – the visual belongs to this campaign.
resourceIdMedia identifier from step 2.
durationDisplay duration in milliseconds.
typeMedia type; the same value the upload returned in type.

The template can be edited by a script, for example with jq:

jq --argjson res "$RESOURCE" '
  .name = "Summer sale 2026"
  | .start = "2026-11-02T00:00:00"
  | .end   = "2026-11-09T00:00:00"
  | .locations[].devices[].isActive = true
  | .visuals = [{
      id: 1, name: "Main visual", isPrimary: true, isCustom: true,
      res: [{ id: 1, conditionId: 0, resourceId: $res,
              name: "summer-sale", duration: 10000, type: 2 }]
    }]
' campaign.json > campaign-edited.json

If the campaign targets both landscape and portrait screens (isHorizontal), add a visual for each orientation. Otherwise the content will be cropped or scaled down on some screens. See Campaign visuals for details.

5. Creating the campaign

curl -u "$AUTH" -X POST \
  "$API/api/campaign/company/$COMPANY" \
  -H "Content-Type: application/json" \
  --data @campaign-edited.json \
  -o response.json

export CAMPAIGN=$(jq -r '.id' response.json)
export GROUP=$(jq -r '.groupId' response.json)

The campaign is created as a draft and does not play anywhere. The response contains the saved campaign with the assigned id and groupId. The template already has state: 2 (draft); the server rejects any other value with 409.

6. Activating the campaign

curl -u "$AUTH" -X PATCH \
  "$API/api/campaign/company/$COMPANY/$CAMPAIGN/+01:00/0"
  • +01:00: time zone as an offset from UTC that the campaign follows. For Central Europe use +01:00 in winter and +02:00 in summer time.
  • 0: expected number of impressions for the whole campaign. It applies in IMPRESSION mode; in SLOT mode use 0.

A campaign starting today or earlier becomes active and its start is set to the moment of activation. A campaign with a future start becomes published and starts on the scheduled day.

The system then recalculates the playback plan and sends it to the affected devices. For connected devices this usually takes tens of seconds; a disconnected device receives the plan once the connection is restored. Check device capacity in the administration, see Campaign capacity.

7. Campaign results

curl -u "$AUTH" "$API/api/report/$COMPANY/campaign/$GROUP"
curl -u "$AUTH" "$API/api/report/$COMPANY/campaign/$GROUP/impression"

Reports use groupId, not the campaign id. The first endpoint returns the campaign summary, the second the numbers of recorded impressions. Devices send records continuously in batches, so the figures are not available in real time. See Campaign report for the meaning of the figures.

Pausing, stopping and deleting

# pause an active campaign; calling it again resumes it
curl -u "$AUTH" -X PATCH \
  "$API/api/campaign/company/$COMPANY/$CAMPAIGN/+01:00/0"

# stop permanently
curl -u "$AUTH" -X PATCH \
  "$API/api/campaign/company/$COMPANY/$CAMPAIGN/+01:00"

# delete
curl -u "$AUTH" -X DELETE \
  "$API/api/campaign/company/$COMPANY/$CAMPAIGN"

The endpoint from step 6 works as a toggle: it pauses an active or published campaign and resumes a paused one. Check the current campaign state (state in the detail) before calling it. A stopped campaign cannot be started again, but it remains in the list together with its reports. A deleted campaign disappears from the list.

Endpoint overview

Paths are relative to the administration address. {c} stands for the Company identifier.

Account

MethodPathPurpose
GET/api/public/loginVerifies the credentials and returns the user profile including company.id.
GET/api/user/infoInformation about the signed-in user.
GET/api/user/checkQuick check that the credentials are valid.

Media

MethodPathPurpose
PUT/api/resource/single/{c}Uploads a file (file-* headers, body = binary data).
GET/api/resource/listing/{c}/1List of media; 1 = no type restriction.
GET/api/resource/single/{c}/{id}Media detail.
DELETE/api/resource/single/{c}/{id}Deletes a media file.

Campaigns

MethodPathPurpose
GET/api/campaign/company/{c}Template of a new campaign.
POST/api/campaign/company/{c}Creates a campaign as a draft.
PATCH/api/campaign/company/{c}Saves changes to an existing campaign.
POST/api/campaign/listing/company/{c}List of campaigns; the request body contains a filter.
GET/api/campaign/company/{c}/{id}Campaign detail.
GET/api/campaign/company/{c}/group/{groupId}Campaign detail by groupId.
PATCH/api/campaign/company/{c}/{id}/{tz}/{impressions}Activates, pauses or resumes a campaign.
PATCH/api/campaign/company/{c}/{id}/{tz}Stops a campaign permanently.
DELETE/api/campaign/company/{c}/{id}Deletes a campaign.

Locations and devices

MethodPathPurpose
GET/api/location/listing/{c}List of locations.
GET/api/location/single/{id}Location detail including opening hours.
GET/api/device/listing/{c}/{locationId}List of devices in a location.
GET/api/device/single/{id}/{lang}Device detail; lang is a language code, for example en.

Reports

MethodPathPurpose
GET/api/report/{c}/campaign/{groupId}Campaign summary.
GET/api/report/{c}/campaign/{groupId}/impressionNumbers of recorded impressions.

Code lists

Code list values are written as numbers in JSON.

Campaign state (state)

ValueStateMeaning
2DraftSaved campaign that does not play.
4PublishedActivated campaign waiting for its start day.
8ActiveThe campaign is playing.
16FinishedThe campaign end has passed.
32StoppedThe campaign was stopped permanently.
64DeletedThe campaign was deleted.
128PausedPlayback is temporarily interrupted.

Media types

type valuefile-type headerMedia
2IMAGEImage (JPG, PNG, WebP)
4VIDEOVideo
8PDFPDF document
16WWW_APPWeb application
32TEXTLong text
128VIDEO_ALPHAVideo with transparent background
256AUDIOAudio

For documents, the file-type header uses the value PDF, not DOCUMENT.

Permissions

The interface applies the same permissions as the administration and checks them on every request. In the sign-in response each area is expressed as a number that is the sum of the individual rights:

ValueRight within your own Company
4View
8Add
16Edit
32Delete

For example, resource: 28 (4 + 8 + 16) means the user may view, add and edit media, but not delete them. Higher values (128 to 1024) represent the same rights outside the user’s own Company; an integration does not need them.

AreaMinimum for the described workflow
resource – media12 (view, add)
device_layer_top – campaigns12 (view, add)
report_layer_top – campaign reports4 (view)
location – locations4 (view)
device_info – devices4 (view)

Activating, pausing and stopping a campaign require the Add right. Deleting an activated campaign or a media file requires the Delete right; a campaign draft can be deleted without it. A good starting point is the Company Ad Manager role with unnecessary rights removed.

Error codes

CodeMeaningWhat to do
400Bad requestCheck the identifiers in the path, the time zone and the required data.
401Missing permissionThe user lacks the required right or access to the Company. For campaigns this is most often the missing Add right.
404Not foundThe record does not exist or does not belong to the given Company.
406Not acceptableInvalid credentials, or the campaign is in a state from which the requested transition is not allowed (e.g. stopped).
409State conflictThe campaign being created is not a draft.
413File too largeReduce the file size; see step 2 for the limits.
500Server errorRetry later; if it persists, contact your provider.
Implementation recommendations

Test the integration first in a test environment or on a device not visible to the public — an activated campaign really plays on production devices. No content plays outside the location’s opening hours, even for a campaign scheduled around the clock.

Store media and campaign identifiers (id, groupId) in your own system; the interface does not offer searching campaigns by name. Upload media one at a time and do not request reports more often than once every few minutes. Rely only on the endpoints listed in this guide.

Complete example

The script performs the whole workflow from uploading an image to activating a campaign on all devices of the Company. It requires curl and jq.

#!/usr/bin/env bash
set -euo pipefail

API="https://admin.example.org"
AUTH="${INTEGRATION_AUTH:?set INTEGRATION_AUTH=login:password}"
FILE="summer-sale.jpg"
NAME="Summer sale 2026"
FROM="2026-11-02T00:00:00"
TO="2026-11-09T00:00:00"
TZ_OFFSET="+01:00"

# 1) Company identifier
COMPANY=$(curl -sf -u "$AUTH" "$API/api/public/login" | jq -r '.company.id')

# 2) upload media
RESOURCE=$(curl -sf -u "$AUTH" -X PUT \
  "$API/api/resource/single/$COMPANY" \
  -H "file-type: IMAGE" \
  -H "file-mime: image/jpeg" \
  -H "file-name: $FILE" \
  -H "file-suffix: jpg" \
  --data-binary "@$FILE" | jq -r '.id')

# 3) campaign template
curl -sf -u "$AUTH" "$API/api/campaign/company/$COMPANY" > template.json

# 4) edit the template
jq --argjson res "$RESOURCE" --arg n "$NAME" --arg from "$FROM" --arg to "$TO" '
  .name = $n
  | .start = $from
  | .end = $to
  | .locations[].devices[].isActive = true
  | .visuals = [{
      id: 1, name: "Main visual", isPrimary: true, isCustom: true,
      res: [{ id: 1, conditionId: 0, resourceId: $res,
              name: $n, duration: 10000, type: 2 }]
    }]
' template.json > campaign.json

# 5) create a draft
RESPONSE=$(curl -sf -u "$AUTH" -X POST \
  "$API/api/campaign/company/$COMPANY" \
  -H "Content-Type: application/json" \
  --data @campaign.json)
CAMPAIGN=$(echo "$RESPONSE" | jq -r '.id')
GROUP=$(echo "$RESPONSE" | jq -r '.groupId')

# 6) activate
curl -sf -u "$AUTH" -X PATCH \
  "$API/api/campaign/company/$COMPANY/$CAMPAIGN/$TZ_OFFSET/0" > /dev/null

echo "Campaign $CAMPAIGN activated, report: $API/api/report/$COMPANY/campaign/$GROUP"
Didn't find what you were looking for?
Contact your software provider.