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:
- Get oAuth2 Bearer Token
- Post Consent to Asynchronous Endpoint
- 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:
- Get API Credentials
- Configure Base64 Encoded Basic Authentication Header
- Get a Bearer Token
- Create a Consent
- Get Consent Results
- Do this with curl, Python, or JavaScript
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
-
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. -
From the Wirewheel Dashboard, copy the clientId and clientSecret:
clientId="xxxxxxxx"
clientSecret="yyyyyyyyyy"
- 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
- 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:
-
Retrieve the
issueURL
(from the channel screen) and base64 encodedclientId:clientSecret
(also from channel screen). -
Next, post to the identity provider to get a
bearerToken
. -
Then, post to
/consents
with the verifiedId (any string) as the ID of the consent. (Or you can useanonymousId
.)
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
Updated 18 days ago