Quick start
Before we begin
This guide assumes you are working with XPKit in the EMEA region. If you are using one of the other XPKit regions update the referenced XPKit Portal URL and API endpoints as appropriate.
Once you have signed up for an XPKit account, follow this guide to get started. By the end of this tutorial you will have created your first event and touch point and registered a visitor for the event.
Resources
Everything you create and manage in XPKit is known as a resource. For example your visitors are profile resources and the actions they perform are activity resources. All resources are usually grouped together under an experience resource (your event). This helps you track and analyse behaviour across events.
With this in mind, let's create an event and register a visitor...
Calling XPKit services
Each resource is managed by a RESTful API accepting and returning JSON payloads. These API endpoints require an OAuth 2 authorization header. The authentication section explains in detail the different authentication flows and scopes. For now let's create an OAuth 2 application in XPKit Portal which we will use to generate the required access token.
- Login to XPKit Portal (external link)
- Navigate to the Authentication > Applications section
- Click on the "Create a new application" button
- Call the application "Quick start" and tick all the boxes for activity, profile and resource. Click save
- Take a note of the client_id and client_secret values shown
Authorization
Obtaining an access token
Call the token endpoint in the Auth API with the client ID and client secret that were generated above.
Example requests:
import requests
endpoint = 'https://auth.emea.xpkit.net/api/token/'
payload = {
'grant_type': 'client_credentials',
'client_id': 'YOUR_CLIENT_ID',
'client_secret': 'YOUR_CLIENT_SECRET'}
req = requests.post(url=endpoint, data=payload)
result = req.json()
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
body: data
});
return response.json();
}
const formData = new FormData();
formData.append('grant_type', 'client_credentials');
formData.append('client_id', 'YOUR_CLIENT_ID');
formData.append('client_secret', 'YOUR_CLIENT_SECRET');
postData('https://auth.emea.xpkit.net/api/token/', formData).then((data) => {
const result = data;
});
curl -v -L -X POST \
-d 'grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET' \
https://auth.emea.xpkit.net/api/token/
If everything worked correctly you will receive back a status code of 200 and a JSON payload:
{
"token_type": "Bearer",
"scope": "activities:create activities:delete activities:read activities:update profiles:create profiles:delete profiles:read profiles:update resources:create resources:delete resources:read resources:update",
"expires_in": 36000,
"access_token": "OVUsH2nFXTZIlOgCZnhX6SrGjmJbZI"
}
You'll notice the scopes match the ones we chose above in XPKit Portal.
Experiences and Objects
Create an event
Now we have a valid access token, we can call the APIs required to create an event and register a visitor.
An XPKit resource is a standard JSON object, you can add any fields you require. Let's define our experience like so:
{
"name": "Game Developers Conference 2024",
"internal_name": "GDC24",
"start_date": "2024-03-18",
"end_date": "2024-03-22",
"location": {
"venue": "Moscone Center",
"street": "747 Howard Street",
"city": "San Francisco",
"state": "California",
"zip": 94103,
"country": "USA"
},
"ticketed": true
}
Now let's call the create experience endpoint:
import requests
endpoint = 'https://resources.emea.xpkit.net/api/experience/'
headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'}
resource = {
'name': 'Game Developers Conference 2024',
'internal_name': 'GDC24',
'start_date': '2024-03-18',
'end_date': '2024-03-22',
'location': {
'venue': 'Moscone Center',
'street': '747 Howard Street',
'city': 'San Francisco',
'state': 'California',
'zip': 94103,
'country': 'USA'
},
'ticketed': true}
req = requests.post(headers=headers, url=endpoint, json=resource)
result = req.json()
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(data),
});
return response.json();
}
const jsonData = {
'name': 'Game Developers Conference 2024',
'internal_name': 'GDC24',
'start_date': '2024-03-18',
'end_date': '2024-03-22',
'location': {
'venue': 'Moscone Center',
'street': '747 Howard Street',
'city': 'San Francisco',
'state': 'California',
'zip': 94103,
'country': 'USA'
},
'ticketed': true
};
postData('https://resources.emea.xpkit.net/api/experience/', jsonData).then((data) => {
const result = data;
});
You should receive back a successful response:
{
"resource": {
"created": "2023-07-03T05:29:54Z",
"end_date": "2024-03-22",
"experience_id": "game-developers-conference-2024",
"internal_name": "GDC24",
"last_modified": "2023-07-03T05:29:54Z",
"location": {
"city": "San Francisco",
"country": "USA",
"state": "California",
"street": "747 Howard Street",
"venue": "Moscone Center",
"zip": 94103
},
"name": "Game Developers Conference 2024",
"start_date": "2024-03-18",
"ticketed": true
},
"resource_id": "aa8f44c8-8a27-4a6e-9e32-23d2480db106",
"resource_url": "/api/experience/aa8f44c8-8a27-4a6e-9e32-23d2480db106/"
}
XPKit generated a slugified experience_id from the name field. We will use this in subsequent API requests.
Timestamps
created and last_modified timestamps are generated automatically across all XPKit resources. Any values provided for these fields will be ignored.
Create a touchpoint
Experiences usually have touchpoints your visitors can interact with, either physical or virtual in nature. In XPKit these touchpoints are known as object resources. We will create one now where visitors can go to register for our event. It will be a registration website and it will look like:
{
"name": "Registration website",
"description": "Website where visitors register prior to arriving"
}
Now let's call the create object endpoint:
import requests
endpoint = 'https://resources.emea.xpkit.net/api/object/'
headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'}
resource = {
'name': 'Registration website',
'description': 'Website where visitors register prior to arriving'}
req = requests.post(headers=headers, url=endpoint, json=resource)
result = req.json()
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(data),
});
return response.json();
}
const jsonData = {
'name': 'Registration website',
'description': 'Website where visitors register prior to arriving'
};
postData('https://resources.emea.xpkit.net/api/object/', jsonData).then((data) => {
const result = data;
});
You should receive back a successful response:
{
"resource": {
"created": "2023-07-04T01:26:44Z",
"description": "Website where visitors register prior to arriving",
"last_modified": "2023-07-04T01:26:44Z",
"name": "Registration website",
"object_id": "registration-website"
},
"resource_id": "1a00cd4f-edf8-4ba1-a476-e3131607a663",
"resource_url": "/api/object/1a00cd4f-edf8-4ba1-a476-e3131607a663/"
}
XPKit generated a slugified object_id from the name field. We will use this in subsequent API requests.
Profiles and Activities
Create a visitor
Next up we will create a visitor (profile resource) and register them for the event.
Unique constraints
Profiles have a number of fields that must be unique: emails (email), QR codes (qr_code) and RFID codes (rfid). These fields are optional but if provided need to be arrays of strings. The values stored in these arrays must be unique, for example an identical RFID cannot belong to more than one profile.
Let's define our profile like so...:
{
"first_name": "Hideo",
"last_name": "Kojima",
"email": ["hideo.kojima@kojimaproductions.jp"],
"speaker": true,
"guest": false
}
...and call the create profile endpoint:
import requests
endpoint = 'https://profiles.emea.xpkit.net/api/profile/'
headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'}
resource = {
'first_name': 'Hideo',
'last_name': 'Kojima',
'email': ['hideo.kojima@kojimaproductions.jp'],
'speaker': true,
'guest': false}
req = requests.post(headers=headers, url=endpoint, json=resource)
result = req.json()
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(data),
});
return response.json();
}
const jsonData = {
'first_name': 'Hideo',
'last_name': 'Kojima',
'email': ['hideo.kojima@kojimaproductions.jp'],
'speaker': true,
'guest': false
};
postData('https://profiles.emea.xpkit.net/api/profile/', jsonData).then((data) => {
const result = data;
});
The response will contain the new profile:
{
"resource": {
"created": "2023-07-04T00:16:23Z",
"email": [
"hideo.kojima@kojimaproductions.jp"
],
"first_name": "Hideo",
"guest": false,
"last_modified": "2023-07-04T00:16:23Z",
"last_name": "Kojima",
"qr_code": [],
"rfid": [],
"speaker": true
},
"resource_id": "c48ea5a2-1f6e-4772-a23f-c4bc09732b47",
"resource_url": "/api/profile/c48ea5a2-1f6e-4772-a23f-c4bc09732b47/"
}
As no values for qr_code or rfid were provided, empty arrays were created.
Register the visitor for the event
We will now register the profile for the event by creating a registration activity.
Activity requirements
- All activities must be associated to an experience via an experience_id field. We can use the one we created earlier (game-developers-conference-2024).
- All activities must be owned by a profile via an owner_id field. We can use the one we created in the previous step (c48ea5a2-1f6e-4772-a23f-c4bc09732b47).
- The type of activity needs to be provided via an activity_type field. We will use "registration".
Referencing other resources
Throughout XPKit you can reference other resources by using their resource_id (see example API responses above containing resource IDs). There are a couple of exceptions to this rule, namely when referencing experience and object resources. As you'll see in the example below, you must use the experience resource's experience_id (and object resource's object_id) field rather than using the resource_id. As we saw above these fields are slugified versions of the experience and object names, which were automatically generated when the resources were created.
Here is our registration activity:
{
"experience_id": "game-developers-conference-2024",
"owner_id": "c48ea5a2-1f6e-4772-a23f-c4bc09732b47",
"activity_type": "registration",
"payload": {
"object_id": "registration-website",
"number_of_tickets": 5
}
}
This specifies that:
- It is a registration activity for the Game Developers Conference 2024
- It was generated by the registration website on behalf of Hideo Kojima
XPKit convention recommends that object and other associated data should sit under a payload field. This is optional.
Finally let's call the XPKit create activity endpoint:
import requests
endpoint = 'https://activities.emea.xpkit.net/api/activity/'
headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'}
resource = {
'experience_id': 'game-developers-conference-2024',
'owner_id': 'c48ea5a2-1f6e-4772-a23f-c4bc09732b47',
'activity_type': 'registration',
'payload': {
'object_id': 'registration-website',
'number_of_tickets': 5
}}
req = requests.post(headers=headers, url=endpoint, json=resource)
result = req.json()
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(data),
});
return response.json();
}
const jsonData = {
'experience_id': 'game-developers-conference-2024',
'owner_id': 'c48ea5a2-1f6e-4772-a23f-c4bc09732b47',
'activity_type': 'registration',
'payload': {
'object_id': 'registration-website',
'number_of_tickets': 5
}
};
postData('https://activities.emea.xpkit.net/api/profile/', jsonData).then((data) => {
const result = data;
});
The response will contain the new activity:
{
"resource": {
"activity_type": "registration",
"created": "2023-07-04T01:49:21Z",
"experience_id": "game-developers-conference-2024",
"last_modified": "2023-07-04T01:49:21Z",
"owner_id": "c48ea5a2-1f6e-4772-a23f-c4bc09732b47",
"payload": {
"number_of_tickets": 5,
"object_id": "registration-website"
}
},
"resource_id": "0d2ebcd1-a31d-463e-a904-3d82b54f00d9",
"resource_url": "/api/activity/0d2ebcd1-a31d-463e-a904-3d82b54f00d9/"
}