# Generate Access Token
Source: https://docs.wearepion.com/api-reference/authentication/generate-access-token
/api-reference/openapi-v1.json post /auth/token
Exchange a Client ID and Client Secret for a short-lived access token.
# Create a new Verification
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/create-a-new-verification
/api-reference/openapi-v1.json post /app/{appId}/whitelabel/verifications
Creates a new verification and returns a unique verification ID
# Create Email Attempt
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/create-email-attempt
/api-reference/openapi-v1.json post /app/{appId}/whitelabel/verifications/{verificationId}/email
Sends an OTP to the provided email address.
# Create Manual Attempt
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/create-manual-attempt
/api-reference/openapi-v1.json post /app/{appId}/whitelabel/verifications/{verificationId}/manual
Submits document files for manual verification.
# Create Portal Attempt
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/create-portal-attempt
/api-reference/openapi-v1.json post /app/{appId}/whitelabel/verifications/{verificationId}/portal
Creates a portal attempt for the verification and returns a portal start URL.
# Get Verification Details
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/get-verification-details
/api-reference/openapi-v1.json get /app/{appId}/whitelabel/verifications/{verificationId}
Retrieves the full verification data including user and institution information.
# Get Verification Status
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/get-verification-status
/api-reference/openapi-v1.json get /app/{appId}/whitelabel/verifications/{verificationId}/status
Returns a streamlined state for a specific verification.
# Institution Search
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/institution-search
/api-reference/openapi-v1.json post /app/{appId}/whitelabel/institutions/search
Searches for institutions matching the provided criteria.
# Set Institution
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/set-institution
/api-reference/openapi-v1.json patch /app/{appId}/whitelabel/verifications/{verificationId}
Updates a verification with the selected institution.
# Trigger Phone OTP
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/trigger-phone-otp
/api-reference/openapi-v1.json post /app/{appId}/whitelabel/verifications/{verificationId}/otp
Sends a one-time passcode to the provided phone number.
# Verification webhook
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/verification-webhook
/api-reference/openapi-v1.json webhook verificationWebhook
Pion sends this webhook for verification-related events. The webhook is signed using HMAC-SHA256 for security verification.
# Verify Email OTP
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/verify-email-otp
/api-reference/openapi-v1.json post /app/{appId}/whitelabel/verifications/{verificationId}/email/verify
Verifies the one-time passcode sent to the user's email.
# Verify Phone OTP
Source: https://docs.wearepion.com/api-reference/beans-id-whitelabel-api/verify-phone-otp
/api-reference/openapi-v1.json post /app/{appId}/whitelabel/verifications/{verificationId}/otp/verify
Verifies the one-time passcode sent to the user's phone.
# Overview
Source: https://docs.wearepion.com/documentation/check-i-d-status/overview
Our Code API lets you quickly check if a student’s account is active and valid.
To set this up, we recommend a "keys-only" login (client credentials). This is the simplest way to connect because it only gives your system permission to do one thing: verify if a student is who they say they are.
If you're looking to implement this service view the [SBiD Status API](/documentation/check-i-d-status/s-bi-d-status-api).
# SBiD Status API
Source: https://docs.wearepion.com/documentation/check-i-d-status/s-bi-d-status-api
SBiD Code API is a service that allows partners to check the status of a Student Beans iD.
## **Authentication**
For most use cases we suggest using the client\_credentials grant type to authenticate. When using the client\_credentials grant type you will only be allowed to request the id\_status scope which allows you to check the status of an SBiD Account.
For more information around how to initiate the client credential auth flow please consult the official OAuth2 documentation at [https://tools.ietf.org/html/rfc6749](https://tools.ietf.org/html/rfc6749) In order to get started you will need to obtain an application id and application secret. Please get in touch with [hello@studentbeans.com](mailto:hello@studentbeans.com) . We have a default TTL for our tokens of 2 hours (or 7200 seconds).
## **API Domain**
`https://accounts.studentbeans.com/`
## **Authorise Endpoint**
If you need to get a bearer token please use the below endpoint to request your token `/oauth/authorize`
## **Token Endpoint**
If you have a bearer token or if you are using client\_credentials, please use the below endpoint to get a token `/oauth/token`
## **Status endpoint**
All status requests have to be made to: `/api/v1/id/code/status.json`
**NOTE**
We currently only support the JSON mime type
## **Single SBiD code status**
### **\[GET] Request Parameters**
| **Parameter** | **Type** | **Description** |
| :------------ | :------- | :----------------------------------------------------- |
| access\_token | string | access token returned from the `/oauth/token` endpoint |
| id\_code | string | Student Beans SBiD code of the user |
**NOTE**
HTTP method is GET so these need to be send in the query string
### **Response**
```
{
"id_code": "ABCDEF1",
"account": true,
"verified": true
}
```
## **Batch SBiD codes status**
By using the batch method you can process a greater volume of SBiDs without constantly running into your rate limit. The max batch size is currently set at 1000.
### **\[POST] Request Parameters**
| **Parameter** | **Type** | **Description** |
| :------------ | :------- | :----------------------------------------------------- |
| access\_token | string | access token returned from the `/oauth/token` endpoint |
| id\_codes | string | Comma seperated list of Student Beans SBiD codes |
**NOTE**
HTTP method is POST so these need to be send in the form data
### **Response**
```
[
{ "id_code": "ABCDEF1", "account": true, "verified": true },
{ "id_code": "ABCDEF2", "account": true, "verified": false },
{ "id_code": "ABCDEF3", "account": false, "verified": false }
]
```
## **Example SBiD Codes:**
```
6C0475E (verified)
7E1729C (not verified)
```
## **Quota / Rate limiting**
Rate limits are currently set at 1 request per second however is negotiable on a case by case basis. If you would like to discuss increasing your rate limit please contact [hello@studentbeans.network](mailto:hello@studentbeans.network) with details of your use case.
## **Over limit Response**
Should you go over your agreed rate limit the API will not fulfil your request, but instead return HTTP status code 429 to indicate the over limit state. Should you get the over limit error please retry your request. For more information about the 429 error code please consult [http://tools.ietf.org/html/rfc6585#section-4](http://tools.ietf.org/html/rfc6585#section-4)
# Pion API
Source: https://docs.wearepion.com/documentation/connect-with-your-customers/pion-api
## Authentication at Pion
The Pion API provides an OAuth Client Credentials grant flow for accessing our services.
Client credentials can be self-served in the Pion Portal. This will create a new pairing of a clientId and clientSecret that is used to fetch an access token that ***must*** be passed into requests that require authentication.
Once you’ve got client credentials, you can send a request to the /auth/token endpoint. This is a post request with two body parameters.
**Client ID**
The Client ID is a unique identifier that is attached to your credentials by Pion. This should be considered sensitive data and stored securely.
**Client Secret**
The Client Secret is a confidential key that should be stored securely. This is used in conjunction with the Client ID to grant access to the Pion API.
This endpoint will return an access token that can then be used in subsequent requests that require authentication.
**Access Token**
A short-lived token that is used to verify that a client has permissions to access Pion data.
## Leads
The Lead Service captures rich, consented data directly from a brands verification integrations and marketplace, allowing you to enrich customer profiles and enhance your existing CRM. Leads are returned in batches of 1000. When a request has more than 1000 leads, an optional cursor attribute will be present in the response, which can be used to fetch the next batch of 1000 leads.
| **Consumer Group** | **Data Available** |
| :------------------------------------ | :-------------------------------------------------------------------------------------------------------------- |
| Student & Graduate | Email Address, First Name, Last Name, Country, Institution, Date of Birth, Gender, Expiry Date, Graduation Year |
| Key Worker & Social Assistance Groups | Email Address, First Name, Last Name, Country |
Once you have a valid access token, retrieved via the /auth endpoint. You can use this token to request lead data for your organisation. This is a GET request with two query parameters.
**From -** This is the date, formatted dd-mm-yyyy, that you would like the earliest lead data from.
**To -** This is the date, formatted dd-mm-yyyy, that you would like the latest lead data from.
**Cursor** **-** This is the optional reference object for the next item in the batch
This endpoint will return a list of the lead data between the two ranges.
# Technical Documentation
## \[POST] /auth/token
POST [https://api.wearepion.com/auth/token](https://api.wearepion.com/auth/token)
### Body Params
| **Field** | **Type** | **Description** |
| :--------------- | :------- | :------------------------------------------ |
| **clientId** | *string* | A unique ID provided by Pion |
| **clientSecret** | *string* | A confidential, unique key provided by Pion |
*Example Request Body*\*\*:\*\*
```text theme={null}
{
"clientId": "clientId",
"clientSecret": "clientSecret"
}
```
### Headers
| Content-Type | application/json |
| :----------- | :--------------- |
### Example Responses
#### 200 OK
```text theme={null}
{
"accessToken": "a1b2c3d4"
}
```
#### 400 Bad Request
```text theme={null}
{
"error": {
"title": "badRequest",
"detail": "Reason for the failed request will be detailed here"
}
}
```
Examples of the detail statement can be as follows:
* JSON body required
* clientId required
* clientSecret required
#### 401 Unauthorised
```text theme={null}
{
"error": {
"title": "unauthorised"
}
}
```
## \[GET] /leads
GET [https://api.wearepion.com/leads?from=13-01-2026\&to=13-02-2026](https://api.wearepion.com/leads?from=13-01-2026\&to=13-02-2026)
### Headers
| Content-Type | application/json |
| :------------ | :--------------- |
| Authorization | Bearer a1b2c3d4 |
### Query Parameters
| **from (required)** | dd-mm-yyyy | |
| :-------------------- | :-------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| to (required) | dd-mm-yyyy | |
| cursor **(optional)** | **\** | |
| fields **(optional)** | | comma separated string of desired response fields in snakecase,
eg. fields\[lead]=email,institution,grad\_year options: `lead_type` `sbid` `email` `first_name` `second_name` `gender` `date_of_birth` `country` `institution` `grad_year` `created_at` |
### Example Responses
#### `GET https://api.wearepion.com/leads?from=13-01-2026&to=13-02-2026`
A request for leads data that does not contain the `fields` query parameter will return all available leads data within range.
```text theme={null}
{
"leads": [
{
"lead_type": "online",
"sbid": "someUserId",
"email": "someuser@mail.com",
"first_name": "Nicholas",
"second_name": "Angel",
"gender": "M",
"date_of_birth": "2000-02-22",
"country": "UK",
"institution": "Canterbury University",
"grad_year": 2024,
"created_at": "2026-01-13T09:15:32Z"
}
],
cursor: "example_cursor"
}
```
#### 400 Bad Request
```text theme={null}
{
"error": {
"title": "badRequest",
"detail": "Reason for the failed request will be detailed here"
}
}
```
#### 401 Unauthorised
```text theme={null}
{
"error": {
"title": "unauthorised"
}
}
```
## \[GET] /leads - Request Selected Fields Only
Using the optional fields query parameter you may request leads data to return only selected fields.
Available fields:
* lead\_type
* sbid
* email
* first\_name
* second\_name
* gender
* date\_of\_birth
* country
* institution
* grad\_year
* created\_at
### Example Responses
#### 200 OK
`GET https://api.wearepion.com/leads?from=13-01-2026&to=13-02-2026&fields[lead]=email,institution,grad_year`
```text theme={null}
{
"leads": [
{
"email": "someuser@mail.com",
"institution": "Canterbury University",
"grad_year": 2024
}
],
cursor: "example_cursor"
}
```
#### 422 Bad Request
`GET https://api.wearepion.com/leads?from=13-01-2026&to=13-02-2026&fields[lead]=email,institution,potatoes`
```text theme={null}
{
"error": {
"title": "UnprocessableEntityError",
"detail": ["Invalid fields in fields[lead] parameter: nonexistentfield. Valid fields are: organisation_uid, created_at, lead_type, sbid, brand_uid, email, first_name, second_name, gender, date_of_birth, country, institution, grad_year, group, additional_info"]
}
}
```
#### 422 Bad Request
`GET https://api.wearepion.com/leads?from=13-01-2026&to=13-02-2026&fields[lead]=`
```text theme={null}
{
"error": {
"title": "UnprocessableEntityError",
"detail": ["fields[lead] parameter must not be empty"]
}
}
```
# Overview
Source: https://docs.wearepion.com/documentation/get-started/overview
Welcome to the Pion Developer documentation. This site is your comprehensive guide to integrating and utilising the suite of products offered by Pion. Whether you're building new applications or enhancing existing ones, our documentation provides all the necessary information to help you succeed. Growth is simple when you can verify, own and reach audiences in one place.
## **Getting Started**
To gain access to these products, please contact your Account Manager. They will provide you with the necessary API tokens and guide you through the initial setup process. Having the right credentials is essential for seamless integration and ensuring secure access to our APIs.
## **What You'll Find Here**
This documentation is designed to be a complete resource for developers. Here's what you can expect to find:
* **API Guides**: Detailed instructions on how to use our APIs, including endpoint references, request and response formats, and example code snippets.
* **Knowledge Bases**: Non-technical overviews of how to implement our products.
We strive to keep our documentation up-to-date and comprehensive. If you have any suggestions or need further assistance, don't hesitate to reach out to our support team.
Instantly verify customer identity.
Real-time tracking for every order.
See if a student is verified.
Instantly confirm your users' student status.
## The Growth Challenge: *What Marketers Really Want*
\
**Growing your business shouldn’t be complicated.**\
You want to win loyalty, run offers and convert customers, but most platforms keep the customer relationship and data. So you end up renting an audience and paying for clicks, but owning nothing.
Pion helps you run and promote offer programs where you have full ownership of your customer data and experience.
Growth is simple when you can verify, own and reach audiences in one place.
## The Unnecessary Compromise: *Own Your Growth*
**Growth can feel like constant trade-offs.**
Juggling providers. Choosing between ownership and reach. Losing control of your customer experience and your data. We think brands deserve more. That’s why Pion provides one simple solution— uniting offers, audiences and ownership together.
## We’re Your Growth Partner: *Why Brands Trust Us*
**We know how to grow confidently.**
We scaled Student Beans from a simple idea into a global brand, reaching millions of students around the world. Then, we expanded into more high-value audiences— like healthcare, military and teachers— with Beans iD.
We’re trusted by Samsung, Sephora, Gymshark, Dominos, H\&M and 3500+ global brands. Here’s why:
**Global Reach & Operations**
* 10 verified consumer groups across 100+ territories
* Local market insight and operational support from dedicated teams in the US, Europe, Asia and Australia
**Security & Stability**
* ISO 27001 certified security for full data protection and compliance
* A resilient platform built to perform during peak global shopping events and sustained high-traffic volumes— with 99.9%+ up time
**Acceleration**
* 100 million+ annual platform visits powered by AI search optimization to secure search rankings and high-intent discovery
* Strategic account management with full-funnel advertising solutions
**Proven Success**
* In 2025, drove over £1.25 billion in annual gross margin value for brand partners
* Best in class app experience with 50,000+5-star ratings on Student Beans app
# Overview
Source: https://docs.wearepion.com/documentation/language-and-territories/overview
A look at the territories and languages Beans iD supports.
## Territory Support
Beans iD integrations support the following territories:
| **Territory** | **Code** |
| :------------------------------- | :------- |
| 🇦🇱 Albania | AL |
| 🇩🇿 Algeria | DZ |
| 🇦🇬 Antigua and Barbuda | AG |
| 🇦🇷 Argentina | AR |
| 🇦🇲 Armenia | AM |
| 🇦🇺 Australia | AU |
| 🇦🇹 Austria | AT |
| 🇦🇿 Azerbaijan | AZ |
| 🇧🇸 Bahamas | BS |
| 🇧🇭 Bahrain | BH |
| 🇧🇩 Bangladesh | BD |
| 🇧🇾 Belarus | BY |
| 🇧🇪 Belgium | BE |
| 🇧🇷 Brazil | BR |
| 🇧🇬 Bulgaria | BG |
| 🇰🇭 Cambodia | KH |
| 🇨🇦 Canada | CA |
| 🇨🇱 Chile | CL |
| 🇨🇳 China | CN |
| 🇨🇴 Colombia | CO |
| 🇨🇷 Costa Rica | CR |
| 🇭🇷 Croatia | HR |
| 🇨🇾 Cyprus | CY |
| 🇨🇿 Czech Republic | CZ |
| 🇩🇰 Denmark | DK |
| 🇩🇴 Dominican Republic | DO |
| 🇪🇨 Ecuador | EC |
| 🇪🇬 Egypt | EG |
| 🇸🇻 El Salvador | SV |
| 🇪🇪 Estonia | EE |
| 🇫🇯 Fiji | FJ |
| 🇫🇮 Finland | FI |
| 🇫🇷 France | FR |
| 🇩🇪 Germany | DE |
| 🇬🇭 Ghana | GH |
| 🇬🇷 Greece | GR |
| 🇬🇹 Guatemala | GT |
| 🇭🇳 Honduras | HN |
| 🇭🇰 Hong Kong | HK |
| 🇭🇺 Hungary | HU |
| 🇮🇳 India | IN |
| 🇮🇩 Indonesia | ID |
| 🇮🇷 Iran | IR |
| 🇮🇪 Ireland | IE |
| 🇮🇱 Israel | IL |
| 🇮🇹 Italy | IT |
| 🇯🇲 Jamaica | JM |
| 🇯🇵 Japan | JP |
| 🇯🇴 Jordan | JO |
| 🇰🇿 Kazakhstan | KZ |
| 🇰🇪 Kenya | KE |
| 🇰🇼 Kuwait | KW |
| 🇰🇬 Kyrgyzstan | KG |
| 🇱🇻 Latvia | LV |
| 🇱🇧 Lebanon | LB |
| 🇱🇹 Lithuania | LT |
| 🇱🇺 Luxembourg | LU |
| 🇲🇴 Macau | MO |
| 🇲🇾 Malaysia | MY |
| 🇲🇹 Malta | MT |
| 🇲🇺 Mauritius | MU |
| 🇲🇽 Mexico | MX |
| 🇲🇩 Moldova | MD |
| 🇳🇱 Netherlands | NL |
| 🇳🇿 New Zealand | NZ |
| 🇳🇬 Nigeria | NG |
| 🇳🇴 Norway | NO |
| 🇴🇲 Oman | OM |
| 🇵🇰 Pakistan | PK |
| 🇵🇦 Panama | PA |
| 🇵🇾 Paraguay | PY |
| 🇵🇪 Peru | PE |
| 🇵🇭 Philippines | PH |
| 🇵🇱 Poland | PL |
| 🇵🇹 Portugal | PT |
| 🇶🇦 Qatar | QA |
| 🇲🇰 Republic of North Macedonia | MK |
| 🇲🇳 Republic Of Mongolia | MN |
| 🇷🇴 Romania | RO |
| 🇷🇺 Russia | RU |
| 🇸🇦 Saudi Arabia | SA |
| 🇸🇬 Singapore | SG |
| 🇸🇰 Slovakia | SK |
| 🇸🇮 Slovenia | SI |
| 🇿🇦 South Africa | ZA |
| 🇰🇷 South Korea | KR |
| 🇪🇸 Spain | ES |
| 🇱🇰 Sri Lanka | LK |
| 🇸🇪 Sweden | SE |
| 🇨🇭 Switzerland | CH |
| 🇹🇼 Taiwan | TW |
| 🇹🇿 Tanzania | TZ |
| 🇹🇭 Thailand | TH |
| 🇹🇹 Trinidad and Tobago | TT |
| 🇹🇳 Tunisia | TN |
| 🇹🇷 Turkey | TR |
| 🇺🇦 Ukraine | UA |
| 🇦🇪 United Arab Emirates | AE |
| 🇬🇧 United Kingdom | UK |
| 🇺🇸 United States | US |
| 🇻🇪 Venezuela | VE |
| 🇻🇳 Vietnam | VN |
| 🇻🇬 Virgin Islands, British | VG |
| 🇿🇼 Zimbabwe | ZW |
## Language Support
Beans iD integrations support the following languages:
| **Language** | **Language Code** |
| :----------- | :---------------- |
| English (UK) | `en-gb` |
| English (US) | `en-us` |
| Belgian | `nl-be` |
| Brazilian | `pt-br` |
| Chinese | `zh-cn` |
| Swiss | `de-ch` |
| Danish | `da-dk` |
| German | `de-de` |
| Spanish | `es-es` |
| Finnish | `fi-fi` |
| French | `fr-fr` |
| Croatian | `hr-hr` |
| Hungarian | `hu-hu` |
| Italian | `it-it` |
| Japanese | `jp-jp` |
| Korean | `ko-kr` |
| Dutch | `nl-nl` |
| Norwegian | `no-no` |
| Polish | `pl-pl` |
| Portuguese | `pt-pt` |
| Romanian | `ro-ro` |
| Russian | `ru-ru` |
| Slovak | `sk-sk` |
| Slovenian | `sl-si` |
| Swedish | `sv-se` |
# Overview
Source: https://docs.wearepion.com/documentation/pion-api/overview
The Pion API helps brands and discount platforms talk to each other so they can instantly confirm a customer’s student status.
By securely sharing data about what students are buying, businesses can work together to show the right people the most relevant deals. This connection allows companies to build loyalty by offering personalized discounts to students exactly when they are ready to shop.
Find out more about the Pion API
# API
Source: https://docs.wearepion.com/documentation/track-every-transaction/api
This documentation is aimed at developers to define the requirements of technical implementation of the Pion Student Beans code tracking API. More information on the definition of each field and what those fields should be populated with can be found in the knowledge base section.
## \[POST]`/code-tracking/transaction`
`POST https://sb-api.studentbeans.com/code-tracking/transaction`
This endpoint allows you to record the use of a Student Beans voucher code from a transaction.
### **Body Params**
| **Field** | **Type** | **Description** |
| :------------------------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **brandUid** \[required] | *string* | A unique ID attached to your brand issued by Pion. The brandUid is unique per country. |
| **code** \[required] | *string* | The code supplied by your brand and issued from a Student Beans platform that is then applied at checkout. |
| **transactionValue** \[required] | *float* | The value of the transaction up to two decimal places as a float. For example, if the transaction value is £10.00, you would enter `10.0` or `10.00` and not `"£10"`, `10` or `"10.0"`. |
| **qualifyingAmount** \[required] | *float* | The value of the `transactionValue` that is eligible to be discounted, up to two decimal places as a float. For example, if the qualifying amount is £1.50, you would enter `1.5` or `1.50` and not `"£1.50"`, or `"1.5"`. |
| **currency** \[required] | *string* | The ISO 4217 currency code for the locale of the transaction. |
| **timestamp** \[required] | *integer* | The timestamp of the transaction between the customer and your brand, in UTC, as Unix Epoch time in seconds. |
| **newUser** | boolean | Boolean value that determines whether the transaction is a new user. |
| **productsOrderedSku** | *array of strings* | An array of string SKU's for the products purchased as part of the transaction. |
| **productsOrderedName** | *array of strings* | An array of string product names purchased as part of the transaction. |
| **userAgent** | *string* | The user agent the transaction has been completed from. |
Example Request Body:
```
{
"brandUid": "20406f16-7f0f-11ee-b962-0242ac120002",
"code": "AFSB20UK-fcf43t",
"transactionValue": 20.25,
"qualifyingAmount": 5.25,
"currency": "GDP",
"timestamp": 1577836800,
"newUser": true,
"productsOrderedSku": ["sk1", "sk2"],
"productsOrderedName": ["Product Name 1", "Product Name 2"],
"userAgent": "iOS Safari"
}
```
### **Headers**
| | |
| :----------- | :---------------------------------------- |
| Content-Type | application-json |
| User-Agent | \/\ \ |
| api-key | \ |
### **Example Responses**
##### **200 OK**
```
{
"data": {
"type": "transaction",
"id": "20406f16-7f0f-11ee-b962-0242ac120002",
"attributes": {
"brandUid": "20406f16-7f0f-11ee-b962-0242ac120002",
"code": "AFSB20UK-fcf43t",
"transactionValue": 20.25,
"qualifyingAmount": 5.25,
"currency": "GBP",
"timestamp": 1577836800,
"newUser": true,
"productsOrderedSku": ["sk1", "sk2"],
"productsOrderedName": ["Product Name 1", "Product Name 2"],
"userAgent": "iOS Safari"
}
}
}
```
##### **400 Bad Request**
```
{
"errors": [
{
"status": 400,
"title": "Bad Request",
"detail": "Reason for failed request will be displayed here"
}
]
}
```
### **Implementation Examples**
#### **Curl Example**
```
curl -X POST \
https://sb-api.studentbeans.com/code-tracking/transaction \
-H 'Content-Type: application/json' \
-H 'api-key: ' \
-H 'User-Agent: ' \
-d '{
"brandUid": "20406f16-7f0f-11ee-b962-0242ac120002",
"code": "AFSB20UK-fcf43t",
"transactionValue": 20.25,
"qualifyingAmount": 5.25,
"currency": "GBP",
"timestamp": 1577836800
}'
```
#### **Ruby Example**
```
require 'net/http'
require 'uri'
require 'json'
url = 'https://sb-api.studentbeans.com/code-tracking/transaction'
api_key= 'YOUR_API_KEY'
user_agent = 'YOUR_USER_AGENT'
request_body = {
"brandUid": "20406f16-7f0f-11ee-b962-0242ac120002",
"code": "AFSB20UK-fcf43t",
"transactionValue": 20.25,
"qualifyingAmount": 5.25,
"currency": "GBP",
"timestamp": 1577836800
}.to_json
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri)
request["api-key"] = api_key
request["User-Agent"] = user_agent
request['Content-Type'] = 'application/json'
request.body = request_body
response = http.request(request) puts response.body
```
#### **Node Example**
```
const axios = require('axios')
const sbTrackingUrl = 'https://sb-api.studentbeans.com/code-tracking/transaction'
const apiKey = 'YOUR_API_KEY'
const userAgent = 'YOUR_USER_AGENT'
const requestBody = {
brandUid: '20406f16-7f0f-11ee-b962-0242ac120002',
code: 'AFSB20UK-fcf43t',
transactionValue: 20.25,
qualifyingAmount: 5.25,
currency: 'GBP',
timestamp: 1577836800
}
const headers = {
'api-key': apiKey,
'Content-Type': 'application/json',
'User-Agent': userAgent
}
axios
.post(sbTrackingUrl, requestBody, { headers })
.then((response) => {
console.log(response.data)
})
.catch((error) => {
console.error(error)
})
```
### **Recommended Implementation Architecture**
#### **User Journey & Data Flow**
```mermaid theme={null}
flowchart TB
A["User issues a Student Beans
Discount Code"] -- Discount code copied and user redirected --> n1["Brand Site"]
n1 -- User adds products to a basket --> n2["Checkout"]
n2 --> n3{"Student Beans
code used?"}
n3 -- NO --> n4["Continue brand specific transaction flow"]
n3 -- YES --> n5["Send Transaction payload to
/code-tracking/transaction"]
n5 --> n6{"Payload is valid?"} & n4
n6 -- YES --> n7["A 200 response is returned with
the created transaction data"]
n6 -- NO --> n8["A 4XX response is returned
highlighting why the payload is invalid"]
```
#### **User Journey & Data Flow with Embedded Connect**
```mermaid theme={null}
flowchart TB
A["Brand Homepage"] -- User navigates to discount page--> n2["Brand Embedded Connect Page"]
n2 -- User verifies student status and redeems a Student Beans code --> n3["Brand Site"]
n3 -- User adds products to a basket --> n4["Checkout"]
n4 --> n5{"Student Beans
code used?"}
n5 -- NO --> n6["Continue brand specific transaction flow"]
n5 -- YES --> n7["Send Transaction payload to
/code-tracking/transaction"]
n7 --> n8{"Payload is valid?"} & n6
n8 -- YES --> n9["A 200 response is returned with
the created transaction data"]
n8 -- NO --> n10["A 4XX response is returned
highlighting why the payload is invalid"]
```
# Knowledge Base
Source: https://docs.wearepion.com/documentation/track-every-transaction/knowledge-base
This section of the documentation aims to give a non-technical overview of what is required for the Student Beans code tracking API. The technical documentation can be found in the API Documentation section.
## **Single Use Unique Codes vs Generic/Multi-use Codes**
### **Unique Codes vs. Generic Codes**
Imagine you're giving out coupons for a free pizza.
Each coupon has a special, one-time-use code. Only one person can use that code to get their free pizza.
Everyone gets the same code. Many people can use that code to get a free pizza.
### **Code Track Pro and Unique Codes**
Code Track Pro is designed to work best with unique codes. It can track who used each code and where they came from.
### Using Generic Codes with Code Track Pro
We can make Code Track Pro work with generic codes, but there are some things to keep in mind:
* **More Time Required:** We'll need to check other information to make sure everything is working right meaning more time to get you set up correctly.
* **Less Information:** You won't get as much detail about who is using the codes in the Pion portal. Information specifically around user demographics will no longer be available.
* **Limited Reporting:** You won't be able to see as much information about who used the codes, like if they were new or returning customers.
### **Summary**
While Code Track Pro can handle generic codes, unique codes are the best option for getting the most out of the tool.
## **Transaction Endpoint**
### **Body Params**
#### **Brand UID**
The brand uid is a unique ID that is attached to your brand by Pion. Your Brand UID is unique per each country you're active in. This is a required field.
#### **Code**
The code is supplied by your brand and is issued from a Student Beans platform, this is then applied at checkout, this must be unique so that Student Beans can link this to a specific issuance. This is a required field.
#### **Transaction Value**
This is the value of the total transaction. This is a required field.
#### **Qualifying Amount**
The qualifying amount represents the proportion of the total basket that is eligible for a discount offered by a brand, here are a a couple of scenarios to consider.
To be clear the qualifying amount is not the percentage value of the discount itself (i.e. 10%). Qualifying Amount is a required field.
Your discount code works on all products or services your business offers. In this case, the entirety of any transaction made with that code is eligible to be discounted. In this scenario, the transactionValue and qualifyingAmount will be identical.
Your discount code only works for certain products or services offered by your business. In this case, the value of those products or services which are eligible to be discounted is what should be entered as the qualifyingAmount.
It is common for the qualifying amount to be different for individual users. Here are a couple of examples of where you might need to pragmatically calculate the qualify amount from the transaction value.
*Example A: A transaction is made for £100, meaning the transactionalValue is 100.0. The discount code used with this transaction is only applicable to products whose value ads up to £50. Therefore the qualifyingAmount is 50.0.*
*Example B: A brand might only offer a 10% discount on a subset of their products, i.e. Bikes but not Scooters. However, the basket contains a bike worth £150 and a scooter worth £50. While the transactionValue is £200 only £150 is eligible for discount, therefor the qualifying amount is 150.0.*
**NOTE**
Note If you have a static cost per acquisition (CPA) rate, eg. **£5.25 per lead**, you are required to enter that static CPA value in this field instead. In the case of this example that would be **5.25**
#### **Currency**
This field will represent the ISO 4217 currency code, this can be found at [https://www.newbridgefx.com/currency-codes-symbols/](https://www.newbridgefx.com/currency-codes-symbols/). This is a required field.
**TIP**
£ = GBP\
\$ = USD\
€ = EUR
**Timestamp**
The timestamp of the transaction between the customer and your brand, in UTC, as Unix Epoch time in seconds.
**INFO**
Ideally, transactions are sent instantaneously. If sending transactions in a batch (e.g., at the end of the month), the timestamp field must be time the transaction occurred between the customer and your brand.
#### **New User**
A true/false value that determines whether the transaction is a new user.
#### **Products Ordered SKU**
A comma-separated list of SKUs for the products purchased as part of the transaction.
#### **Products Ordered Name**
A comma-separated list of string product names was purchased as part of the transaction.
#### **User Agent**
The user agent the transaction has been completed from.
### **Basket Examples**
#### **Example A: The entire portion of the basket is discounted**
The example below is a demonstration of what a basket might look like where all of the items are discounted via Student Beans codes.
| **Product** | **Price** | **Discounted?** | **Note** |
| :---------- | :-------- | :-------------- | :-------------------------------------------------------------------------------------------------------------- |
| T-Shirt | **£10** | Yes | This item ***is*** discounted via Student Beans so the price ***should be included*** in the qualifying amount. |
| Jeans | **£20** | Yes | This item ***is*** discounted via Student Beans so the price ***should be included*** in the qualifying amount. |
| Shoes | **£30** | Yes | This item ***is*** discounted via Student Beans so the price ***should be included*** in the qualifying amount. |
In the payload that you send to Pion, as all items are discounted, the transaction value and the qualifying amount will be the sum of all the products, £60.
#### **Example B: A portion of the basket is discounted**
The example below is a demonstration of what a basket might look like where only some of the items are discounted via Student Beans codes.
| **Product** | **Price** | **Discounted?** | **Note** |
| :---------- | :-------- | :----------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------- |
| T-Shirt | **£10** | Yes | This item ***is*** discounted via Student Beans so the price ***should be included*** in the qualifying amount. |
| Jeans | £20 | No | This item ***is not*** discounted via Student Beans so the price ***should not be included*** in the qualifying amount. |
| Shoes | **£30** | Yes | This item ***is*** discounted via Student Beans so the price ***should be included*** in the qualifying amount. |
| Socks | £5 | Yes, but not via Student Beans | This item while discounted, ***is not*** discounted via Student Beans so the price ***should not be included*** in the qualifying amount. |
In the payload that you send to Pion, the qualifying amount should be the sum total of ***only*** the items that are valid for a Student Beans discount. i.e. the sum of the T-Shirt and Shoes, £40. The transaction value should still be the total value of the basket, £65.
### **Headers**
#### **API Key**
Your API key will be issued to you by Student Beans, this is used to authorize requests to the code tracking API.
#### **User Agent**
In some cases, you may also need to send a user agent field if you are still receiving an unauthorized error with the correct credentials.
## **Glossary**
This section contains terminology that might be ambiguous.
#### ***Single Use Unique Code***
There are a couple of different code types at Student Beans. Specifically, to utilize CodeTrackPro to its fullest you'll need a single-use unique code. This is a code that is unique per user and redeems an offer through a Student Beans product. This may look something like: "SB01-abc", "SB02-def", "SB03-ghi".
##### ***Generic/Multiuse Code***
Another type of code that can be offered through Student Beans is a code that can be used multiple times by different users, this might look something like "10OFFBRAND". This type of code has limitations (see **Using Generic Codes with Code Track Pro)** but can be used with CodeTrackPro.
# Overview
Source: https://docs.wearepion.com/documentation/track-every-transaction/overview
The Pion Code Tracking API allows you to accurately track all transactions that have used a unique Student Beans code, negating the need for a manual report at the end of the month.
To maximise the value of this service, we recommend using single-use, unique codes. If you are using generic multiuse codes, or wish to understand the implications between the two code types, please read [the following section](/documentation/track-every-transaction/knowledge-base).
This documentation is composed of two sections, Knowledge Base and API Documentation. The API Documentation section focuses on the technical requirements of the API and how it should be interacted with. The Knowledge Base section focuses on highlighting what each part of the API achieves and the value it can provide.
The Pion code tracking API has a single endpoint that is called upon when a successful transaction is made using a unique Student Beans prefixed voucher code [(or a generic code)](/documentation/track-every-transaction/knowledge-base).
# Embedding the UI
Source: https://docs.wearepion.com/documentation/verify-your-customers/beans-id-whitelabel-api/embedded/embedding-the-ui
### **Adding the Script**
Add the `
```
### **Insert the UI**
Once the script has been setup, a custom HTML element will be made available allowing you to embed the Beans iD Whitelabel Embedded UI on your page. This can be done by pasting the below snippet into your page in the location that you want the UI to be embedded:
```text theme={null}
```
| **Attribute** | **Required** | **Description** |
| :---------------- | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `verification-id` | ✅ | This UID returned from creating a verification during [the previous step](/api-reference/create-a-new-verification). |
| `redirect-url` | ✅ | The URL to send a user to once they have completed their verification via the UI. For security, this needs to match a `redirectUrl` associated with the `clientUid` used to start the verification, which can be configured via the Pion Portal. |
| `language` | ❌ | A list of valid codes can be found [here](/documentation/language-and-territories/overview). |
| `title` | ❌ | This property controls what screen readers will read when describing the iFrame used to embed the UI. |
| `width` | ❌ | This property controls the width of the embedded iFrame. This can be set to a `px` or a `%` value. |
| `height` | ❌ | This property controls the height of the embedded iFrame. This can be set to a `px` or a `%` value. *The iFrame has an enforced minimum height to ensure all the relevant content is always visible to a user.* |
# Embedded Technical Documentation
Source: https://docs.wearepion.com/documentation/verify-your-customers/beans-id-whitelabel-api/embedded/technical-documentation
## **Introduction**
This documentation provides a detailed explanation of how to integrate with Beans iD Whitelabel API - Embedded. It includes the steps you will go through for integration and provides reference points to the different API endpoints that you will utilise.
This implementation allows for a user to verify as a member of any of our supported consumer groups utilising a user interface provided by Pion that can be embedded on your site and fully customised to look and feel like your host application.
## **How does it work?**
The intended flow is as follows:
To conduct a verification, several requests must be made to the Pion API.
The Pion API provides an OAuth Client Credentials grant flow which returns an access token. Client credentials can be self-served in the Pion Portal. This will create a new pairing of a `clientId` and `clientSecret` that is used to fetch an access token that ***must*** be passed into requests that require authentication.
Once you’ve got client credentials, you can send a request to the `/auth/token` endpoint, the documentation for which can be found [here](/api-reference/authentication/generate-access-token).
To begin the verification process a request is sent to the Create Verification endpoint in the Pion API, the documentation for which can be found [here](/api-reference/beans-id-whitelabel-api/create-a-new-verification).
This will begin the verification process for your chosen consumer group, and will create a unique verification ID used to reference this verification going forwards.
The `verificationId` returned from this step **must** be saved against your user. This ensures that this verification ID can only be used for the verification of the user it is associated with.
Once a verification ID has been generated (*detailed in the previous step*), a user can be sent into the Beans iD Whitelabel Embedded UI.
This involves adding a `
```
In the `Triggers` section of the options, set the tag to fire on all pages.
Save your tag as `beansid` and then publish your container.
### Manually add the`
```
The above should be included as is, there's no need to make any changes.
# Content Security Policy
Source: https://docs.wearepion.com/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/troubleshooting/content-security-policy
**ISSUE**
We face 2 types of issue related to Content Security Policy (CSP):
* You may be using a Content Security Policy to enforce a list of URLs from which resources can be loaded on to your site. This could be blocking your embedded landing page from loading.
* We also use a Content Security Policy on your landing page to ensure that it can only be embedded on your domain. If we haven't included the domain of the page you're trying to embed your landing page on then this could also be blocking your embedded landing page from loading.
**SOLUTION**
If CSP is causing an issue, you will see one of the two error messages listed below.
#### **An issue with our CSP**
```
Refused to frame 'https://www.studentbeans.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self' ...".
```
If you see an error message similar to the above in your console then this is likely an error with our CSP.
Please contact your customer success representative and let them know the URL of the page you are trying to embed your landing page on. We will add this domain to our CSP to allow for your landing page to be embedded on this URL.
#### **An issue with your CSP**
```
Refused to frame 'https://www.studentbeans.com/' because it violates the following Content Security
Policy directive: "..."
```
If you see this error message in your browser console, it is likely the error is with your CSP.
You will need to update your CSP to include the following:
* `studentbeans.com`
* `www.studentbeans.com`
* `verification.beansid.com`
* `cdn.studentbeans.com`
# Invalid Language
Source: https://docs.wearepion.com/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/troubleshooting/invalid-language
**ISSUE**
This error will be shown when the `language` attribute provided to the `` component is invalid.
This likely indicates a mistake in the value you have provided as your `language`. The `language` should consist of 2 letters, followed by a hyphen, followed by 2 more letters. For example, `en-gb` or `fr-fr`.
**SOLUTION**
To rectify this error ensure the `language` you have provided to the `` component is correct.
A list of supported languages is available [here](/documentation/language-and-territories/overview) and instructions for overriding language can be found [here](/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/overriding-languag).
# Invalid Slug
Source: https://docs.wearepion.com/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/troubleshooting/invalid-slug
**ISSUE**
This error will be shown when the `slug` attribute provided to the `` component is invalid.
This likely indicates a mistake in the value you have provided as your `slug`. The `slug` should contain numbers (`0-9`), letters (`a-z`), and hyphens (`-`) only.
**SOLUTION**
To rectify this error ensure the `slug` you have provided to the `` component is correct. Check the values we sent you and ensure the values you have used match. If you're still having trouble reach out to your customer success representative for some assistance.
An example of how to setup your landing page correctly can be found in the [landing page setup instructions](/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/insert-your-landing-page).
# Invalid Territory
Source: https://docs.wearepion.com/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/troubleshooting/invalid-territory
**ISSUE**
This error will be shown when the `territory` attribute provided to the `` component is invalid.
This likely indicates a mistake in the value you have provided as your `territory`. The `territory` should consist only of letters (`a-z`) and should be 2 characters in length.
**SOLUTION**
To rectify this error ensure the `territory` you have provided to the `` component is correct. Check the values we sent you and ensure the values you have used match. If you're still having trouble reach out to your customer success representative for some assistance.
An example of how to setup your landing page correctly can be found in the [landing page setup instructions](/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/insert-your-landing-page).
# Legacy Issues
Source: https://docs.wearepion.com/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/troubleshooting/legacy-issues
# **Issue: Missing data-connect attribute**
**Upgrade your implementation**
#### **If you are being linked to this error in your browser console then you are using a legacy implementation.**
Please consider upgrading to our latest implementation to ensure continued functionality of your embedded landing page alongside access to new features. Instructions on our latest implementation method can be found [here](/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/insert-your-landing-page).
**Issue**
This error will be shown when a `data-connect` attribute has not been provided to the `
```
# **Issue: Invalid data-connect attribute**
**Upgrade your implementation**
#### **If you are being linked to this error in your browser console then you are using a legacy implementation.**
Please consider upgrading to our latest implementation to ensure continued functionality of your embedded landing page alongside access to new features. Instructions on our latest implementation method can be found [here](/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/insert-your-landing-page).
**Issue**
This error will be shown when the `data-connect` attribute provided to the `
```
# Missing Slug
Source: https://docs.wearepion.com/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/troubleshooting/missing-slug
**ISSUE**
This error will be shown when a `slug` attribute has not been provided to the `` component.
**SOLUTION**
To rectify this error ensure you provide your landing page `slug` to the `` component within the HTML of your page. An example of this can be found in the [landing page setup instructions](/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/insert-your-landing-page).
# Missing Territory
Source: https://docs.wearepion.com/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/troubleshooting/missing-territory
**ISSUE**
This error will be shown when a `territory` attribute has not been provided to the `` component.
**SOLUTION**
To rectify this error ensure you provide the territory code for the territory you want to embed to the `` component within the HTML of your page. An example of this can be found in the [landing page setup instructions](/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/insert-your-landing-page).
# Overview
Source: https://docs.wearepion.com/documentation/verify-your-customers/landing-pages/web/embedded-landing-pages/troubleshooting/overview
In this section you will find common issues that you may face when setting up your Beans iD embedded landing page. Alongside this, you will also find instructions on how to use the debugging tool contained within our