API Getting Started

Summary

This page shows a sample programs to get you started using the Wirewheel REST API. The examples include cURL (Client URL), NodeJS, and Python.

The basic procedure is:

  1. Get oAuth2 Bearer Token
  2. Post Consent to Asynchronous Endpoint
  3. Go back later and GET Consent results

πŸ‘

Which ID to Use

When you post a consent you supply either a verifiedId or anonymousID.

The system then will assign a subjectId to the consent.

πŸ‘

Important Node on Async Model

When you post a consent to the endpoint it submits it asynchronously. The API returns just a 2xx HTTP status code and no response body. So the procedure is to POST the consent then come back later and GET the results to verify that it worked.

These examples create a consent. For a definition of consent, refer to Introduction to UPCP.

What You'll Learn

In this document, you'll learn how to:

πŸ“˜

Definition

In this document, API means the REST API. If you want to use the Javascript SDK, refer to the SDK Getting Started for instructions.

πŸ“˜

Note on Environment Variables

The sample code here uses environment variables. They are accessed using β€œ$variable” using /bin/bash on Mac. If you use Windows, Ubuntu, or the Mac zsh then you might have to put different escape characters to make those work. This is because of small differences in the implementation of bash shell.

πŸ“˜

Error 401

API authentication uses oAuth2. If you get error 401 then you are probably missing a scope. Scope means authorization. See instructions here. For example:

const scopes = ['consent-insert-api consent-get-api subject-profile-manage']

Getting API Credentials

You get API credentials from the Channel. Look here for instructions.

πŸ“˜

Background Reading on oAuth2

If you are not familiar with how to use oAuth2 security with APIs, refer to oAuth2 Explained.

Configure Base64 Encoded Basic Authentication Header

  1. You will need to base64 encode clientId + β€œ:” clientSecret. Notice the colon (:) in the middle. Note: You must concatenate the strings before you base64 encode them.

  2. From the Wirewheel Dashboard, copy the clientId and clientSecret:

clientId="xxxxxxxx"
clientSecret="yyyyyyyyyy"
  1. Concatenate the two strings with a colon (:) in the middle and base64 encode that. From the command line, you can execute this: (If you are using Windows you can find many websites that will do this online.)

export base64IdSecret=echo -n "$clientId:$clientSecret" | base64

  1. Save that and the issuerURL (which is the URL of the identity provider) in your environment variables. This is to avoid hard-coding those into the programs shown below.

export issuerURL="https://wirewheelio.okta.com/oauth2/xxxxxx/v1/token"

Request a Scope

You need to pick a scope. This basically is a request to use a particular API or set of APIs. For more information, look here.

Get a Bearer Token

Run this curl and then save the results in the environment variable bearerToken. Note: This is a x-www-form-urlencoded post with URL parameters and not JSON.

curl -X POST "$issuerURL?grant_type=client_credentials&scope=consent-insert-api%20consent-get-api" \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --header "Authorization: Basic $base64IdSecret"

The bearer token is in the access_token.

{"token_type":"Bearer","expires_in":3600,"access_token":"xxxxxxx","scope":"consent-get-api consent-insert-api"}

You can use this bearer token for 3600 seconds (60 minutes).

Curl Example

Create a Consent

First, create a consent. You can use the sample data shown below. Note the http headers.

curl  -X POST -k -H "Authorization: Bearer $bearerToken" -H 'Content-Type: application/json' -i 'https://api.dev.cmp.wirewheel.io/consents' --data '{
  "subject": {
    "verifiedId": "walker-1234"
  },
  "actions": [
    { "target": "camera", "vendor": "cam-device", "action": "ACCEPT" },
    { "target": "location", "vendor": "location-device", "action": "REJECT" },
    { "target": "proximity sensors", "vendor": "android", "action": "REJECT" },
    { "target": "send stats", "vendor": "wirewheel", "action": "ACCEPT" }
  ],
  "tags": ["a tag"],
  "attributes": {
    "os": "linux"
  }
}'

Wirewheel responds with an HTTP status code and dumps the HTTP headers:

HTTP/2 201 
content-length: 0
date: Wed, 26 Oct 2022 11:41:56 GMT
vary: Origin
access-control-allow-origin: *
x-cache: Miss from cloudfront
via: 1.1 6040df3b952854c04b0e5d5c11fdf274.cloudfront.net (CloudFront)
x-amz-cf-pop: ATH50-C1
x-amz-cf-id: RSzlzQ1tQr5u-dQ_NSbaKJCQeR2OxwbjIMNS3CM6NW58mw8-DhevgA==

Get Unified Consent

Now list what you just created.

curl -X GET -k -H "Authorization: Bearer $bearerToken" \
-H 'Content-Type: application/json' \
-i 'https://api.demo.upcp.wirewheel.io/v2/consents/unified/2EAKL2MzXnOJx4gChqAODN3o38z'

Responds:

{
	"unifiedConsent": {
		"subjectId": "2GLYTX8DTvHI8IeV26lxyozKK13",
		"brandId": "2BvS6wql6A2WUE0mHCC7Gj1vzVo",
		"channelIds": ["2BvSJifBX2K9ZAWlAseypkQaWKf"],
		"region": "CY",
		"actions": [{
			"target": "promotion",
			"vendor": "bank",
			"action": "ACCEPT"
		}],
		"attributes": {
			"dob": "2002-08-23",
			"email": "[email protected]",
			"sex": "f",
			"ipaddr": "255.255.255.254"
		},
		"lastUpdateDate": "2022-10-19T08:48:58.741Z"
	},
	"conflicts": []
}

Check for Consent

curl -X GET -k -H "Authorization: Bearer $bearerToken" \
-H 'Content-Type: application/json' \
-i 'https://api.demo.upcp.wirewheel.io/v2/consents/check/2EAKL2MzXnOJx4gChqAODN3o38z'

Returns:

"vendor": "bank",

Python

Here is the same code in Python. You do not have to export the bearerToken, as the code gets that when it runs.

The flow is:

  1. Retrieve the issueURL (from the channel screen) and base64 encoded clientId:clientSecret (also from channel screen).

  2. Next, post to the identity provider to get a bearerToken.

  3. Then, post to /consents with the verifiedId (any string) as the ID of the consent. (Or you can use anonymousId.)

Note: Other than the structure, the values for actions, tags, and attributes can be any value in target, vendor, tags, and action keys shown below. In other words, actions, for example, can be any string.

Attributes are completely free-form. You can put any value there.

Create Consent

import requests
import simplejson as json
import os
import base64

encoded = base64.b64encode(os.environ['clientId'].encode('utf-8') + ":".encode('utf-8') + os.environ['clientSecret'].encode('utf-8')).decode('utf-8')


headers = {
   "Content-Type": "application/x-www-form-urlencoded",
   "Authorization": "Basic " + encoded
}

params = {
    "grant_type" : "client_credentials",
    "scope" : "consent-insert-api consent-get-api"
}

url = os.environ['issuerURL']

rsp = requests.post(url, params = params, headers=headers)

print("http status code", rsp.status_code)

try:
    print(rsp.json())
except:
    print("bearer token JSON exception caught ", rsp.text)

jsonStr = """{
              	  "subject": {
               	      "verifiedId": "water123"
                	},
       	 	   "actions": [{
                        "target": "promotion",
               	        "vendor": "bank",
                        "action": "ACCEPT"
                	}],
                    "attributes": {
                      "dob": "2002-08-23",
                      "email": "[email protected]",
                      "sex": "f",
                      "ipaddr": "255.255.255.254"
       		}
         }"""



headers = {
   "Content-Type": "application/json",
   "Authorization": "Bearer " + rsp.json()['access_token']
}



data=json.loads(jsonStr)

url='https://api.demo.upcp.wirewheel.io/v2/consents'

rsp = requests.post(url, json = data, headers=headers)

print("http status code", rsp.status_code)

try:
    print(rsp.json())
except:
    print("post JSON exception caught", rsp.text, " headers ", rsp.headers)

Responds:

http status code 201
post JSON exception caught   headers  {'Content-Length': '0', 'Connection': 'keep-alive', 'Date': 'Thu, 27 Oct 2022 09:49:52 GMT', 'vary': 'Origin', 'access-control-allow-origin': '*', 'X-Cache': 'Miss from cloudfront', 'Via': '1.1 22cca4e72d16c1882ac60c018e6acbbe.cloudfront.net (CloudFront)', 'X-Amz-Cf-Pop': 'TLV50-C2', 'X-Amz-Cf-Id': 'fy1mr3f5T4Ti_z1_4IAA1WDHYBbtxLThfSH-2-wDVKAVBI6Uxg7WNw=='}

Get Unified Consent

import requests
import simplejson as json
import os
import base64

encoded = base64.b64encode(os.environ['clientId'].encode('utf-8') + ":".encode('utf-8') + os.environ['clientSecret'].encode('utf-8')).decode('utf-8')


headers = {
   "Content-Type": "application/x-www-form-urlencoded",
   "Authorization": "Basic " + encoded
}

params = {
    "grant_type" : "client_credentials",
    "scope" : "consent-insert-api consent-get-api subject-profile-manage"
}


url = os.environ['issuerURL']

rsp = requests.post(url, params = params, headers=headers)

print("http status code", rsp.status_code)

try:
    print(rsp.json())
except:
    print("JSON exception caught ", rsp.text)



headers = {
   "Content-Type": "application/json",
   "Authorization": "Bearer " + rsp.json()['access_token']
}

url = 'https://api.demo.upcp.wirewheel.io/v2/consents/unified/sillyputty'

rsp = requests.get(url, headers=headers)

try:
    print(rsp.json())
except:
    print("JSON exception caught")

Responds:

{
	'unifiedConsent': {
		'subjectId': '2E1XyVfpLxoOXs8r4gFkaeRSGMn',
		'brandId': '2BvS6wql6A2WUE0mHCC7Gj1vzVo',
		'channelIds': ['2BvSJifBX2K9ZAWlAseypkQaWKf'],
		'region': 'CY',
		'compliance': {
			'privacyPolicy': {
				'version': 'string',
				'url': 'https://foo.com/privacy.html'
			},
			'gpc': 1
		},
		'actions': [{
			'target': 'promotion',
			'vendor': 'bank',
			'action': 'ACCEPT'
		}],
		'attributes': {
			'dob': '2002-08-23',
			'email': '[email protected]',
			'sex': 'f',
			'ipaddr': '8.8.8.8'
		},
		'lastUpdateDate': '2022-10-27T10:03:26.071Z'
	},
	'conflicts': []
}

Check for Consent

import requests
import simplejson as json
import os
import base64

encoded = base64.b64encode(os.environ['clientId'].encode('utf-8') + ":".encode('utf-8') + os.environ['clientSecret'].encode('utf-8')).decode('utf-8')


headers = {
   "Content-Type": "application/x-www-form-urlencoded",
   "Authorization": "Basic " + encoded
}

params = {
    "grant_type" : "client_credentials",
    "scope" : "consent-insert-api consent-get-api subject-profile-manage"
}


url = os.environ['issuerURL']

rsp = requests.post(url, params = params, headers=headers)

print("http status code", rsp.status_code)

try:
    print(rsp.json())
except:
    print("JSON exception caught ", rsp.text)



headers = {
   "Content-Type": "application/json",
   "Authorization": "Bearer " + rsp.json()['access_token']
}

url = 'https://api.demo.upcp.wirewheel.io/v2/consents/check/' + "2GLYTX8DTvHI8IeV26lxyozKK13"

rsp = requests.get(url, headers=headers)

try:
    print(rsp.json())
except:
    print("JSON exception caught")

Responds:

{'exists': True}

JavaScript

Here is the same code in NodeJS. Note: You do not have to export the bearerToken, as the code gets that when it runs. Also, the current time is used for the verifiedId in order to have a unique value for testing.

Create Consent

import { createRequire } from "module";
const require = createRequire(import.meta.url);

var querystring = require('querystring');
import fetch from 'node-fetch';

var base64IdSecret = btoa(process.env.clientId + ":" + process.env.clientSecret);

console.log("base64IdSecret=", base64IdSecret);

var getToken = async () => {
       return fetch(process.env.issuerURL,  {
       		method: 'POST',
       		headers: {
               		"Authorization": "Basic " + base64IdSecret,
               		'Content-Type': 'application/x-www-form-urlencoded'
               },
       		body: new URLSearchParams({
        		'grant_type': 'client_credentials',
        		'scope': 'consent-insert-api consent-get-api'
    		})
       	      })
        .then(response => response.json())
      	.then(data => data.access_token);
      }


var getConsent = async(token, subjectId) => {

        console.log("token ", token);

	return fetch('https://api.demo.upcp.wirewheel.io/v2/consents/unified/' + subjectId, {
       		method: 'GET',
       		headers: {
                   "Authorization": "Bearer " + token,
                   'Content-Type': 'application/json'
                   }
       		}).then(response => response.json())
                  .then(data => console.log(JSON.stringify(data)))

}

getToken()
 .then(token => getConsent(token, "sillyputty"))

Responds:

{
	"unifiedConsent": {
		"subjectId": "2E1XyVfpLxoOXs8r4gFkaeRSGMn",
		"brandId": "2BvS6wql6A2WUE0mHCC7Gj1vzVo",
		"channelIds": ["2BvSJifBX2K9ZAWlAseypkQaWKf"],
		"region": "CY",
		"compliance": {
			"privacyPolicy": {
				"version": "string",
				"url": "https://foo.com/privacy.html"
			},
			"gpc": 1
		},
		"actions": [{
			"target": "promotion",
			"vendor": "bank",
			"action": "ACCEPT"
		}],
		"attributes": {
			"dob": "2002-08-23",
			"email": "[email protected]",
			"sex": "f",
			"ipaddr": "8.8.8.8"
		},
		"lastUpdateDate": "2022-10-27T10:03:26.071Z"
	},
	"conflicts": []
}

Check for Consent

import { createRequire } from "module";
const require = createRequire(import.meta.url);

var querystring = require('querystring');
import fetch from 'node-fetch';

var base64IdSecret = btoa(process.env.clientId + ":" + process.env.clientSecret);

console.log("base64IdSecret=", base64IdSecret);

var getToken = async () => {
       return fetch(process.env.issuerURL,  {
       		method: 'POST',
       		headers: {
               		"Authorization": "Basic " + base64IdSecret,
               		'Content-Type': 'application/x-www-form-urlencoded'
               },
       		body: new URLSearchParams({
        		'grant_type': 'client_credentials',
        		'scope': 'consent-insert-api consent-get-api'
    		})
       	      })
        .then(response => response.json())
      	.then(data => data.access_token);
      }


var getConsent = async(token, subjectId) => {

        console.log("token ", token);

	return fetch('https://api.demo.upcp.wirewheel.io/v2/consents/check/' + subjectId, {
       		method: 'GET',
       		headers: {
                   "Authorization": "Bearer " + token,
                   'Content-Type': 'application/json'
                   }
       		}).then(response => response.json())
                  .then(data => console.log(JSON.stringify(data)))

}

getToken()
 .then(token => getConsent(token, "sillyputty"))

Responds:

{"exists":true}

Didn’t find what you were looking for?

Email our team: [email protected]?subject=UPCP