Skip to content

REST API

Overview

The Serenytics API gives you access to most of the Serenytics platform features, including:

  • generate PDF reports from dashboards
  • create users and organisations
  • create data sources
  • obtain secure URLs to embed in iFrames within your application
  • execute a script

All the routes from this API starts with "api/".

REST API to extract data from datasources

Warning: there is another REST API in Serenytics. When you create a datasource, you can enable its data to be available in a REST API. This is an automatically generated REST API created for you. And you can manage and share custom API KEYs for this API to partners, colleagues or customers. Routes from this API start with "data-api/". The description to enable this data API is available here.

When to use the API vs our Python client

We advise you to use the REST API only if you are working with another language than Python or for advanced needs which are not yet available in our Python client. If you are working in the Python language, please check if the feature you need is available in our python client before using the API. The client includes error handling and is usually easier to use.

Authentification

Our API uses a key authentication. Each API key is associated to a single user. Your personal API key can be found in the Account menu.

The key must be passed in the field X-Api-Key of headers.

For example, in Python, with the requests module the way to GET the list of webapps of your organization using the route /api/web_app is:

import requests

route = "https://api.serenytics.com/api/web_app"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    web_apps = r.json()
    print(web_apps)
else:
    print("Failed to get webapps")

The same call in Javascript with Node/Axios would be:

var axios = require('axios');
route = "https://api.serenytics.com/api/web_app"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}
axios.get(route, {headers:headers}).then(response => {
  console.log(response.data);
  console.log('DONE');
}).catch((e)=>{
  console.log(e);
  console.log('FAILED');
});

Hint

The Serenytics frontend is a simple REST API client. This means it's possible to open your browser console network tab to inspect the API calls.

Do not share your API key

Your API key is very powerful. It lets you execute all the actions that can be made by our frontend. So keep it secret and do not commit it in your code repository. If you just need to get data from your datasources with an API (or share data to your partners through an API), use the dedicated data-api. It is safer as the keys you use can be managed and be restricted to a set of datasources. Documentation is here.

Examples

Here is an example you can use to get your jobs and datasources and backup them in files. This can be useful to backup your python jobs in a folder that you put in a Git repository. If you re-run it after a while, you can see your changes with your previous versions.

YOUR_API_KEY= "xxxxxxx"

import requests
import os
from pprint import pprint

DESTINATION_FOLDER = f"./serenytics_backup"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

def get_obj_from_route(obj_name:str):
    route = f"https://api.serenytics.com/api/{obj_name}"

    r = requests.get(route, headers=headers)
    if r.status_code == 200:
        objects = r.json()["objects"]
    else:
        print(f"Failed to get {obj_name}")
        exit(1)

    return objects


def get_folders():
    route = "https://api.serenytics.com/api/folder"

    r = requests.get(route, headers=headers)
    if r.status_code == 200:
        folders = r.json()["objects"]
    else:
        print("Failed to get jobs")
        exit(1)

    return folders



def backup_objects(object_name:str):
    objects = get_obj_from_route(object_name)

    print(f"Backup {object_name}s")
    folders = get_folders()
    folders = {f["uuid"]: f for f in folders}

    for obj in objects:
        folder_uuid = obj["folder_uuid"]
        folder = folders.get(folder_uuid)

        local_folder = f"{DESTINATION_FOLDER}/{object_name}s/{folder['name']}"
        if not os.path.exists(local_folder):
            print(f"Create folder {local_folder}")
            os.makedirs(local_folder)

        # extract code field as it must be written in another file.
        code = obj.get("code")
        if "code" in obj:
            del obj["code"]

        filename = obj['name'].replace('/','_')
        local_file = f"{local_folder}/{filename}.json"
        with open(local_file, 'w') as file:
            pprint(obj, stream=file)

        if code:
            local_file = f"{local_folder}/{filename}.py"
            with open(local_file, 'w') as file:
                file.write(code)

    print("done")


backup_objects("script")
backup_objects("data_source")

WebApp

GET /api/web_app

Get the list of web_app (i.e. dashboards).

import requests
route = "https://api.serenytics.com/api/web_app"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    web_apps = r.json()
    print(web_apps)
else:
    print("Failed to get web_apps")

GET /api/web_app/:uuid

Returns the WebApp object from its uuid.

URL parameters:

  • uuid: uuid of the web app (dashboard) you want to obtain

Returns: the json object of the queried WebApp.

Warning

Contact us if you need details about the WebApp model.

Python example:

import requests

route = "https://api.serenytics.com/api/web_app/%s" % YOUR_WEB_APP_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    web_app = r.json()
    print(web_app["name"])

PUT /api/web_app/:uuid

Modify a WebApp.

URL parameters:

  • uuid: uuid of the web app (dashboard) to modify

Body parameters:

  • The entire WebApp JSON or only the fields you want to modify.

Returns: the json object of the modified WebApp.

Warning

Contact us if you need details about the WebApp model.

Python example:

import requests
import json

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

route = "https://api.serenytics.com/api/web_app/%s" % YOUR_WEB_APP_UUID

# get the webapp
r = requests.get(route, headers=headers)
if r.status_code != 200:
    print('Failed to get dashboard')
    exit(1)

web_app = r.json()

# modify the local object
web_app["name"] = "My New Name"


# save the modified object
r = requests.put(route, headers=headers, data=json.dumps(web_app))
if r.status_code != 200:
    print('Failed to update dashboard')
    exit(1)
print(r.json()["name"])

DELETE /api/web_app/:uuid

Delete the WebApp object from its uuid.

URL parameters:

  • uuid: uuid of the web app (dashboard) to delete

Returns: a 204 code if the WebApp was deleted

Warning

Use with caution, the deleted WebApp cannot be recovered.

Python example:

import requests

route = "https://api.serenytics.com/api/web_app/%s" % YOUR_WEB_APP_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.delete(route, headers=headers)
print(r.status_code)

POST /api/web_app/:uuid/clone

Clone a WebApp.

URL parameters:

  • uuid: uuid of the web app (dashboard) to clone

Returns: the json object of the cloned WebApp.

Python example:

import requests
import json

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

route = "https://api.serenytics.com/api/web_app/%s/clone" % YOUR_WEB_APP_UUID

# get the webapp
r = requests.post(route, headers=headers)
if r.status_code != 200:
    print('Failed to clone dashboard')
    exit(1)

cloned_web_app = r.json()

POST /api/web_app/:uuid/embed

Generate a secure URL for a given dashboard. If your dashboard is a template dashboard, this API also lets you define the values of the global filter variables you defined.

URL parameters:

  • uuid: uuid of the web app (dashboard) you want to embed

Body parameters:

  • expire_in (integer): Validity of the obtained URL in seconds. Must be > 0 and <= 3600 * 24 * 5 (5 days). Once this delay is over, the app will refuse to open this URL and all the queries sent by the dashboard will be refused.
  • payload (object): The payload used to instantiate a template dashboard.
  • nb_max_embed (integer) [optional]: number of times the obtained dynamic URL can be used. Must be an integer value greater or equal to 1. We strongly advise you to use 1 as a safe value. See "security" note below to get more details.

Returns: a json object with the URL to use to load this dashboard.

In the result, the embeddedUrl is the secure URL to embed in an iFrame.

Warning

You need to be the owner of the dashboard to call this API.

Expire_in details

When the expire_in delay is expired, two things happen. First, you won't be able to open this URL. The Serenytics app will detect that this URL is not valid anymore. So, for this first point, you could set expire_in to a few seconds (i.e. the delay between your call to /embed and the time you open the dashboard in the iFrame should be short). The second point is that once the expire_in delay is expired, all the data-queries sent by the dashboard will be rejected. Let's say that your user opens your app at t1. Before t1 + expire_in, everything will be ok. But if he tries to use a filter in the dashboard after t1 + expire_in, the query will be refused. So we advise you to choose a long enough expiration delay (such as 24 hours).

Security

When you use this API route to embed a dashboard, you embed the obtained embeddedUrl in an iFrame. A malicious user can open the source code of your app in the browser and extract this URL. Then he can pass it to another user who could open the dashboard (until the expire_in delay is expired). To avoid this malicious use case, there is an option named nb_max_embed. If set to 1, the first time the embeddedUrl is opened, everything will work (and this first time will be when the embedded dashboard is displayed in your application). If a malicious user copies this URL from your page source code, and then tries to open it in another tab/browser (or passes it to another person), the dashboard won't be displayed as it has already been displayed once.

Python example:

import json
import requests

route = "https://api.serenytics.com/api/web_app/%s/embed" % YOUR_WEB_APP_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

data = {
    "expire_in": 86400,  # 24 hours
    "payload": {'quarter': 'Q2'},
    "nb_max_embed": 1
}

r = requests.post(route, data=json.dumps(data), headers=headers)

Result:

HTTP 200 OK
Content-type: application/json

{
  "embeddedPayload": "e8d5d2cd-60cb-453a-97e7-0eb43cc7d67f",
  "embeddedUrl": "https://app.serenytics.com/api/web_app/7eef1661-6390-40c3-b326-f3056c1d4287?embeddedPayload=e8d5d2cd-60cb-453a-97e7-0eb43cc7d67f",
  "status": "ok"
}

Java example:

// See https://github.com/Serenytics/serenytics-demo-java-client for a complete running
// example, including maven config and imports

String apiKey = "YOUR_API_KEY";
String webAppUuid = "YOUR_WEB_APP_UUID";

String urlTemplate = "https://api.serenytics.com/api/web_app/%s/embed";

HttpPost request = new HttpPost(String.format(urlTemplate, webAppUuid));
request.setHeader("X-Api-Key", apiKey);
request.setHeader("Content-type", "application/json");

JSONObject content = new JSONObject();
content.put("payload", (new JSONObject()).put("quarter", "Q2"));
content.put("expire_in", 3600);
content.put("nb_max_embed", 1);

StringEntity entity = new StringEntity(content.toString(), "UTF-8");
entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
request.setEntity(entity);

POST /api/web_app/:uuid/dashboard_variables

Set the variables of a dashboard. The dictionary passed as parameter is merged into the existing one defined in the dashboard. You cannot remove a variable in the existing dashboard variables. You can only update a list of variables or add new ones.

URL parameters:

  • uuid: uuid of the web app (dashboard)

Payload

Pass the new variables as a JSON, ina field named dashboard_variables.

Returns: the modified dashboard.

Python example:

import requests
import json

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

url = 'https://api.serenytics.com/api/web_app/' + DASH_UUID + '/dashboard_variables'

payload = {
    'dashboard_variables' : {
        'date_of_data': '2022-06-24',
        'business_unit': 'UK'
    }
}

r = requests.post(url,data=json.dumps(payload), headers=headers)


if r.status_code != 201:
    print("Failed to set the new variables")

Script

GET /api/script

Get the list of scripts (i.e. jobs).

import requests
route = "https://api.serenytics.com/api/script"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    jobs = r.json()
    print(jobs)
else:
    print("Failed to get jobs")

POST /api/script/:script_uuid/run

Run a Serenytics script (with or without parameters).

URL parameters:

  • uuid: uuid of the script to run

Body parameters:

  • async_[optional] (boolean): Whether the API call returns immediately or waits for the script execution to be finished. Default: true.

Python example with params:

import json
import requests

route = "https://api.serenytics.com/api/script/%s/run" % YOUR_SCRIPT_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

data = {
    "param1": 120,
    "param2": {'quarter': 2}
}

r = requests.post(route, data=json.dumps(data), headers=headers)
# note : use client.script_args in the Serenytics script to retrieve this data

Python example without params:

import json
import requests

route = "https://api.serenytics.com/api/script/%s/run" % YOUR_SCRIPT_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.post(route, headers=headers)

Result:

HTTP 200 OK
Content-type: application/json

{"status": "ok", "text": "Script launched"}
HTTP 400 Bad Request

This URL lets you run a script you defined in the Serenytics studio. By default the script is run in an asynchronous way. The return of the API call only indicates that the script execution is queued in the Serenytics server.

You can pass a JSON with parameters to the script (see example above). In the Serenytics script, you can retrieve this JSON by calling the property `client.script_args.

If you specify async=false in the JSON parameters or in the url (.../run?async_=false) the script is run in a synchronous way. The API call waits for the script to be finished before returning the exit code, and the stdout and stderr outputs of the script.

Running the script as a webhook

You can also run the script as a webhook (for instance to use as a Slack command or to integrate with Zapier).

In this case you first need to generate a token for your script in the Serenytics studio. Then use an url of the form: https://api.serenytics.com/api/script/:script_uuid/run?token=YOUR_SCRIPT_TOKEN as a webhook.


DataSource

GET /api/data_source

Get the list of datasources.

import requests
route = "https://api.serenytics.com/api/data_source"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    data_sources = r.json()
    print(data_sources)
else:
    print("Failed to get data_sources")

GET /api/data_source/:uuid

Returns the DataSource object from its uuid.

URL parameters:

  • uuid: uuid of the DataSource you want to obtain

Returns: the json object of the queried DataSource.

Warning

Contact us if you need details about the DataSource model.

Python example:

import requests

route = "https://api.serenytics.com/api/data_source/%s" % YOUR_DATA_SOURCE_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    data_source = r.json()
    print(data_source["name"])

PUT /api/data_source/:uuid

Modify a DataSource.

URL parameters:

  • uuid: uuid of the DataSource to modify

Body parameters:

  • The entire DataSource JSON or only the fields you want to modify.

Returns: the json object of the modified DataSource.

Warning

Contact us if you need details about the DataSource model.

Python example:

import requests
import json

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

route = "https://api.serenytics.com/api/data_source/%s" % YOUR_DATA_SOURCE_UUID

# get the data_source
r = requests.get(route, headers=headers)
if r.status_code != 200:
    print('Failed to get the data source')
    exit(1)

data_source = r.json()

# modify the local object
data_source["name"] = "My New Name"


# save the modified object
r = requests.put(route, headers=headers, data=json.dumps(data_source))
if r.status_code != 200:
    print('Failed to update data_source')
    exit(1)
print(r.json()["name"])

DELETE /api/data_source/:uuid

Delete the DataSource object from its uuid.

URL parameters:

  • uuid: uuid of the DataSource to delete

Returns: a 204 code if the DataSource was deleted

Warning

Use with caution, the deleted DataSource cannot be recovered.

Python example:

import requests

route = "https://api.serenytics.com/api/data_source/%s" % YOUR_DATA_SOURCE_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.delete(route, headers=headers)
print(r.status_code)

POST /api/data_source/:uuid/invalidate_cache

Invalidate data source cache.

All future calls to get data (for instance when loading a dashboard using this source) won't use current cache. Works whatever the cache config of the source.

URL parameters:

  • uuid: uuid of the data source

Example:

import requests

route = "https://api.serenytics.com/api/data_source/%s/invalidate_cache" % YOUR_DATA_SOURCE_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.post(route, headers=headers)

Result:

HTTP 200 OK
Content-type: application/json

{"status": "ok"}

POST /api/data_source/:uuid/batch

Insert, update, or delete several rows in the datawarehouse in one call. All operations are executed in the given order.

URL parameters:

  • uuid: uuid of the data source

Body parameters:

  • async_[optional] (boolean): Whether the API call returns immediately or waits for the data operations to be finished. Default: true.
  • operations (object): Operations to execute on data source (insert/update/delete).

Example:

import json
import requests

route = "https://api.serenytics.com/api/data_source/%s/batch" % YOUR_DATA_SOURCE_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

data = {
   "async_": True,
   "operations": [
       {
           "action": "insert",
           "rows": [
               {'id': 1, 'country': 'FR', 'name': 'John', 'quantity': 10},
               {'id': 2, 'country': 'US', 'name': 'Mark', 'quantity': 2},
               {'id': 3, 'country': 'UK', 'name': 'John', 'quantity': 1},
               {'id': 4, 'country': 'US', 'name': 'David', 'quantity': 8}
           ]
       },
       {
           "action": "insertOrUpdate",
           "primaryKey": "id",
           "rows": [
               {'id': 1, 'country': 'FR', 'name': 'John', 'quantity': 50},
               {'id': 5, 'country': 'US', 'name': 'Peter', 'quantity': 13}
           ]
       },
       {
           "action": "delete",
           "primaryKey": "id",
           "rows": [2, 4]
       }
   ]
}

r = requests.post(route, headers=headers, data=json.dumps(data))

Result:

HTTP 200 OK
Content-type: application/json

{"status": "ok", "task_id": "57727bb1b321731d9439b8bd"}
HTTP 400 Bad Request

There are three different actions supported:

  • insert: Insert new rows in the datawarehouse. The rows attribute must contain a list of data rows.
  • insertOrUpdate: Insert or update an existing row. You need to set the primaryKey attribute to indicate which column is the primary key used to determine if the row already exists and must be updated or if the row doesn't exist and must be inserted. The rows attribute contains a list of data rows and each one must have a value in the primary key column.
  • delete: Delete existing rows. Same as insertOrUpdate, you need to set the primaryKey attribute. The rows attribute must contain a list of the primary key values to delete.

When calling the API with async_=true, the result contains a task_id (see example above). You can then check the results of the task by using the task API.

Warning

The new inserted or updated data should have the same structure as old data (i.e. same columns). If not, new columns will be ignored and existing columns in the datawarehouse will be filled with NULL.

Warning

Only use column names in lower case without accentuated characters. This is a restriction from our internal datawarehouse. You can later use our source mapper in the user interface to rename your columns for the user designing dashboards.

Formatted Data

The formatted data route lets you query data from a datasource. You can execute simple query but you can also add groupbys and filters.

Use the data-api to get data

The formatted_data API is the internal API used by the Serenytics frontend. If you need to get data from your datasources with an API (or share data to your partners through an API), use the dedicated data-api. It is safer as the keys you use can be managed and be restricted to a set of datasources. Documentation is here.

POST /api/data_source/formatted_data/:data_source_uuid

Obtain data from a datasource. This route can also be used to get only columns info of a given datasource.

The number of rows returned by this API is capped to 20 000. If the queried datasource is close to this limit, you must check the number of rows obtained by your API call. If the API returned exactly 20 000 rows, it means the result has been capped and you got only a subset of the dataset.

If you query an invalid datasource, or if you're not allowed to access this datasource, you will receive the corresponding status code from the API (e.g. 401 or 403).

In all other cases, the API will return a 200 http code. You need to check the field status from the received data. It contains ok if everything went well and error if an error occured. In this case, the field errors contains details about the errors.

URL parameters:

  • uuid: uuid of the data source

Example:

This example shows how to get columns info for a given datasource.

import requests

SOURCE_UUID = 'YOUR_SOURCE_UUID'

route = 'https://api.serenytics.com/api/formatted_data/' + SOURCE_UUID

headers = {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-type': 'application/json'
}

data = {
    "only_headers": "true"
}
r = requests.post(route, headers=headers, data=json.dumps(data))

print(r.json())

Result:

{
'columns_titles': [
    {'name': 'Date', 'type': 'datetime', 'datetime_format': '%Y-%m-%d'},
    {'name': 'Country', 'type': 'str'}, {'name': 'Category', 'type': 'str'},
    {'name': 'SubCategory', 'type': 'str'},
    {'name': 'Quantity', 'type': 'int'},
    {'name': 'Price', 'type': 'float'},
    {'name': 'Cost of Goods', 'type': 'float'}
],
'status': 'ok'}

Example:

This example shows how to get the actual data from a given datasource. You have to pass the names of the columns to select in the data_processing_pipeline field (to be precise, in the first value of this array).

import requests

SOURCE_UUID = 'YOUR_SOURCE_UUID'

route = 'https://api.serenytics.com/api/formatted_data/' + SOURCE_UUID

headers = {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-type': 'application/json'
}

data = {
        'order': 'row_by_row',
        'data_processing_pipeline': [{
            'select': ["Country","Date"]
        }]
    }
r = requests.post(route, headers=headers, data=json.dumps(data))

print(r.json())

Example:

This example shows how to add groupbys, select, filters and a limit.

import requests

SOURCE_UUID = 'YOUR_SOURCE_UUID'

route = 'https://api.serenytics.com/api/formatted_data/' + SOURCE_UUID

headers = {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-type': 'application/json'
}

data = {
        'order': 'row_by_row',
        'data_processing_pipeline': [{
            'group_by': ['Country'],
            'select': [{'name': 'Country'},
                       {'name': 'Quantity', 'agg_function': 'sum'}],
            'where': [{'name': 'Price', 'op': '>', 'value': '20'}],
            'limit': 100,
        }]
    }
r = requests.post(route, headers=headers, data=json.dumps(data))

print(r.json())

Tip

If you struggle to define the correct options to pass to the API. Create a table widget in the Serenytics studio with the groupby/filter/limits options you need. Then open the browser developer console in the Network section to inspect the payload passed to this API (search for the formatted_data API call).

Example:

This example shows how to get the data from a formula defined in the datasource. To query a formula, you need to get its unique identifier and pass it in the measureUuid field. This identifier is available in the formula editor, in the documentation section of your formula.

In this example, the formula is used in the select fields. But you can use a formula in the groupbys or filters in the same way.

import requests

SOURCE_UUID = 'YOUR_SOURCE_UUID'

route = 'https://api.serenytics.com/api/formatted_data/' + SOURCE_UUID

headers = {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-type': 'application/json'
}

data = {
        'order': 'row_by_row',
        'data_processing_pipeline': [{
            'select': [
                {"name": "Country"},
                {"name": "MyFormula", "measureUuid": "697c7a7d0ffd5254"}]
        }]
    }
r = requests.post(route, headers=headers, data=json.dumps(data))

print(r.json())

Field name for a formula

When querying a formula, you need to pass both its name and unique identifier. The name is only used in the output of the API. You can use any value but it must be defined (in the future, this field may become optional). The field measureUuid is mandatory.

Task

GET /api/task/:task_id

Get the status of the specified task.

URL parameters:

  • task_id: id of the task

Example:

import json
import requests

route = "https://api.serenytics.com/api/task/%s" % YOUR_TASK_ID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)

Result:

HTTP 200 OK
Content-type: application/json

{"status": "pending"}
HTTP 200 OK
Content-type: application/json

{"status": "ok"}

Folder

GET /api/folder

Returns the list of folders.

Returns: a json object with a field objects contains a list of folders.

Warning

Contact us if you need details about the Folder model.

Python example:

import requests

route = "https://api.serenytics.com/api/folder"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    folders = r.json()["objects"]
    for f in folders:
        print(f["name"], "--> ", f["resource_type"])

POST /api/folder

Create a folder.

Returns: the json object of the created folder.

Body parameters:

  • name: The name of the folder to create.
  • resource_type: The type of resource for this folder (in datasource, webapp, script).

Warning

Contact us if you need details about the Folder model. Folders with the word home in their name are very specific. Do not use this keyword in the folders your create.

Python example:

import requests
import json

route = "https://api.serenytics.com/api/folder"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

data = {
   "name": "My new folder",
   "resource_type": "datasource"
   }

r = requests.post(route, headers=headers, data=json.dumps(data))
if r.status_code == 201:
    print(r.json())

User

GET /api/user

Returns the list of users in your organization.

Returns: a json object with a field objects contains a list of users.

Python example:

import requests

route = "https://api.serenytics.com/api/user"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    users = r.json()["objects"]
    for user in users:
        print(f'{user["username"]} --> {user["category"]}')

GET /api/user/<user_uuid>

Returns a given user (using its uuid).

Returns: the user as a json object.

Python example:

import requests

route = "https://api.serenytics.com/api/user/93251f96-acbb-4bb7-b101-ca628c5c21b8"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
print(r.status_code)
print(r.json())

GET /api/user/byname/

Returns a given user (using its username).

Returns: the user as a json object.

Python example:

import requests

route = "https://api.serenytics.com/api/user/byname"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers, params={'username':'john@doe.com'})
print(r.status_code)
print(r.json())

POST /api/user

Creates a new user.

Returns:

  • 201 code and the json object of the created user if the user was created.
  • 400 code if the user already exists.
  • 401 code if your not authorized to create users (you must be an admin user).

Body parameters:

  • username: The username of the user to create.
  • password: The password of the user to create.
  • category: The type of the new user (in viewer, studio_dashboard, studio,admin).

The type studio_dashboard is used for Business Analyst.

Python example:

import requests
import json

route = "https://api.serenytics.com/api/user"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

data = {
   "username": "john@doe.com",
   "password": "myStrongPassword",
   "category": "viewer"
   }

r = requests.post(route, headers=headers, data=json.dumps(data))
print(r.status_code)
print(r.json())

PUT /api/user/<user_uuid>

Modifies category and meta_data fields of a given user. Metadata are per-login values which can be used to filter dashboards in viewer mode (e.g. to filter a dashboard by user's business unit).

Returns:

  • 200 code and the json object of the modified user.

Body parameters:

  • category: The category of the user (in viewer, studio_dashboard, studio,admin).

The body parameter must only contains the fields you want to update in the user object.

Python examples:

import requests
import json

route = "https://api.serenytics.com/api/user/93251f96-acbb-4bb7-b101-ca628c5c21b8"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

new_params = {
    "category": "studio",
    "login_metadata": {"business_unit": "france"}
}
r = requests.put(route, headers=headers, data=json.dumps(new_params))
print(r.status_code)
print(r.json())

Here is a full example to modify the metadata of a user.

import json
import requests

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

# Get the user
route1 = 'https://api.serenytics.com/api/user/byname'
r1 = requests.get(route1, headers=headers, params={'username':'john@doe.com'})
print(r1.status_code)

# Modify its metadata
if r1.status_code == 200:
    user_uuid = r1.json()["uuid"]
    route2 = 'https://api.serenytics.com/api/user/' + user_uuid
    new_params = {
        "login_metadata": {"business_unit": "france"}
    }
    r2 = requests.put(route2, headers=headers, data=json.dumps(new_params))
    print(r2.status_code)
    print(r2.json())

DELETE /api/user/<uuid>

Delete the User object from its uuid.

URL parameters:

  • uuid: uuid of the user to delete

Returns: a 204 code if the User was deleted

Python example:

import requests

route = "https://api.serenytics.com/api/user/%s" % USER_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.delete(route, headers=headers)
print(r.status_code)

Usersgroup

A usersgroup object is a group of user. When sharing a dashboard to a list of viewers, it is advised to create a group with those users and then to share the dashboard to this group.

GET /api/usersgroup

Returns the list of usersgroup in your organization.

Returns: a json object with a field objects contains a list of usersgroup.

Python example:

import requests

route = "https://api.serenytics.com/api/usersgroup"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
if r.status_code == 200:
    groups = r.json()["objects"]
    for g in groups:
        print(g["name"])

GET /api/usersgroup/<user_uuid>/list_of_users

Returns a the list of users in a given group (using its uuid).

Returns: the user as a json object.

Python example:

import requests

route = "https://api.serenytics.com/api/usersgroup/8dee7842-3596-494b-8fa6-c81c50e9574d"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers)
print(r.status_code)
print(r.json())

users = r.json()["objects"]
for u in users:
    print(u["username"])

GET /api/usersgroup/byname

Returns a given usersgroup (using its name).

Returns: the usersgroup as a json object.

Python example:

import requests

route = "https://api.serenytics.com/api/usersgroup/byname"

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.get(route, headers=headers, params={'name':'marketing team'})
print(r.status_code)
print(r.json())

POST /api/usersgroup/<group_uuid>/adduser

Add a user (by its username) to a group.

Returns:

  • 201 when the user is added to the group.
  • 400 if the user is already in the group (check the json content in response to get detailed message).

Body parameters:

  • username_to_add: The username of the user to add to the group.

Python example:

import requests
import json

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

# get the group object from its name
route1 = "https://api.serenytics.com/api/usersgroup/byname"

r1 = requests.get(route, headers=headers, params={'name':'marketing team'})
print(r1.status_code)
print(r1.json())
group_uuid = r1.json()["uuid"]

# add the user to the group
route2 = "https://api.serenytics.com/api/usersgroup/" + group_uuid + "/adduser"
r2 = requests.post(route2, headers=headers, data=json.dumps({'username_to_add': 'john@doe.com'}))
print(r2.status_code)
print(r2.json())

POST /api/usersgroup/<group_uuid>/removeuser

Remove a user (by its username) from a group.

Returns:

  • 204 if the user is removed from the group.
  • 400 if the user is not in the group.

Body parameters:

  • username_to_remove: The username of the user to remove from the group.

Python example:

import requests
import json

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

# get the group object from its name
route1 = "https://api.serenytics.com/api/usersgroup/byname"

r1 = requests.get(route, headers=headers, params={'name':'marketing team'})
print(r1.status_code)
print(r1.json())
group_uuid = r1.json()["uuid"]

# remove the user from the group
route2 = "https://api.serenytics.com/api/usersgroup/" + group_uuid + "/removeuser"
r2 = requests.post(route2, headers=headers, data=json.dumps({'username_to_remove': 'john@doe.com'}))
print(r2.status_code)
print(r2.json())

DELETE /api/usersgroup/<uuid>

Delete the Usersgroup object from its uuid.

URL parameters:

  • uuid: uuid of the usersgroup to delete

Returns: a 204 code if the Usersgroup was deleted

Python example:

import requests

route = "https://api.serenytics.com/api/usersgroup/%s" % USERSGROUP_UUID

headers = {
    'X-Api-Key': YOUR_API_KEY,
    'Content-type': 'application/json'
}

r = requests.delete(route, headers=headers)
print(r.status_code)