Tubular Labs API

Table of contents:

Overview

The Tubular Web API allows you to access the data backing your track dashboards programmatically without needing to visit the Tubular application from a web browser. You can then leverage this data to create your own trends graphs or other internal applications.

The Web API consists of HTTP RPC-style methods, all of the form https://tubularlabs.com/api/v3/METHOD.

All API calls must be issued over HTTPS using a POST method. Arguments specific to a call can be passed in the form of either HTTP url parameters or as form variables.

The response from a call contains a JSON object, which will always contain a top-level boolean property “ok”, indicating success or failure. In the case of problematic calls that could still be completed successfully, “ok” will be true and the warning property will contain a short machine-readable warning code (or comma-separated list of them, in the case of multiple warnings).

Success response strings take the following form:

{
  "ok": true,
  "stuff": "This is good"
}

Error response strings take the following form:

{
  "ok": false,
  "error": "something_bad"
}

Warning response strings take the following form:

{
  "ok": true,
  "warning": "something_problematic",
  "stuff": "Your requested information"
}

Standard HTTP error status codes will be returned when method calls result in failures. Refer to the table of potential error response codes below for specific examples.

Authentication

In order to ensure the security of your data, the Tubular API requires a basic system of authentication.

All requests will be authenticated with OAuth 2.0. API tokens can either be passed in the Authentication HTTP header as Bearer tokens or as a “token” parameter to the API call itself. Tubular uses 2Leg OAuth to authenticate its API requests. The Token issue endpoint is: https://tubularlabs.com/api/v3/oauth.token

The “client secret” used by the Token issue endpoint described above is represented by an API credential that is tied to your Tubular Intelligence account. You can generate a new API credential by going to your account settings page under the API page or by visiting the following URL: https://tubularlabs.com/app/settings/api.

If you are not able to access this page, then please contact Tubular support.

The client will get an OAuth 2.0 response which will contain the token to continue to then make additional calls to the API endpoints. The token should preferentially be encoded as an Authentication header rather than passed as a token. The token you get in the auth handshake is temporary and will only be usable within a 24 hour period from when the token is first generated.

Responses

HTTP Response codes

Successful API requests should return the 200 HTTP status code.

In the event of an error, the response will include an error message in the body and an associated HTTP response code. A failure code will be returned in the event of malformed data (e.g. missing required argument, etc.).  If the request is structurally correct (i.e., all required arguments are provided), but a requested resource is either not found or malformed this will be considered a 200 response, however the “ok“ flag will be set to “false” to indicate an error has occurred.

The following table provides a list of standard errors that a method may return. Methods will extend this with their own local errors as needed.

HTTP Code Error Description
400 invalid_array_arg A PHP style array argument was passed – this is not valid
400 invalid_post_data A POST request was made with a valid Content-Type but the data was missing or incorrect.
400 invalid_post_type A POST request was made with a Content-Type that wasn’t one of: application/json application/x-www-form-urlencoded multipart/form-data text/plain
400 not_authed No authentication token provided
401 invalid_auth Invalid authentication token
403 account_inactive Authentication token is for a deleted user or team
404 not_found The requested API endpoint was not found
405 method_not_allowed A GET method was used when POST was expected or vice versa.
413 invalid_arg_name The method was passed invalid argument(s). This includes very long names and names with non-alphanumeric characters other than _. If you get this error, it is typically an indication that you have made a very malformed API call.
429 rate_limited The security token that was used has exceeded a query limitation. The error message should indicate the precise limitation exceeded (e.g., “60 queries per minute”) that pertains to your account configuration (see Rate Limiting below).

HTTP Content-Type

The only valid response format is JSON and messages will have a Content-Type header of application/json included.

Rate Limiting

All API requests must adhere to a rate limit. The current default rate limit is 60 requests per minute. This rate limit applies to any combination of API methods that are called within a trailing 1 minute timeframe. Issuing 10 requests to dashboard.metrics followed by 51 requests to auth.test all within one minute of each other, for example, would cause the last call to auth.test to return a rate_limited error.

If you would like to raise your rate limit, then please reach out to your Tubular sales representative.

Methods

All API methods will follow the convention of SCOPE.ACTION – where scope is the area (e.g. “auth” or  “dashboard”) and action is what operation to perform (e.g. “list”, “metrics”, “trends”).

  • auth.test —  Checks authentication token and verifies that it hasn’t expired.
  • dashboard.list — Returns a list of all tracked dashboards.
  • dashboard.metrics — Returns the top level metrics of a track dashboard.
  • dashboard.trends — Returns the data necessary to generate the daily graph on a track dashboard.

auth.test

https://tubularlabs.com/api/v3/auth.test

Checks authentication token and verifies that it hasn’t expired.

Note that this method might be useful for testing purposes, however it is discouraged from being used in practice since it will count against your rate limit. Furthermore, all method calls are designed to return an invalid_auth error (see error code table above) if an expired token is used.

Arguments

Argument Example Required Description
token xxxx-xxxx-xxx Optional (include in HTTP auth header if not specified). Authentication token

Response

{
  "ok": true
}
Parameter Description
ok Standard API response for success/failure

dashboard.list

https://tubularlabs.com/api/v3/dashboard.list

Returns a list of all tracked dashboards

Arguments

Argument Example Required Description
token xxxx-xxxx-xxx Optional (include in HTTP auth header if not specified). Authentication token

Response

{
    "ok": true,
    "dashboards": [
        {
             "id": 12345,
             "name": "Super Cool Videos"
        },
        {
             "id": 12346,
             "name": "The best from the rest"
        },
        {
             "id": 12347,
             "name": "My Favorite Peeps"
        }
    ]
}
Parameter Description
ok Standard API response for success/failure
dashboards A list of dashboards
dashboards.id The ID for the specific dashboard
dashboards.name The name for this dashboard

dashboard.metrics

https://tubularlabs.com/api/v3/dashboard.metrics

Returns the top level metrics of a track dashboard.

Arguments

Argument Example Required Description
token xxxx-xxxx-xxx Optional (include in HTTP auth header if not specified). Authentication token
dashboard_id 12345 Required The identifier of the requested track dashboard. Only dashboards owned by the user for whom the authenticated token was generated for will be accepted.
date_start 2016-03-01 Optional A date in the format YYYY-MM-DD representing the starting date for the timeframe of data that you want back. If not specified, it defaults to 90 days from today.
date_end 2016-04-01 Optional A date in the format YYYY-MM-DD representing the ending date for the timeframe of data that you want back. If not specified, it defaults to the last day for which data is available.

Response

{
    "ok": true,
    "metrics": [
        {
           "platform":"youtube",
           "views":23456,
           "engagements":4560,
           "uploads":12
        },
        {
            "platform":"facebook",
            "views":23456,
            "engagements":4560,
            "uploads":12
        },
        {
            "platform":"aol",
            "views":23456,
            "engagements":4560,
            "uploads":12
        }
    ]
}
Parameter Description
ok Standard API response for success/failure
metrics A list of of summary metrics by platform
metrics.platform The platform name identifier
metrics.views The sum of the views over the time period for the specific platform
metrics.engagements The sum of the engagements over the time period for the specific platform
metrics.uploads The sum of the uploads over the time period for the specific platform

dashboard.trends

https://tubularlabs.com/api/v3/dashboard.trends

Returns the data necessary to generate the daily graph on a track dashboard.

Arguments

Argument Example Required Description
token xxxx-xxxx-xxx Optional (include in HTTP auth header if not specified). Authentication token
dashboard_id 12345 Required The integer identifier of the requested track dashboard. Only dashboards owned by the user for whom the authenticated token was generated for will be accepted.
date_start 2016-03-01 Optional A date in the format YYYY-MM-DD representing the starting date for the timeframe of data that you want back. If not specified, it defaults to 90 days from today.
date_end 2016-04-01 Optional A date in the format YYYY-MM-DD representing the ending date for the timeframe of data that you want back. If not specified, it defaults to the last day for which data is available.

Response

{
    "ok": true,
    "trends":[
        {
            "platform":"youtube",
            "trends":[
                {
                    "day":"2016-05-01",
                    "views":23456,
                    "engagements":4560,
                    "uploads":12
                },
                {
                    "day":"2016-05-02",
                    "views":23456,
                    "engagements":4560,
                    "uploads":12
                },
                {
                    "day":"2016-05-30",
                    "views":23456,
                    "engagements":4560,
                    "uploads":12
                }
            ]
        },
        {
            "platform":"vine",
            "trends":[
                {
                    "day":"2016-05-01",
                    "views":23456,
                    "engagements":4560,
                    "uploads":12
                },
                {
                    "day":"2016-05-02",
                    "views":23456,
                    "engagements":4560,
                    "uploads":12
                },
                {
                    "day":"2016-05-30",
                    "views":23456,
                    "engagements":4560,
                    "uploads":12
                }
            ]
        }
    ]
}
Parameter Description
ok Standard API response for success/failure
trends The trends by platform for the given dashboard
trends.platform The identifier for the platform
trends.trend.views The number of views for the given day
trends.trend.engagements The number of engagements for the given day
trends.trends.uploads The number of video uploads for the given day

Sample code

This section contains some sample code that exercises the API using various languages and/or tools.

Python client

The following code was written using Python 2.7.10 with no additional python modules installed.

#!/usr/bin/env python
 
import os
import json
import oauthlib
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
 
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = "1"

#
# The following Client ID and Client Secret values are uniquely tied to your Tubular Intelligence
# account. They can be generated by visiting the following url:
#
#   https://tubularlabs.com/app/settings/api
#
client_id = ‘xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx’
client_secret = ‘xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx’

client = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=client)

#
# Generate an authentication token (valid for 24 hours)
#
token = oauth.fetch_token(
    token_url='https://tubularlabs.com/api/v3/oauth.token',
    client_id=client_id,
    client_secret=client_secret)

#
# Test that the authentication token is valid (this step is optional)
#
response = oauth.post("https://tubularlabs.com/api/v3/auth.test")
response_json = json.loads(response.text)
if response.status_code != 200 or not response_json['ok']:
    raise Exception, 'auth token is no longer valid!'

#
# Query for a list of track dashboards
#
response = oauth.post("https://tubularlabs.com/api/v3/dashboard.list")
response_json = json.loads(response.text)
if response.status_code != 200 or not response_json['ok']:
    raise Exception, 'dashboard list request failed!'

#
# Gather metrics and trends for each dashboard, data defaults to a timespan from 90 days
# ago to today
#
dashboards = response_json['dashboards']
metrics = {}
trends = {}

for dashboard in dashboards:
    dashboard_id = dashboard['id']

    #
    # Query for dashboard metrics
    #
    post_data = {
        'dashboard_id': dashboard_id,
        #'date_start': 'xxxx-xx-xx', #optional
        #'date_end': 'xxxx-xx-xx', #optional
    }

    response = oauth.post("https://tubularlabs.com/api/v3/dashboard.metrics", data=post_data)
    response_json = json.loads(response.text)
    if response.status_code != 200 or not response_json['ok']:
        raise Exception, 'dashboard metrics request failed for {}!'.format(dashboard_id)
    metrics[dashboard_id] = response_json

    #
    # Query for dashboard trends
    #
    post_data = {
        'dashboard_id': dashboard_id,
        #'date_start': 'xxxx-xx-xx', #optional
        #'date_end': 'xxxx-xx-xx', #optional
    }

    response = oauth.post("https://tubularlabs.com/api/v3/dashboard.trends", data=post_data)
    response_json = json.loads(response.text)
    if response.status_code != 200 or not response_json['ok']:
        raise Exception, 'dashboard trends request failed for {}!'.format(dashboard_id)
    metrics[dashboard_id] = response_json

Rscript client

The following code was written using R version 3.3.3

#!/usr/bin/env Rscript

# If you don't have these libraries, just install.packages("name")
library(httr)
library(lubridate)
library(base64enc)

# YOUR SPECIFIC INFO
my_client_id <- "YOUR CLIENT ID FROM SETTINGS"
my_client_secret <- "YOUR CLIENT SECRET FROM SETTINGS"
my_hashed_secret <- base64encode(charToRaw(my_client_secret))

# Get token
get_token_url <- "https://tubularlabs.com/api/v3/oauth.token"
client_id_body <- paste("grant_type=client_credentials", paste("client_id", my_client_id, sep = "="), sep = "&")
auth <- paste("basic", my_hashed_secret, sep = " ")
content_type <- "application/x-www-form-urlencoded"
req_auth <- POST(get_token_url, body = client_id_body, add_headers(Authorization = auth, "Content-Type" = content_type), verbose())
token <- content(req_auth)$access_token
token_body <- paste("token=", token, sep = "")

# Test auth
auth_test_url <- "https://tubularlabs.com/api/v3/auth.test"
req_test <- POST(auth_test_url, body = token_body, add_headers("Content-Type" = content_type), verbose())
print(content(req_test))

# Get all the dashboards for that user
get_dash_url <- "https://tubularlabs.com/api/v3/dashboard.list"
req_dash <- POST(get_dash_url, body = token_body, add_headers("Content-Type" = content_type), verbose())
dashboards <- content(req_dash)$dashboards

# Dashboards list data frame
dash_list_df <- data.frame()
for (d in dashboards){
    row_c <- c(ID = d$id, Name = d$name)
    dash_list_df <- rbind(dash_list_df, row_c, stringsAsFactors = FALSE)
}
colnames(dash_list_df) <- c("ID", "Name")
dash_list_df <- transform(dash_list_df, ID = as.numeric(ID))
ids <- as.vector(dash_list_df[["ID"]])
print(dash_list_df)
print(ids)

# Metrics per dashboard
get_dash_metrics_url <- "https://tubularlabs.com/api/v3/dashboard.metrics"
today <- format(Sys.Date(), "%Y-%m-%d")
month_ago <- as.Date(Sys.Date()) %m+% months(-1)
metrics_body <- paste(paste("date_start", month_ago, sep = "="), paste("date_end", today, sep = "="), token_body, sep = "&")

# Metrics for one dashboard, for one month, into a dataframe
dash_df <- data.frame()
dash_id <- ids[1]
dash_metrics_body <- paste(paste("dashboard_id", dash_id, sep = "="), metrics_body, sep="&")
req_dash_metrics <- POST(get_dash_metrics_url, body = dash_metrics_body, add_headers("Content-Type" = content_type), verbose())
dash_metrics <- content(req_dash_metrics)
for (row in dash_metrics$metrics) {
    row_c <- c(ID = dash_id, Platform = row$platform, Engagements = row$engagements, Uploads = row$uploads, Views = row$views)
    dash_df <- rbind(dash_df, row_c, stringsAsFactors = FALSE)
}
print(dash_df)
colnames(dash_df) <- c("ID", "Platform", "Engagements", "Uploads", "Views")
dash_df <- transform(dash_df, Engagements = as.numeric(Engagements))
dash_df <- transform(dash_df, Uploads = as.numeric(Uploads))
dash_df <- transform(dash_df, Views = as.numeric(Views))
print(dash_df)

# Metrics for each dashboard, for one month, into a dataframe
all_dash_df <- data.frame()
for (dash_id in ids) {
    dash_metrics_body <- paste(paste("dashboard_id", dash_id, sep = "="), metrics_body, sep="&")
    req_dash_metrics <- POST(get_dash_metrics_url, body = dash_metrics_body, add_headers("Content-Type" = content_type), verbose())
    dash_metrics <- content(req_dash_metrics)
    print(dash_metrics$metrics)
    for (row in dash_metrics$metrics) {
        row_c <- c(ID = dash_id, Platform = row$platform, Engagements = row$engagements, Uploads = row$uploads, Views = row$views)
        all_dash_df <- rbind(all_dash_df, row_c, stringsAsFactors = FALSE)
    }
}
colnames(all_dash_df) <- c("ID", "Platform", "Engagements", "Uploads", "Views")
all_dash_df <- transform(all_dash_df, Engagements = as.numeric(Engagements))
all_dash_df <- transform(all_dash_df, Uploads = as.numeric(Uploads))
all_dash_df <- transform(all_dash_df, Views = as.numeric(Views))
print(all_dash_df)

# Trends per dashboard
get_dash_trends_url <- "https://tubularlabs.com/api/v3/dashboard.trends"
today <- format(Sys.Date(), "%Y-%m-%d")
month_ago <- as.Date(Sys.Date()) %m+% months(-1)
trends_body <- paste(paste("date_start", month_ago, sep = "="), paste("date_end", today, sep = "="), token_body, sep = "&")

# Trends for one dashboard, for one month, into a dataframe
trends_id <- ids[2]
dash_trends_body <- paste(paste("dashboard_id", trends_id, sep = "="), trends_body, sep="&")
req_dash_metrics <- POST(get_dash_trends_url, body = dash_trends_body, add_headers("Content-Type" = content_type), verbose())
trends <- content(req_dash_metrics)$trends
# Convert to dataframe
trends_df <- data.frame()
for (platform_trends in trends) {
    platform <- platform_trends$platform
    for (point in platform_trends$trends) {
        row_c <- c(ID = trends_id, Platform = platform, Day = point$day, Views = point$views, Engagements = point$engagements, Uploads = point$uploads)
        trends_df <- rbind(trends_df, row_c, stringsAsFactors = FALSE)
    }
}
colnames(trends_df) <- c("ID", "Platform", "Day", "Views", "Engagements", "Uploads")
trends_df <- transform(trends_df, Engagements = as.numeric(Engagements))
trends_df <- transform(trends_df, Uploads = as.numeric(Uploads))
trends_df <- transform(trends_df, Views = as.numeric(Views))
trends_df <- transform(trends_df, Day = as.Date(Day, "%Y-%m-%d"))
print(trends_df)

# Trends for all dashboards, for one month, into a dataframe
all_trends_df <- data.frame()
for (trends_id in ids) {
    dash_trends_body <- paste(paste("dashboard_id", trends_id, sep = "="), trends_body, sep="&")
    req_dash_metrics <- POST(get_dash_trends_url, body = dash_trends_body, add_headers("Content-Type" = content_type), verbose())
    trends <- content(req_dash_metrics)$trends
    # Convert to dataframe
    for (platform_trends in trends) {
        platform <- platform_trends$platform
        for (point in platform_trends$trends) {
            row_c <- c(ID = trends_id, Platform = platform, Day = point$day, Views = point$views, Engagements = point$engagements, Uploads = point$uploads)
            all_trends_df <- rbind(all_trends_df, row_c, stringsAsFactors = FALSE)
        }
    }
}
colnames(all_trends_df) <- c("ID", "Platform", "Day", "Views", "Engagements", "Uploads")
all_trends_df <- transform(all_trends_df, Engagements = as.numeric(Engagements))
all_trends_df <- transform(all_trends_df, Uploads = as.numeric(Uploads))
all_trends_df <- transform(all_trends_df, Views = as.numeric(Views))
all_trends_df <- transform(all_trends_df, Day = as.Date(Day, "%Y-%m-%d"))
print(all_trends_df)

Curl command using POST param

The following represents a sample curl command for an oauth.token request using 2 legged OAuth, whereby the client id is passed as a POST parameter and the client secret is passed in the Authorization header. Note that the client secret must be base64 encoded.

curl https://tubularlabs.com/api/v3/oauth.token \
--request POST \
--data "grant_type=client_credentials&client_id=CLIENT_ID" \
--header "Authorization: basic BASE64_ENCODED_CLIENT_SECRET"

Curl command using Authorization header

The following represents another sample curl command for an oauth.token request using 2 legged OAuth. In this example, both the client id and the client secret are passed within the authorization header. Note that the client id and secret must be of the format “CLIENT_ID:CLIENT_SECRET” (make special note of the colon separator) and must be base64 encoded.

--request POST \
--data "grant_type=client_credentials" \
--header "Authorization: basic BASE64_ENCODED_CLIENT_ID_PLUS_SECRET"