NAV Navigation
shell python

Overview

Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.

The Solstice Active Routing API enables developers, engineers, and consultants to mirror a Solstice display to an arbitrary number of other Solstice displays. It is used by the Solstice Active Learning application.

Active Routing is infrastructure that supports products in a variety of areas such as Active Learning, Multiroom Sharing, and other potential markets that require the duplication of content or collaboration across multiple screens or conference rooms that reside in a single local-area network (LAN).

This is a REST API, that returns JSON responses.

Because Active Routing use cases involve mirroring one display to many, you will need to have at least 2 Solstice Pods to utilize the API. If you don't have an HDMI Multi-viewer, you will also need a display for each Pod.

Python sample code is available to help you get started.

Terminology

Getting Started

Step 1: Authenticate

Code samples

curl -k -X POST \
--header "content-type: application/x-www-form-urlencoded" \
https://<podip>:5443/v2/token \
-d "grant_type=password&username=admin&password="
import json
import requests

HOST = '<Replace with source Pod IP address>'
password = ''

headers = {'content-type': 'application/x-www-form-urlencoded'}
payload = f'grant_type=password&username=admin&password={password}'
r = requests.post('https://' + HOST + ':5443/v2/token', headers=headers, data=payload, verify=False)
print(f'Status code: {r.status_code}')
print(f'Response: {r.json()}')
print(r.json())

Your application must authenticate to the source Pod in order to successfully execute API calls. The v2 API uses the Oauth2 "password grant flow", which returns a JWT that can be used in the Authorization header of subsequent API calls.

Step 2: Configure Source

Code samples

curl -k -X PATCH \
--header "Authorization: Bearer <JWT>" \
--header "Content-Type: application/json" \
https://<podip>:5443/v2/content/activerouting \
-d '{"presence": false, "message": "Sharing!", "background": "#F95127", "foreground": "#FFFFFF"}'
import json
import requests

HOST = '<Replace with source Pod IP address>'
access_token = '<Replace with access token from auth>'

# Configure session parameters
payload = {}
payload['presence'] = False
payload['message'] = 'Sharing!'
payload['background'] = '#F95127'
payload['foreground'] = '#FFFFFF'

headers = {'content-type': 'application/json', 'Authorization': 'Bearer ' + access_token}
r = requests.patch('https://' + HOST + ':5443/v2/content/activerouting', headers=headers, data=json.dumps(payload), verify=False)

print(f'Status code: {r.status_code}')
print(f'Result: {r.json()}')

You must configure the source pod before capturing the sink displays. To do this, pass the Authorization header and Content-Type, along with the JSON payload to the /v2/content/activerouting endpoint.

Step 3: Capture Sink

Code samples

curl -k -X POST \
--header "Authorization: Bearer <JWT>" \
--header "Content-Type: application/json" \
https://<podip>:5443/v2/content/activerouting/connections \
-d '{"sink": "<sinkIp>", "post": "fullscreen", "message": "Testing from API", "background": "#F95127", "foreground": "#FFFFFF", "resolution": "1920x1080"}'
import json
import requests

HOST = '<Replace with source Pod IP address>'
access_token = '<Replace with access token from auth>'
sink = '<Replace with Pod to which you will be mirroring>'

payload = {}
payload['post'] = 'fullscreen'
payload['message'] = 'Testing from API'
payload['foreground'] = '#FFFFFF'
payload['background'] = '#F95127'
payload['resolution'] = '1920x1080'
payload['sink'] = sink

headers = {'content-type': 'application/json', 'Authorization': 'Bearer ' + access_token}
r = requests.post('https://' + HOST + ':5443/v2/content/activerouting/connections', headers=headers, data=json.dumps(payload), verify=False)

print(f'Status code: {r.status_code}')
print(f'Result: {r.json()}')

In the last step, capture the sink to begin mirroring the source display. To do this, pass the Authorization header and Content-Type, along with the JSON payload to the /v2/content/activerouting/connections endpoint.

Active Routing API v1

Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.

Base URLs:

Authentication

Scope Scope Description

Token

Request a token

Code samples

# You can also use wget
curl -X POST https://replace_with_pod_IP_or_host:5443/v2/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -H 'Accept: application/json'

import requests
headers = {
  'Content-Type': 'application/x-www-form-urlencoded',
  'Accept': 'application/json'
}

r = requests.post('https://replace_with_pod_IP_or_host:5443/v2/token', headers = headers)

print(r.json())

POST /token

Request a bearer token for the v2 API

Body parameter

grant_type: password
username: string
password: string

Parameters

Name In Type Required Description
body body TokenRequest true Subset of config to update

Example responses

200 Response

{
  "access_token": "string",
  "token_type": "jwt"
}

Responses

Status Meaning Description Schema
200 OK OAuth 2.0 access token response TokenSuccess
400 Bad Request Bad request (e.g. malformed body) None
401 Unauthorized Invalid credentials None
default Default An unexpected error Errors

Response Schema

Active Routing

Get current session data

Code samples

# You can also use wget
curl -X GET https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/ \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer {access-token}'

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {access-token}'
}

r = requests.get('https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/', headers = headers)

print(r.json())

GET /content/activerouting/

Example responses

200 Response

{
  "state": "none",
  "connections": 0,
  "framesPerSecond": 0,
  "bytesPerSecond": 0,
  "presence": true
}

Responses

Status Meaning Description Schema
200 OK SESSION data for active routing ActiveRoutingSession
401 Unauthorized Bad authorization token Errors
default Default An unexpected error Errors

Update current session data

Code samples

# You can also use wget
curl -X PATCH https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/ \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer {access-token}'

import requests
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer {access-token}'
}

r = requests.patch('https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/', headers = headers)

print(r.json())

PATCH /content/activerouting/

Body parameter

{
  "presence": true,
  "message": "string",
  "foreground": "string",
  "background": "string"
}

Parameters

Name In Type Required Description
body body ActiveRoutingConfigure true CONFIGURE active routing session

Example responses

400 Response

{
  "errors": [
    {
      "error": "invalid_request",
      "description": "string"
    }
  ]
}

Responses

Status Meaning Description Schema
200 OK Active Routing configuration updated None
400 Bad Request Bad request (e.g. malformed request body) Errors
401 Unauthorized Bad authorization token Errors
default Default An unexpected error Errors

Update overlay text on display

Code samples

# You can also use wget
curl -X POST https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/overlaytext \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer {access-token}'

import requests
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer {access-token}'
}

r = requests.post('https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/overlaytext', headers = headers)

print(r.json())

POST /content/activerouting/overlaytext

Body parameter

{
  "text": "string",
  "color": "string"
}

Parameters

Name In Type Required Description
body body ActiveRoutingOverlay true OVERLAY text onto active routing display

Example responses

401 Response

{
  "errors": [
    {
      "error": "invalid_request",
      "description": "string"
    }
  ]
}

Responses

Status Meaning Description Schema
200 OK Text overlaid onto display None
401 Unauthorized Bad authorization token Errors
default Default An unexpected error Errors

Get licensing information

Code samples

# You can also use wget
curl -X GET https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/licensing \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer {access-token}'

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {access-token}'
}

r = requests.get('https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/licensing', headers = headers)

print(r.json())

GET /content/activerouting/licensing

Example responses

200 Response

{
  "trial": "string",
  "subscription": "string",
  "licensed": true
}

Responses

Status Meaning Description Schema
200 OK Retrieve LICENSING information for active routing ActiveRoutingLicensing
401 Unauthorized Bad authorization token Errors
default Default An unexpected error Errors

Get active routing connections

Code samples

# You can also use wget
curl -X GET https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/connections \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer {access-token}'

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {access-token}'
}

r = requests.get('https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/connections', headers = headers)

print(r.json())

GET /content/activerouting/connections

Example responses

200 Response

{
  "connections": {
    "property1": {
      "guid": "string",
      "ip": "192.168.0.1",
      "name": "string"
    },
    "property2": {
      "guid": "string",
      "ip": "192.168.0.1",
      "name": "string"
    }
  }
}

Responses

Status Meaning Description Schema
200 OK ENUMERATE all active routing connections ActiveRoutingEnumerate
401 Unauthorized Bad authorization token Errors
default Default An unexpected error Errors

Create an active routing connection

Code samples

# You can also use wget
curl -X POST https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/connections \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer {access-token}'

import requests
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer {access-token}'
}

r = requests.post('https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/connections', headers = headers)

print(r.json())

POST /content/activerouting/connections

Body parameter

{
  "sink": "192.168.0.1",
  "resolution": "string",
  "post": "normal",
  "message": "string",
  "foreground": "string",
  "background": "string",
  "audio": true
}

Parameters

Name In Type Required Description
body body ActiveRoutingConnect true CONNECT active routing session (address, resolution, post type)

Example responses

200 Response

{
  "guid": "string"
}

Responses

Status Meaning Description Schema
200 OK Creates a new active routing connection and returns guid. ActiveRoutingGuid
400 Bad Request Bad request (e.g. malformed request body) Errors
401 Unauthorized Bad authorization token Errors
default Default An unexpected error Errors

Delete all active routing connections

Code samples

# You can also use wget
curl -X DELETE https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/connections \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer {access-token}'

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {access-token}'
}

r = requests.delete('https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/connections', headers = headers)

print(r.json())

DELETE /content/activerouting/connections

Example responses

200 Response

{
  "message": "string",
  "reboot_required": true,
  "restart_required": true
}

Responses

Status Meaning Description Schema
200 OK TERMINATE all active routing connections Success
401 Unauthorized Bad authorization token Errors
default Default An unexpected error Errors

Delete a single active routing connection

Code samples

# You can also use wget
curl -X DELETE https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/connections/{guid} \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer {access-token}'

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {access-token}'
}

r = requests.delete('https://replace_with_pod_IP_or_host:5443/v2/content/activerouting/connections/{guid}', headers = headers)

print(r.json())

DELETE /content/activerouting/connections/{guid}

Parameters

Name In Type Required Description
guid path string(uuid) true GUID of the active routing connection

Example responses

200 Response

{
  "message": "string",
  "reboot_required": true,
  "restart_required": true
}

Responses

Status Meaning Description Schema
200 OK DISCONNECT active routing connection Success
401 Unauthorized Bad authorization token Errors
404 Not Found Active routing connection for that GUID could not be found. None
default Default An unexpected error Errors

Schemas

ActiveRoutingConfigure

{
  "presence": true,
  "message": "string",
  "foreground": "string",
  "background": "string"
}

Properties

Name Type Required Restrictions Description
presence boolean true none Display the presence bar on mirrored pods
message string true none Text to be displayed in the notch on source.
foreground string true none Text color for message displayed in the notch on source.
background string true none Background color of notch on source. Supported colors: #B8BDBF, #7080D4, #7AC4E5, #00BE89, #FF423D, #FB8048, #F3B11B, #F36F8F, #945ECF, #8F9FA5, #61B424, #55A3D8

ActiveRoutingConnect

{
  "sink": "192.168.0.1",
  "resolution": "string",
  "post": "normal",
  "message": "string",
  "foreground": "string",
  "background": "string",
  "audio": true
}

Properties

Name Type Required Restrictions Description
sink string(ipv4) true none The display to which you are mirroring.
resolution string true none Supported value is '1920x1080'
post ActiveRoutingPostType true none Determines whether the sink display is fullscreen or normal. Fullscreen is required to display the colored notch.
message string true none The text to be displayed in the notch.
foreground string true none Text color for message displayed in the notch.
background string true none Background color of notch. Supported colors: #B8BDBF, #7080D4, #7AC4E5, #00BE89, #FF423D, #FB8048, #F3B11B, #F36F8F, #945ECF, #8F9FA5, #61B424, #55A3D8
audio boolean false none Chooses whether mirroring includes audio or not. (optional)

ActiveRoutingEnumerate

{
  "connections": {
    "property1": {
      "guid": "string",
      "ip": "192.168.0.1",
      "name": "string"
    },
    "property2": {
      "guid": "string",
      "ip": "192.168.0.1",
      "name": "string"
    }
  }
}

Properties

Name Type Required Restrictions Description
connections object true none none
» additionalProperties ActiveRoutingItem false none none

ActiveRoutingGuid

{
  "guid": "string"
}

Properties

Name Type Required Restrictions Description
guid string(uuid) true none none

ActiveRoutingItem

{
  "guid": "string",
  "ip": "192.168.0.1",
  "name": "string"
}

Properties

Name Type Required Restrictions Description
guid string(uuid) true none none
ip string(ipv4) true none none
name string true none none

ActiveRoutingLicensing

{
  "trial": "string",
  "subscription": "string",
  "licensed": true
}

Properties

Name Type Required Restrictions Description
trial string true none none
subscription string true none none
licensed boolean true none none

ActiveRoutingOverlay

{
  "text": "string",
  "color": "string"
}

Properties used to define text displayed over top of mirrored content.

Properties

Name Type Required Restrictions Description
text string true none none
color string true none none

ActiveRoutingPostType

"normal"

Properties

Name Type Required Restrictions Description
anonymous string false none none

Enumerated Values

Property Value
anonymous normal
anonymous fullscreen

ActiveRoutingSession

{
  "state": "none",
  "connections": 0,
  "framesPerSecond": 0,
  "bytesPerSecond": 0,
  "presence": true
}

Properties

Name Type Required Restrictions Description
state ActiveRoutingSessionState true none Allowed state values
connections integer(int32) true none Number of connections in session
framesPerSecond integer(int32) true none Frames per second for current session
bytesPerSecond integer(int32) true none Bytes per second for current session
presence boolean true none Is presence bar being shared in session

ActiveRoutingSessionState

"none"

Values that are allowed for session state.

Properties

Name Type Required Restrictions Description
anonymous string false none Values that are allowed for session state.

Enumerated Values

Property Value
anonymous none
anonymous source
anonymous sink

Error

{
  "error": "invalid_request",
  "description": "string"
}

Properties

Name Type Required Restrictions Description
error ErrorType true none internal - Internal error; path_failed - Patch element failed to apply at path specified in description; invalid_request - Invalid request body or missing header; invalid_token - Invalid or missing authorization token in request
description string false none none

ErrorType

"invalid_request"

internal - Internal error; path_failed - Patch element failed to apply at path specified in description; invalid_request - Invalid request body or missing header; invalid_token - Invalid or missing authorization token in request

Properties

Name Type Required Restrictions Description
anonymous string false none internal - Internal error; path_failed - Patch element failed to apply at path specified in description; invalid_request - Invalid request body or missing header; invalid_token - Invalid or missing authorization token in request

Enumerated Values

Property Value
anonymous invalid_request
anonymous not_found
anonymous resource_conflict
anonymous path_failed
anonymous internal
anonymous not_licensed
anonymous invalid_token

Errors

{
  "errors": [
    {
      "error": "invalid_request",
      "description": "string"
    }
  ]
}

Properties

Name Type Required Restrictions Description
errors [Error] false none none

GrantType

"password"

Properties

Name Type Required Restrictions Description
anonymous string false none none

Enumerated Values

Property Value
anonymous password

Success

{
  "message": "string",
  "reboot_required": true,
  "restart_required": true
}

Properties

Name Type Required Restrictions Description
message string false none none
reboot_required boolean false none none
restart_required boolean false none none

TokenErrorType

"invalid_request"

Properties

Name Type Required Restrictions Description
anonymous string false none none

Enumerated Values

Property Value
anonymous invalid_request
anonymous unauthorized_client

TokenRequest

{
  "grant_type": "password",
  "username": "string",
  "password": "string"
}

See https://tools.ietf.org/html/rfc6749#section-4.3.2

Properties

Name Type Required Restrictions Description
grant_type GrantType true none none
username string true none none
password string true none none

TokenSuccess

{
  "access_token": "string",
  "token_type": "jwt"
}

See https://tools.ietf.org/html/rfc6749#section-5.1

Properties

Name Type Required Restrictions Description
access_token string true none none
token_type TokenType true none none

TokenType

"jwt"

Properties

Name Type Required Restrictions Description
anonymous string false none none

Enumerated Values

Property Value
anonymous jwt