Developers
Our platform was built to be flexible and intuitive for developers like you. You own all the data you collect with Tradable Bits. Our API and SDK are designed to make it easy to access your fan data, tickets and campaigns at any time, on your terms Customize the front end of any of your campaigns with the help of our documentation, complete with examples. Our RESTful API helps you access, send or receive fan data from our system to your endpoints quickly and securely. Enrich your Fan CRM and Tickets Analytics with data from other CRM systems through our many integrations. Have any questions about our developers platform? Our support team is happy to help.
Loyalty Portal Integration

The Loyalty Portal is a fan engagement system built around quests, points, and rewards. Fans complete challenges (quests) to earn points. As they accumulate points, they reach milestone tiers and unlock rewards — badges, access passes, promo codes, and more.

This guide covers the key concepts, setup process, and API integration for building a custom application on top of the Loyalty Portal.

Key Concepts

Account — Your Tradable Bits account is the top-level container. API access is authenticated using your account's api_key and api_secret.

Business (Team) — A Business represents a team or brand within your account. The loyalty portal is configured independently for each business — each has its own quests, rewards, tiers, and branding.

Fan — An end-user who interacts with the loyalty portal. Fans register with an email address and authenticate via password, email verification code, or SMS code. Each fan accumulates their own point balance and quest completions.

Point Type — The loyalty currency for a business (e.g., "Fan Points", "Loyalty XP"). You create a point type once and assign it to the business. All quests, tiers, and rewards reference this currency.

Performance (Event) — Represents a scheduled event, game, or show. Quests and rewards can be tied to a specific performance so they only appear during that event's timeframe.

Fan Point — A transaction record indicating the award of points or a reward. Each fan point entry represents a single point change — positive for points earned (e.g., completing a quest) or a reward delivery record. A fan's balance is the sum of all their fan point transactions.

Fan Activity — Interactions with the Loyalty Portal are based on fan activities — a record indicating a login or some fact of interaction with the portal. If the API is used to present the portal, these records must be created programmatically as shown in the runtime flow below. A fan must have at least one activity record to be eligible for automatic reward delivery.

Important: Fan Points and Fan Activities are required for the Loyalty Portal to function.

Fan Points are the transaction engine behind the loyalty currency and reward delivery. Every point earned, spent, or reward assigned is recorded as a fan point transaction. Without these records, tiers cannot be calculated, quest rewards cannot be tracked, and reward eligibility cannot be determined.

Fan Activities are required for automatic reward processing. The background reward system only considers fans who have at least one activity record associated with the business. When building a custom integration via API, your application must ensure fan activities are created when fans interact with the portal (e.g., when completing quests via the POST /api/v1/ent/businesses/{business_id}/quests/{page_tab_id}/fans/{fan_id}/complete endpoint, which creates the activity automatically). Without activity records, fans will not receive rewards even if they meet all point tier or quest requirements.

Point Tiers

Point Tiers are named milestones within a point type. They define the progression levels fans can reach. A fan's current tier is the highest tier whose minimum points they have reached.

Tiers serve two purposes:

  • Gate quest access — fans must reach a tier to unlock certain quests
  • Trigger automatic rewards — fans receive rewards when they reach a tier threshold
Tier ExampleMinimum Points
Bronze100
Silver500
Gold1,500
Platinum5,000

Quests

A Quest is a challenge that fans complete to earn points. Each quest awards a configurable number of points on completion. Quests can be global (always available) or tied to a specific performance (event/game).

There are six quest types:

Quest TypeWhat the fan does
campaignComplete a Tradable Bits campaign (contest, poll, survey, etc.)
quickpicksAnswer prediction-style questions in a QuickPicks campaign
link_urlVisit a specific tracked URL
scanScan a QR code or NFC tag at a physical venue
wristbandLink a wristband or ticket barcode to their account
customA flexible quest completed through an API call from your app

Access Restrictions — Quests can optionally be locked until the fan meets certain criteria:

RestrictionWhat the fan needs
(none)Open to everyone
fan_pointsFan must have accumulated a minimum number of total points
point_tierFan must have reached a specific tier
questsFan must have completed one or more prerequisite quests
tagFan must have a specific CRM tag (quest is hidden otherwise)

This lets you build progressive quest chains — complete Quest A to unlock Quest B, reach Gold tier to unlock Quest C, etc.

Rewards

A Reward is something a fan receives when they meet specific requirements. Every reward has an expiration date and an optional limit on how many fans can receive it.

Requirement types — How a reward is triggered:

RequirementHow the fan earns it
point_tierAutomatically awarded when the fan's total points reach the linked tier's threshold
questsAutomatically awarded when the fan completes all quests in a required set
(none)Assigned manually through the API or admin UI

Delivery types — What the fan receives:

Reward TypeDescription
badgeA digital badge displayed on the fan's profile
passA time-limited access pass presented as a QR code
prize_codeA redeemable code drawn from a pre-loaded pool
atvenuA promotion pushed to a wristband or QR code via AtVenu
bestringA promotion pushed to a wristband via BestRing

Rewards are processed automatically by a background task. When a fan meets a reward's requirements, the system delivers the reward and optionally sends an SMS and/or email notification.

Fans must have logged into the loyalty portal at least once to be eligible for automatic rewards.

Setup Process

Follow these steps to configure a loyalty portal for a business.

Step 1: Create a Point Type

Create a loyalty currency for the business. This is done in the admin UI under CRM > Points, or via the API:

import requests
data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET",
        "point_name": "Fan Points"}
res = requests.post("https://nest.tradablebits.com/api/v1/crm/points", data=data)
result = res.json()
print("point_uid:", result["point_uid"])

Step 2: Assign Point Type to Business

Link the point type to the business. In the admin UI, go to Business > Fan Loyalty Portal and select the point type. This page also configures portal branding — colors, fonts, header images, intro pages, and notification preferences.

Step 3: Create Point Tiers

Define milestone levels within the point type. In the admin UI, go to CRM > Point Tiers, or via the API:

import requests
point_uid = "YOUR_POINT_UID"
data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET",
        "tier_name": "Bronze", "min_points": 100}
res = requests.post(f"https://nest.tradablebits.com/api/v1/crm/point_tiers/{point_uid}", data=data)
result = res.json()
print("point_tier_uid:", result["point_tier_uid"])

Step 4: Create Quests

Build the challenges fans will complete. In the admin UI, go to Quests under the business, or via the API:

import requests
business_id = 12345
data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET",
        "quest_type": "custom",
        "quest_title": "Complete your profile",
        "quest_description": "Fill in all your profile details",
        "reward_type": "fan_points",
        "fan_points_reward": 50}
res = requests.post(f"https://nest.tradablebits.com/api/v1/ent/businesses/{business_id}/quests", data=data)
result = res.json()
print("page_tab_id:", result["page_tab_id"])

Quest creation parameters:

FieldTypeRequiredDescription
quest_typestringYesOne of: campaign, quickpicks, link_url, scan, wristband, custom
quest_titlestringYesDisplay title (max 128 chars)
quest_descriptionstringNoLonger description text
button_textstringNoCTA button label (max 32 chars)
reward_typestringNofan_points or null
fan_points_rewardintegerConditionalPoints awarded on completion (required if reward_type is fan_points, max 10,000,000)
performance_uiduuidConditionalTie quest to a specific event (required for scan and wristband)
target_page_tab_idintegerConditionalCampaign ID for campaign or quickpicks quests
link_urlstringConditionalDestination URL for link_url quests (tracker auto-generated)
scan_group_nameslistConditionalScan group names for scan quests
site_namestringConditionalSite name for scan quests (max 128 chars)
access_restriction_typestringNoOne of: fan_points, quests, point_tier, tag
fan_points_requiredintegerConditionalRequired when access_restriction_type is fan_points
point_tier_uiduuidConditionalRequired when access_restriction_type is point_tier
required_page_tab_idslist[int]ConditionalRequired when access_restriction_type is quests
tag_namestringConditionalRequired when access_restriction_type is tag
start_datedateNoQuest availability start (ISO format)
end_datedateNoQuest availability end
media_uiduuidNoImage asset for the quest
idol_uiduuidNoAssociate with a specific idol/artist

Step 5: Create Rewards

Set up rewards fans will unlock. In the admin UI, go to Milestone Rewards under the business, or via the API:

import requests
business_id = 12345
data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET",
        "reward_title": "Bronze Badge",
        "reward_type": "badge",
        "requirement_type": "point_tier",
        "point_tier_uid": "YOUR_TIER_UID",
        "expiration_timestamp": "2026-12-31T23:59:59",
        "timezone": "America/Los_Angeles",
        "winner_selection_model": "all"}
res = requests.post(f"https://nest.tradablebits.com/api/v1/ent/businesses/{business_id}/rewards", data=data)
result = res.json()
print("reward_uid:", result["reward_uid"])

Reward creation parameters:

FieldTypeRequiredDescription
reward_titlestringYesDisplay title (must be unique per business)
reward_typestringYesOne of: badge, pass, prize_code, atvenu, bestring
expiration_timestampdatetimeYesWhen the reward expires (ISO format)
timezonestringYesTimezone (e.g., America/Los_Angeles)
winner_selection_modelstringYesall (unlimited) or first (limited supply)
reward_limitintegerConditionalMax recipients (required when winner_selection_model is first)
requirement_typestringNopoint_tier, quests, or null
point_tier_uiduuidConditionalRequired when requirement_type is point_tier
required_page_tab_idslist[int]ConditionalRequired when requirement_type is quests
descriptionstringNoLonger description text
performance_uiduuidNoTie to a specific event (required for atvenu and bestring)

Reward-type-specific fields:

Reward TypeAdditional Fields
passaccess_start_timestamp, access_end_timestamp, access_pass_type (e.g., qrcode)
prize_codeprize_codes (comma or newline-separated list), is_limited (single-use flag)
atvenuatvenu_sales_event_key, atvenu_promo_key, atvenu_delivery_method (wristband or qrcode)
bestringbestring_location_group_id, bestring_promotion_id

Authentication Flow

All fan-facing interactions require authentication. The flow uses the sessions API to obtain a session_uid and fan_id for all subsequent calls.

Step 1: Check email — Determine if the fan exists

import requests
email = "fan@example.com"
data = {"api_key": "YOUR_API_KEY", "network": "email", "email": email}
res = requests.post("https://nest.tradablebits.com/api/v1/sessions/connect", data=data)
result = res.json()
if result["status"] == "register":
    print("New fan — registration required")
elif result["status"] == "login":
    print("Existing fan — login required")
    has_password = result.get("password", False)
    has_phone = result.get("phone", False)

Step 2: Register (if new fan)

data = {"api_key": "YOUR_API_KEY", "network": "register",
        "email": email, "first_name": "Jane", "last_name": "Doe"}
res = requests.post("https://nest.tradablebits.com/api/v1/sessions/connect", data=data)

Step 3: Login — via password, email verification, or SMS verification

# Password login
data = {"api_key": "YOUR_API_KEY", "network": "email",
        "email": email, "password": "fanpassword"}
res = requests.post("https://nest.tradablebits.com/api/v1/sessions/connect", data=data)
result = res.json()
session_uid = result["session_uid"]
fan_id = result["fan_id"]
# Email verification login (two-step)
# 1. Request verification code
data = {"api_key": "YOUR_API_KEY", "network": "verify_email", "email": email}
res = requests.post("https://nest.tradablebits.com/api/v1/sessions/connect", data=data)
request_uid = res.json()["request_uid"]

# 2. Submit the code the fan received
data = {"api_key": "YOUR_API_KEY", "network": "submit_verification_code",
        "email": email, "verification_code": "49270", "request_uid": request_uid}
res = requests.post("https://nest.tradablebits.com/api/v1/sessions/connect", data=data)
session_uid = res.json()["session_uid"]
fan_id = res.json()["fan_id"]

Runtime API Flow

Once authentication is complete and the portal is configured, your application interacts with the loyalty portal through the following API sequence.

1. Get businesses

data = {"api_key": "YOUR_API_KEY"}
res = requests.get("https://nest.tradablebits.com/api/v1/businesses", params=data)
businesses = res.json()
for biz in businesses:
    print(biz["business_id"], biz["business_name"])

2. Get point tiers for the business

point_uid = "BUSINESS_POINT_UID"
data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET"}
res = requests.get(f"https://nest.tradablebits.com/api/v1/crm/point_tiers/{point_uid}", params=data)
tiers = res.json()
for tier in tiers:
    print(tier["tier_name"], tier["min_points"])

3. Get the fan's current tier

data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET",
        "point_name": "Fan Points"}
res = requests.get(f"https://nest.tradablebits.com/api/v1/crm/fans/{fan_id}/point_tier", params=data)
fan_tier = res.json()

4. Get quests

business_id = 12345
data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET"}
res = requests.get(f"https://nest.tradablebits.com/api/v1/ent/businesses/{business_id}/quests", params=data)
quests = res.json()

5. Get the fan's quest completions

data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET"}
res = requests.get(f"https://nest.tradablebits.com/api/v1/ent/businesses/{business_id}/quests/fans/{fan_id}/complete", params=data)
completions = res.json()  # { page_tab_id: true/false }

6. Complete a quest

page_tab_id = 67890
data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET"}
res = requests.post(f"https://nest.tradablebits.com/api/v1/ent/businesses/{business_id}/quests/{page_tab_id}/fans/{fan_id}/complete", data=data)
result = res.json()
print("activity_id:", result["activity_id"])

Points are automatically awarded based on the quest's fan_points_reward configuration. If the fan has already completed the quest, the existing activity_id is returned.

7. Get the fan's rewards

data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET"}
res = requests.get(f"https://nest.tradablebits.com/api/v1/ent/businesses/{business_id}/fans/{fan_id}/rewards", params=data)
rewards = res.json()

8. Manually assign a reward (for rewards with no automatic requirement)

data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET",
        "reward_uid": "REWARD_UID"}
res = requests.post(f"https://nest.tradablebits.com/api/v1/ent/businesses/{business_id}/fans/{fan_id}/rewards", data=data)

9. Poll for recent reward updates

data = {"api_key": "YOUR_API_KEY", "api_secret": "YOUR_API_SECRET",
        "last_update_date": "2026-01-01"}
res = requests.get("https://nest.tradablebits.com/api/v1/ent/reward_updates", params=data)
updates = res.json()

Determining Quest Status

After fetching quests and completions, your application should evaluate each quest's status for the fan:

  1. If the quest's page_tab_id is in the completions map as truecompleted
  2. If access_restriction_type is set, check the restriction:
    • fan_points — compare the fan's total points against fan_points_required
    • point_tier — compare the fan's total points against the tier's min_points
    • quests — check if all required_page_tab_ids are completed
    • tag — check if the fan has the required CRM tag (hide the quest if they don't)
  3. If restrictions are not met — locked (show with lock icon and explanation)
  4. Otherwise — active (available to complete)

API Reference Summary

ActionMethodEndpoint
Authenticate fanPOST/api/v1/sessions/connect
Get businessesGET/api/v1/businesses
List point typesGET/api/v1/crm/points
Create point typePOST/api/v1/crm/points
List point tiersGET/api/v1/crm/point_tiers/{point_uid}
Create/update tierPOST/api/v1/crm/point_tiers/{point_uid}
Get fan's current tierGET/api/v1/crm/fans/{fan_id}/point_tier
List questsGET/api/v1/ent/businesses/{business_id}/quests
Create questPOST/api/v1/ent/businesses/{business_id}/quests
Delete questDELETE/api/v1/ent/businesses/{business_id}/quests/{page_tab_id}
List rewardsGET/api/v1/ent/businesses/{business_id}/rewards
Create rewardPOST/api/v1/ent/businesses/{business_id}/rewards
Delete rewardDELETE/api/v1/ent/businesses/{business_id}/rewards/{reward_uid}
Get fan's rewardsGET/api/v1/ent/businesses/{business_id}/fans/{fan_id}/rewards
Assign reward to fanPOST/api/v1/ent/businesses/{business_id}/fans/{fan_id}/rewards
Get quest completionsGET/api/v1/ent/businesses/{business_id}/quests/fans/{fan_id}/complete
Complete questPOST/api/v1/ent/businesses/{business_id}/quests/{page_tab_id}/fans/{fan_id}/complete
Poll reward updatesGET/api/v1/ent/reward_updates
Render media assetGET/fb_media/{media_uid}

Media assets referenced by media_uid can be rendered via https://nest.tradablebits.com/fb_media/{media_uid}. Optional query parameters: width, height for image resizing.