Self-Classification Categories API
If you are a DMP client, you can implement the Oracle Data Cloud self-classification category and rule web services to independently classify the page and user attributes ingested from your site or classify your onboarded from your offline data. Classification is the process in which your data that has been transferred into the Oracle Data Cloud platform is collected and mapped to categories in your private taxonomy. Implementing the category and rule APIs enables you to create hierarchical categories within your taxonomy and write rules that define when a user gets added to a category.
With the self-classification category API, you can add new first-party categories to the Self-Classification tree in your private taxonomy, and then use the rule web service to create classification rules that map your user data to your categories. The categories you add to your taxonomy via the self-classification category API are private and owned exclusively by your DMP. Your categories will appear in the Oracle Data Cloud platform when you log in to your seat, and you can also get them using the categories API.
Important: The Self-Classification Categories API will be deprecated in the near future and replaced with the Categories API. You should begin migrating to the Categories API to take advantage of its advanced features for creating and managing categories in your taxonomy. These new features include the ability to create categories anywhere in your taxonomy, edit categories created by the Oracle Data Cloud Services Team, and view the reach of your categories.
Note: Users no longer create campaigns in the Oracle Data Cloud platform UI. The campaign workflow is now part of the audience workflow. The platform still uses campaigns to manage audience data delivery however. They are created automatically when a UI user delivers an audience. In the APIs, you create and use campaigns as before.
In this topic
Explore the API
The embedded I/O doc below enables you to explore the API. The I/O doc explains the parameters for each method and provides templates for your calls. You cannot make live API calls from the tool, however.
Open the link below in a new tab to see the I/O doc in a three-pane format.
selfclassificationscategories.docs.apiary.io/
For help with this API, contact My Oracle Support (MOS).
Service URI
The URI for the Categories API is:
services.bluekai.com/Services/WS/classificationCategories
Bulk import
To create and configure multiple categories at the same time using the new bulk import feature:
- In the query string of your call to the self-classification category API, include the category ID of the parent category under which categories are to be created or updated.
serviceUrl = 'https://servcies.bluekai.com/Services/WS/classificationCategories/280096'
- In the
headers
field, set theContent-Type
tomultipart/form-data
and specify an encapsulationboundary
parameter.headers = {"Content-Type": "multipart/form-data; boundary=a8d84ae2e7db4676843c7df172b68bfc","Accept": "application/json","User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0"}
- In the POST/PUT body, enter the opening encapsulation
boundary
. - Set the
Content-Disposition
toform-data
, and include aname
parameter that is set tocategoryFile
, and an optionalfilename
parameter. - Set the
Content-Type
totext/tab-separated-values
. - Enter tab-separated values for the category to be created or updated. You must still insert fields for any values that you do not specify.
- Enter the closing encapsulation
boundary
.
The following example demonstrates the body of a bulk import POST or PUT request. It creates one category, and then creates a child category under the first category:
'''--a8d84ae2e7db4676843c7df172b68bfcContent-Disposition: form-data; name="categoryFile"; filename="self-classification-categories.tsv"Content-Type: text/tab-separated-valuesabc123 newCategory1 a new category true false false xyz234 abc123 newChildCategory a child category false true false--a8d84ae2e7db4676843c7df172b68bfc--'''
The following table lists the values for the category to be created or updated:
Column | Field | Data type | Required? | Description |
---|---|---|---|---|
1 | id
|
string | required | Either the permanent ID of an existing category in your self-classification tree or a temporary ID that you provide for a new category defined in this file. |
2 | parent_key
|
int | optional | The parent ID of this category. This may either be an ID of an existing category in your self-classification tree, or a temporary ID for a new category defined in this file. If you enter an ID, this category will be listed under the specified parent category. If you leave this blank, the category is added to the category ID specified in the service URI. |
3 | name
|
string | required | A unique, concise name for the category. The category will be listed by this name in your taxonomy. The name may be a maximum of 255 characters. |
4 | description
|
string | required | A verbose summary of the type of users included in with this category. The description may be a maximum of 255 characters. |
5 | analytics_excluded
|
boolean | optional | Whether the category is excluded from audience analytics reports. The default value is false. |
6 | navigation_only
|
boolean | optional | Whether the category functions exclusively as a parent node that cannot be selected. The default value is false. |
7 | mutex_children
|
boolean | optional | Whether child categories under this category are mutually exclusive (only one may be selected). The default value is false. |
8 | notes
|
string | optional | Any notes to be associated with the category |
9 | rule_ids
|
list | optional | A colon-separated list of rule IDs used to map user attributes (phints) into this category (for example, 100:101:102). |
Bulk import demo
The sample bk_bulk_cat_import.py Python code demonstrates how to do a bulk category import using the Categories API. To run this script, you must have the following:
- Python 2.7+
- Requests library 1.2.3 (or later)
You can use PIP (a Python Package Installation tool) to help install the requests library. To download and install PIP, install the requests library, and then delete the PIP installation file, enter the following commands in your console:
curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
sudo python get-pip.py
sudo pip install requests
rm get-pip.py
To run this script, you need to create a TSV file named self-classification-categories.tsv (download template) that contains the categories you want to edit or create, and provide the following parameters:
url
: The URL of the production environment (services.bluekai.com)verbosity
: Enter a series of four verbose options for printing information.bkuid
: Your web service user keybksecretkey
: Your web service private key
The following example demonstrates the required syntax for calling this script:
classificationCategory.py --url https://services.bluekai.com -v -v -v -v --bkuid WebServiceUserKey --bksecretkey WebServicePrivateKey
#! /usr/bin/env python -B
# -*- coding: utf-8 -*-
import sys, requests, json, argparse, unittest, hmac, base64, urllib, urlparse, hashlib
def cli_options():
parser = argparse.ArgumentParser(description='Demo for REST API')
parser.add_argument('-u','--url', default='https://localhost:8080/', help='Web service base URL')
parser.add_argument('-i','--bkuid', default='', help='BlueKai UID')
parser.add_argument('-k','--bksecretkey', default='', help='BlueKai Secret key')
parser.add_argument('-v','--verbose', default=0, action='count', help='Prints additional information')
return parser.parse_args()
args = cli_options()
URL = args.url.strip()
BKUID = args.bkuid
BKSECRETKEY = args.bksecretkey
VERBOSITY = args.verbose
USER_AGENT = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0'}
JSON_HEADERS = {'Content-Type': 'application/json', 'Accept':'application/json'}
COMMON_HEADERS = dict(USER_AGENT.items() + JSON_HEADERS.items())
class ClassificationCategory():
res = False
def info(self, message, verbosityLevel = 1):
if VERBOSITY >= verbosityLevel:
if not isinstance(message, basestring):
print json.dumps(message, indent=4)
else:
print message
def prepare_headers(self, headers = None):
if headers is None:
return COMMON_HEADERS.copy()
else:
return dict(COMMON_HEADERS.items() + headers.items())
def parse_query_params(self, query):
parameterList = query.split('&')
params = {}
if len(parameterList) > 0:
for entry in parameterList:
kvPair = entry.split('=')
params[kvPair[0]] = kvPair[1] if len(kvPair) > 1 else '';
return params
def prepare_request(self, endpoint, method = 'GET', params = None, data = None, headers = None, files = None, sign=True):
if files is not None:
headers.pop('Content-Type', None)
req = requests.Request(method, URL + endpoint, data = data, headers = headers, files = files)
prepared = req.prepare()
if sign:
if params is None:
params = {}
parsedUrl = urlparse.urlparse(URL)
parsedEndpoint = urlparse.urlparse(endpoint)
servletPath = "" if parsedEndpoint.path.strip().startswith("/") else "Services/WS/"
urlPath = parsedUrl.path.strip('/')
if urlPath:
urlPath = urlPath + '/'
fullPath = '/'+ urlPath + servletPath + parsedEndpoint.path.strip('/')
stringToSign = method + fullPath
params = dict(params.items() + self.parse_query_params(parsedUrl.query).items() + self.parse_query_params(parsedEndpoint.query).items())
queryParameterStr = '';
for key in params.keys():
if len(key) > 0:
if isinstance(params[key], list):
for listItem in params[key]:
value = urllib.quote(str(listItem))
stringToSign += value
queryParameterStr += urllib.quote(key) + '=' + value + '&'
else:
value = urllib.quote(str(params[key]))
stringToSign += value
queryParameterStr += urllib.quote(key) + '=' + value + '&'
if prepared.body is not None:
stringToSign += prepared.body
h = hmac.new(BKSECRETKEY, stringToSign.strip(), hashlib.sha256)
s = base64.standard_b64encode(h.digest())
signature = urllib.quote_plus(s)
finalURL = parsedUrl.scheme + '://' + parsedUrl.netloc + fullPath + '?' + queryParameterStr + 'bkuid=' + BKUID + '&bksig=' + signature
else:
finalURL = URL + endpoint
self.info('Sending %s request to: %s' %(method, finalURL))
prepared.url = finalURL
if VERBOSITY >=4:
print "Request object:"
for key, value in prepared.headers.iteritems():
print "%s: %s" % (key, value)
if prepared.body is not None and len(prepared.body)>0:
print ""
print prepared.body
return prepared
def post(self, endpoint, payload = None, params = None, headers = None, files = None):
if payload is not None:
data = payload if isinstance(payload, basestring) else json.dumps(payload)
else:
data = None
self.res = requests.Session().send(self.prepare_request(endpoint, method = 'POST', params = params, data = data, files = files, headers = self.prepare_headers(headers)), verify = False)
return self
def test_bulk_self_class_create(self):
files = {'categoryFile': open('self-classification-categories.tsv', 'rb')}
created_categories = self.post('classificationCategories', files = files, params={}).res.json()
self.info(created_categories, 2)
instance=ClassificationCategory()
instance.test_bulk_self_class_create()
Related API calls
Here are the API calls you will typically make before you use the Categories API:
Before Categories API | Use case |
---|---|
Containers API | The use case for the containers API depends on which data ingest method you are using to transfer your data into the Oracle Data Cloud platform (online ingest, offline onboard, user data API, or mobile ingest):
|
Here are the API calls you will typically make after you use the Categories API:
Post Categories API | Use Case |
---|---|
Audiences API | Create a target audience that includes your self-classified first-party categories. |
Self-Classification Rules API | Map the user data extracted from your site with your categories. |
Categories API | View your categories and their inventory. |
GET response summary
The Categories API GET request returns the categories in your private taxonomy. Here are the properties included for each category:
Field | Type | Description |
---|---|---|
analytics_excluded
|
boolean | Indicates whether the category is excluded from audience analytics reports |
created_at
|
date | A timestamp indicating when the category was initially created |
description
|
string | The user-specified summary associated with the category |
id
|
integer | The unique ID assigned to the category |
mutex_children
|
boolean | Indicates whether the number of the category's child nodes that can be added to a segment is limited to one. |
name
|
string | The user-specified name of the category |
navigation_only
|
boolean | Indicates whether the category functions exclusively as a parent node that cannot be selected |
notes
|
string | Any notes entered for this category |
parent_id
|
integer | The unique ID assigned to the parent node of the category |
rule_ids
|
list | A list of unique IDs of the classification rules that are assigned to this category |
total_count
|
integer | The total number of categories returned by the GET (list) request |
updated_at
|
date | A timestamp indicating when the category was last modified |
Response errors
If the POST request for creating categories fails, the POST response will use one of the following HTTP status codes:
Code | Error message | Description |
---|---|---|
400 | Bad Request | The body of the POST response will contain short description of the problems with the POST request. |
401 | Unauthorized | You need to authenticate the request. See authentication and authorization for more information. |
403 | Forbidden | You have reached the maximum number of categories (by default, the limit is 100). |
404 | Not Found | The specified parent category is either not in your self-classification tree or is not in your Partner seat |
The body of the POST response will contain a list of error codes for each of the input attributes causing the error. The following example demonstrates a POST response listing the errors for a failed request:
{
"errors": {
"parent_id": [
"CATEGORY_PARENT_NOT_SPECIFIED"
],
"description": [
"CATEGORY_DESCRIPTION_NOT_SPECIFIED"
],
"name": [
"CATEGORY_NAME_NOT_SPECIFIED"
]
},
"detail": "Bad request"
}