Management command API

The command API allows conference control and platform-level operations to be invoked.

This topic includes information on:

Command resources

A summary of the schema for command resources is available from the:

  • Management Node web interface via https://<manageraddress>/admin/platform/schema/
  • REST API via:

    • https://<manageraddress>/api/admin/command/v1/participant/
    • https://<manageraddress>/api/admin/command/v1/conference/
    • https://<manageraddress>/api/admin/command/v1/platform/

The following command resources are available via the REST API:

Component Path
Dial /api/admin/command/v1/participant/dial/
Disconnect participant /api/admin/command/v1/participant/disconnect/
Disconnect conference /api/admin/command/v1/conference/disconnect/
Mute participant /api/admin/command/v1/participant/mute/
Mute all Guests /api/admin/command/v1/conference/mute_guests/
Unmute participant /api/admin/command/v1/participant/unmute/
Unmute all Guests /api/admin/command/v1/conference/unmute_guests/
Lock conference /api/admin/command/v1/conference/lock/
Unlock conference /api/admin/command/v1/conference/unlock/
Unlock participant /api/admin/command/v1/participant/unlock/
Transfer participant /api/admin/command/v1/participant/transfer/
Change participant role /api/admin/command/v1/participant/role/
Transform layout /api/admin/command/v1/conference/transform_layout/
Create backup /api/admin/command/v1/platform/backup_create/
Restore backup /api/admin/command/v1/platform/backup_restore/
Sync LDAP template /api/admin/command/v1/conference/sync/
Send provisioning email to VMR owner /api/admin/command/v1/conference/send_conference_email/
Send provisioning email to device owner /api/admin/command/v1/conference/send_device_email/
Certificate upload /api/admin/command/v1/platform/certificates_import/
Start an overflow Conferencing Node /api/admin/command/v1/platform/start_cloudnode/
Take system snapshot /api/admin/command/v1/platform/snapshot/
Platform upgrade /api/admin/command/v1/platform/upgrade/
Upload software bundle /api/admin/command/v1/platform/software_bundle/

Resource details

More information can be obtained for each resource by downloading the resource schema in a browser. You may want to install a JSON viewer extension to your browser in order to view the JSON strings in a readable format.

For example, to view the schema for the dial command the URI would be:

https://<manageraddress>/api/admin/command/v1/participant/dial/schema/?format=json

Each schema contains information on the available fields including:

  • whether the field is optional (nullable: true) or required (nullable: false)
  • the default value
  • the type of data the field must contain
  • the choices for the field, e.g. valid_choices: ["audio", "video", "video-only"]
  • help text with additional information on usage.

Resource methods

Each command resource supports the following HTTP methods:

Method Action
POST Invokes a new command for the resource.

Response format

The response for a command will be a JSON object with the following attributes:

Attribute Value
status

success or error depending on whether or not the command succeeded.

message

An informational message string if the result was error.

data Command-specific response data.

Individual commands may have response attributes specific to the command. See the command examples for more information.

Examples

Dialing a participant into a conference

By submitting a POST request to the dial resource URI, a new participant can be dialed into a conference.

When using this command, note that:

  • The conference_alias is used for two purposes:

    • The participant being dialed will see the incoming call as coming from this alias.
    • On answer, the participant will join the conference instance associated with this alias.
  • If routing is set to routing_rule then:

    • The destination alias must match an outgoing Call Routing Rule for the call to be placed (and it then uses the protocol, outgoing location and call control systems etc. as configured for that rule).
    • You must specify system_location. In this case, this acts as the notional source location used when considering if a Call Routing Rule applies or not. A random node in that location is used, which may just take the signaling for the call if the node is loaded.
    • You do not need to specify node or protocol.
  • If routing is set to manual then:

    • One or both of the node and system_location must be specified.
    • The node overrides the system_location if both are given.
    • If only the system_location is given, a random node in that location is used, which may just take the signaling for the call if the node is loaded.
    • The node must be an IP address and not an FQDN.

The following example places a call to the alias alice and uses Call Routing Rules. The node/location used to place the call is determined by whichever Call Routing Rule matches this dial request. The rule can optionally use the Calls being handled in location condition to test against the nominated source location of London. Alice will see the call as coming from alias meet@example.com, and on answer will join the Virtual Meeting Room associated with that alias (in this case VMR_1, based on our configuration API examples), as a Host.

import requests
import json
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/participant/dial/",
    auth=('<user1>', '<password1>'),
    data={
        'conference_alias': 'meet@example.com',
        'destination': 'alice',
        'routing': 'routing_rule',
        'remote_display_name': 'Alice Parkes',
        'role': 'chair',
        'system_location': 'London',
        },
    verify=True)
print("New participant created:", json.loads(response.content)['data']['participant_id'])

Note that if the dial command is successful the response will contain a participant_id attribute which can be used in queries for status and other conference control commands such as Disconnecting a participant and Muting a participant.

Disconnecting a participant

By submitting a POST request to the disconnect resource URI, an existing participant can be disconnected from a conference instance.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/participant/disconnect/",
    auth=('<user1>', '<password1>'),
    data={
        'participant_id': '00000000-0000-0000-0000-000000000001',
        },
    verify=True)

Muting a participant

By submitting a POST request to the mute resource URI, the audio being sent from an existing conference participant can be muted, meaning all other participants will not hear them.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/participant/mute/",
    auth=('<user1>', '<password1>'),
    data={
        'participant_id': '00000000-0000-0000-0000-000000000001',
        },
    verify=True)

Muting all Guest participants

By submitting a POST request to the mute_guests resource URI, the audio being received from all Guest participants within an existing conference will be muted.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/conference/mute_guests/",
    auth=('<user1>', '<password1>'),
    data={
        'conference_id': '00000000-0000-0000-0000-000000000001',
    },
    verify=True)

Unmuting a participant

By submitting a POST request to the unmute resource URI, a previously muted conference participant will have their audio restored, meaning other participants will again be able to hear them.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/participant/unmute/",
    auth=('<user1>', '<password1>'),
    data={
        'participant_id': '00000000-0000-0000-0000-000000000001',
        },
    verify=True)

Unmuting all Guest participants

By submitting a POST request to the unmute_guests resource URI, the audio being received from all Guest participants within an existing conference will be unmuted.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/conference/unmute_guests/",
    auth=('<user1>', '<password1>'),
    data={
        'conference_id': '00000000-0000-0000-0000-000000000001',
    },
    verify=True)

Locking a conference instance

By submitting a POST request to the conference lock resource URI, the conference instance will be locked, preventing new participants from joining. Instead new participants will be held at the Waiting for conference host screen. Note that if a service has a Host PIN, participants who enter the PIN will still be able to access the conference even when it is locked. For more information, see Locking a conference and allowing participants to join a locked conference.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/conference/lock/",
    auth=('<user1>', '<password1>'),
    data={
        'conference_id': '00000000-0000-0000-0000-000000000001',
    },
    verify=True)

Unlocking a conference instance

By submitting a POST request to the conference unlock resource URI, a previously locked conference instance can be unlocked, meaning new participants will be allowed to join. Any participants held at the Waiting for conference host screen will also automatically join the conference.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/conference/unlock/",
    auth=('<user1>', '<password1>'),
    data={
        'conference_id': '00000000-0000-0000-0000-000000000001',
    },
    verify=True)

Unlocking a participant

By submitting a POST request to the participant unlock resource URI, a participant held at the Waiting for conference host screen because the conference has been locked will be allowed to join the conference.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/participant/unlock/",
    auth=('<user1>', '<password1>'),
    data={
        'participant_id': '00000000-0000-0000-0000-000000000001',
    },
    verify=True)

Transferring a participant

By submitting a POST request to the participant transfer resource URI, a participant can be moved from one conference to another. The target conference is identified by an alias in the conference_alias field, and they will have the specified role.

If the target conference is PIN-protected, the participant will bypass the PIN entry.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/participant/transfer/",
    auth=('<user1>', '<password1>'),
    data={
        'participant_id': '00000000-0000-0000-0000-000000000001',
        'conference_alias': 'meet@example.com',
        'role': 'guest'
    },
    verify=True)

Changing a participant's role

By submitting a POST request to the participant role resource URI, a participant can have its role changed. The target participant is identified by the participant_id field, and it will be given the specified role ("guest" or "chair").

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/participant/role/",
    auth=('<user1>', '<password1>'),
    data={
        'participant_id': '00000000-0000-0000-0000-000000000001',
        'role': 'chair',
    },
    verify=True)

Changing a conference's layout

By submitting a POST request to the conference transform_layout resource URI, you can control the layout, overlay text and other in-conference indicators.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/conference/transform_layout/",
    auth=('<user1>', '<password1>'),
    data={
        'conference_id': '00000000-0000-0000-0000-000000000001',
        'enable_overlay_text': True,
        'layout': '4:0'
    },
    verify=True)

Creating a system backup

You can create a system backup by submitting a POST request to the platform backup_create resource URI.

You must specify a passphrase (replacing <backup_password> in the example below). The passphrase is used to encrypt the backup file. You must remember the passphrase as it will be required if you need to subsequently restore the data.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/platform/backup_create/",
    auth=('<user1>', '<password1>'),
    data={
        'passphrase': '<backup_password>',
    },
    verify=True)

The backup file is created on the Management Node under the https://<manageraddress>/api/admin/configuration/v1/system_backup/ location.

Restoring a system backup

To restore a system backup (from a file stored on the Management Node) you need to:

  1. List the available backups on the Management Node to identify the filename of the backup you want to restore.
  2. Download the backup file to a temporary location.
  3. Restore the contents of the backup file to your Pexip Infinity system.

Listing the available backups

You can perform a GET on /api/admin/configuration/v1/system_backup/ to list the available backup files on the Management Node that can be restored (however, restoration must occur on exactly the same software version of Pexip Infinity that the backup was taken from).

import requests
response = requests.get(
    "https://<manageraddress>/api/admin/configuration/v1/system_backup/",
    auth=('<user1>', '<password1>'),
    verify=True)
print(response.content)

The response will include data similar to this for each backup file:

{
    "build": "59437.0.0",
    "date": "2021-01-08T15:36:16",
    "filename": "pexip_backup_10-44-7-0-mgr_25_59437.0.0_21_01_08_09_05_43.tar.pexbak",
    "resource_uri": "/api/admin/configuration/v1/system_backup/pexip_backup_10-44-7-0-mgr_25_59437.0.0_21_01_08_09_05_43.tar.pexbak/",
    "size": 214702132,
    "version": "25"
}

The "filename" value is what you will use in place of <filename> in the following GET command to download the file.

Note that if a backup file is no longer needed, you can perform a DELETE on the https://<manageraddress>/api/admin/configuration/v1/system_backup/<filename>/ URL to delete individual files.

Downloading the backup file

Next you can perform a GET on /api/admin/configuration/v1/system_backup/<filename>/ to download the backup file to a temporary location.

import requests
response = requests.get(
    "https://<manageraddress>/api/admin/configuration/v1/system_backup/<filename>/",
    auth=('<user1>', '<password1>'),
    verify=True)
with open("/tmp/temp.bak", "w") as file_handle:
    file_handle.write(response.content)

This downloads the backup file to /tmp/temp.bak — you can change this to your preferred location and filename if required.

Using the example response from the list of available backups, the GET would be for: "https://10.44.7.0/api/admin/configuration/v1/system_backup/pexip_backup_10-44-7-0-mgr_25_59437.0.0_21_01_08_09_05_43.tar.pexbak/"

Restoring the backup

Finally, you can restore the contents of the backup file by submitting a POST request to the platform backup_restore resource URI, telling it to use the temporary file created in the previous step.

You must also specify the passphrase that was used to encrypt the backup file when it was generated.

import requests
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/platform/backup_restore/",
    auth=('<user1>', '<password1>'),
    data={
        'passphrase': '<backup_password>',
    },
    files={
        'package': open('/tmp/temp.bak'),
    },
    verify=True)

Starting an overflow Conferencing Node

If you are using dynamic bursting, the start_cloudnode resource can be used to manually start up a specific overflow node.

import requests
import json
response = requests.post(
    "https://<manageraddress>/api/admin/command/v1/platform/start_cloudnode/",
    json={'instance_id': '<node instance id>'},
    auth=('<user1>', '<password1>'),
    verify=True)
print(response.content)

You can use the cloud_node status resource to obtain the instance IDs for your overflow nodes.

If the command is successful the response content takes the format: '{"status": "success"}'

If the Conferencing Node is already running, the response is: '{"status": "failed", "error": "Unable to start a cloud node which isn't in 'STOPPED' state"}'

If the instance_id does not match a cloud overflow node, the response is a 400 Bad Request with the following content: '{"start_cloudnode": {"instance_id": ["Failed to find the cloud node."]}}'

Taking a system snapshot

To take a 12 hour system snapshot:

import os
import re
import requests

save_path = "/tmp/"

response = requests.post(
    "https://<management-address>/api/admin/command/v1/platform/snapshot/",
    auth=(<username>, <password>),
    data={"limit": 12},  # hours
    stream=True,
    verify=True,
)
response.raise_for_status()
content_disposition = response.headers["content-disposition"]
m = re.search("filename=([^ ]+)", content_disposition)
if not m:
    raise Exception(f"Failed to find snapshot filename in {content_disposition!r}")
filename = os.path.join(save_path, m.group(1).strip('"'))
print("Saving snapshot to ", filename)
with open(filename, "wb") as fp:
    for chunk in response.iter_content(8192):
        fp.write(chunk)