Python quickstart

A Python program that refreshes a token, lists your screens and puts a playlist on a screen. The blocks on this page form one file.

1 Get a token

Open the CMS at Settings, Connected apps and click Generate token. A member without admin rights does not see this tab.

Then choose the organization, which decides the screens the program sees, and click Allow. The next page shows the client ID and the refresh token, once. Copy both.

In your terminal, set the client ID and the path of the token file, then write the refresh token to that file. read -rs waits without showing anything: paste the refresh token and press Enter, so it stays out of the shell history:

export GIBEON_CLIENT_ID=CLIENT_ID
export GIBEON_REFRESH_TOKEN_FILE=./gibeon-refresh-token
touch "$GIBEON_REFRESH_TOKEN_FILE"
chmod 600 "$GIBEON_REFRESH_TOKEN_FILE"
read -rs GIBEON_REFRESH_TOKEN && printf '%s' "$GIBEON_REFRESH_TOKEN" > "$GIBEON_REFRESH_TOKEN_FILE"

Install the one dependency in a venv, because Homebrew Python and Debian 12 or newer refuse a pip install outside one:

python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install requests

Put the blocks below in order in gibeon.py and run python3 gibeon.py.

2 Refresh the token

An access token lasts 60 minutes. Every refresh also returns a new refresh token, so a value in the environment is stale after one run.

The program writes the new token to a temp file in the same directory, sets chmod 600 and renames it over the file in GIBEON_REFRESH_TOKEN_FILE. Only then does it use the access token. A process that dies while using it keeps a working refresh token.

Every request checks the status: on an error, raise_for_status stops the program with a non-zero exit code.

import os
import tempfile

import requests

token_file = os.environ["GIBEON_REFRESH_TOKEN_FILE"]

with open(token_file) as f:
    refresh_token = f.read().strip()

response = requests.post(
    "https://id.gibeon.io/auth/v1/oauth/token",
    data={
        "grant_type": "refresh_token",
        "client_id": os.environ["GIBEON_CLIENT_ID"],
        "refresh_token": refresh_token,
    },
    timeout=30,
)
response.raise_for_status()
tokens = response.json()

# Store the new refresh token before anything uses the access token.
fd, tmp_path = tempfile.mkstemp(dir=os.path.dirname(token_file) or ".")
with os.fdopen(fd, "w") as f:
    f.write(tokens["refresh_token"])
os.chmod(tmp_path, 0o600)
os.replace(tmp_path, token_file)

headers = {"Authorization": f"Bearer {tokens['access_token']}"}

3 List your screens

This returns every screen in your tenant. The program prints the id, name and status of each screen, and never a token.

response = requests.get("https://www.gibeon.io/v1/players", headers=headers, timeout=30)
response.raise_for_status()

for player in response.json()["data"]:
    print(player["id"], player["name"], player["status"])

4 Assign a playlist and publish

This step runs only when GIBEON_PLAYER_ID and GIBEON_PLAYLIST_ID are set. The screen id is in the list from the previous step. The playlist id is in the CMS address bar when you open a playlist: /playlists/PLAYLIST_ID/content. Export both and run the program again.

A screen with zones plays those; otherwise its sequence; otherwise its planning; otherwise its own playlist. The body clears the sequence and the planning, so the playlist plays unless the screen has zones.

The PATCH alone changes nothing on the screen: until you publish, it keeps showing the old assignment. Publishing builds a new snapshot and tells the screen right away.

player_id = os.environ.get("GIBEON_PLAYER_ID")
playlist_id = os.environ.get("GIBEON_PLAYLIST_ID")

if player_id and playlist_id:
    response = requests.patch(
        f"https://www.gibeon.io/v1/players/{player_id}",
        headers=headers,
        json={"playlist_id": playlist_id, "sequence_id": None, "planning_id": None},
        timeout=30,
    )
    response.raise_for_status()
    player = response.json()["data"]

    response = requests.post(
        f"https://www.gibeon.io/v1/players/{player_id}/publish",
        headers=headers,
        timeout=30,
    )
    response.raise_for_status()
    print(player["id"], player["name"], player["status"])

What’s next