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.

FANXP Integration into Native/Mobile Application

As part of Integration for FANXP it is quite often required to implement native visual for the campaign inside mobile application. The simplest option would be to use web view and native url for the campaign or WPA like implementation, however our server supports and provides API for fully native implementation

Overall in order to build FanXP experience into native app you need to integrate following components

  • Authentication with email/password
  • Handler for forgotten password
  • Handler for new registration
  • Initialization of WebSocket Connection (Socket.IO)
  • Video Player integration (Native control for HLS feed)
  • Handler for Quiz/Clicker/Static Overlay events
  • Chat Integration
  • Style and Look&Feel synchronization between Web and Native FanXP

Authentication Flow

First step to integrate will be to implement authentication support. Examples are written in python, but obviously appropriate language has to be used in real implementation

import requests
email = "test@example.com"
password = "password123"
data = {"api_key":"b0dbe529-19a6-4323-8a58-8a95ffcbfb1c","network":"email","email":email,"password":password}
res = requests.request("POST","https://tradablebits.com/api/v1/sessions/connect",data=data)
if res.status_code == 200:
    result = res.json()
    session_uid = result['session_uid']
    fan_id = result['fan_id']
    print("Valid Login")
else:
    print("Invalid Login/Pass")
    

In the case of invalid password, you can prompt to send email or sms with confirmation code

import requests
email = "test@example.com"
# set network to forgot_sms for SMS notification
data = {"api_key":"b0dbe529-19a6-4323-8a58-8a95ffcbfb1c","network":"forgot","email":email}
res = requests.request("POST","https://tradablebits.com/api/v1/sessions/connect",data=data)
if res.status_code == 200:
    result = res.json()
    status = result['status']
    message = result['message']
    request_uid = result['request_uid']
    print("Request", request_uid, message)
else:
    print("Error",res.text)
    

Once user gets email/sms with code, password can be reset via following call

import requests
email = "test@example.com"
request_uid = "36e26cf6-432c-4197-8788-fd1dac98e5f3"
reset_code = "49270"
data = {"api_key":"b0dbe529-19a6-4323-8a58-8a95ffcbfb1c","network":"reset","email":email,"reset_code":reset_code,"request_uid":request_uid}
res = requests.request("POST","https://tradablebits.com/api/v1/sessions/connect",data=data)
if res.status_code == 200:
    result = res.json()
    session_uid = result['session_uid']
    fan_id = result['fan_id']
    print("Login Success", fan_id, session_uid)
else:
    print("Error", res.text)
    

If email is not known to the system, application may decide to register new fan record

import requests
email = "test@example.com"
data = {"api_key":"b0dbe529-19a6-4323-8a58-8a95ffcbfb1c","network":"register","email":email,"first_name":"Test","last_name":"Test"}
res = requests.request("POST","https://tradablebits.com/api/v1/sessions/connect",data=data)
if res.status_code == 200:
    result = res.json()
    session_uid = result['session_uid']
    fan_id = result['fan_id']
    print("Login Success", fan_id, session_uid)
else:
    print("Error", res.text)
    
Campaign Configuration

Once you have the credentials sorted out, next step will be to get a list of available campaigns. Keep in mind, this call requires API secret, so it shouldn't be exposed in non-secure environment.

import requests
data = {"api_secret":"9eb875ac-6baf-4ee9-b189-afc725cba7f6","app_type":"fanxp"}
res = requests.request("GET","https://tradablebits.com/api/v1/apps",params=data)
if res.status_code == 200:
    result = res.json()
    for row in result:
        print('campaign',row)
else:
    print("Error")
    

Once you choose a specific campaign, your application can start integration into dependencies for full FanXP experience. In particular, connect into Socket IO for control messages and chat, fetch video configuration and setup a listener for quiz push.

First, we need to check authorization

import requests
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af"}
res = requests.request("GET","https://tradablebits.com/application/fanxp_tab/12272",params=data)
if res.status_code == 200:
    result = res.json()
    account_id = result['account_id']
    ws_rooms = result['rooms']
    chat_rooms = [x for x in filter(lambda x: x['room_type'] == "public_chat", ws_rooms)]
    control_rooms = [x for x in filter(lambda x: x['room_type'] == "control", ws_rooms)]
    if len(control_rooms) > 0: control_room = control_rooms[0]
    if len(chat_rooms) > 0: chat_room = chat_rooms[0]
    print(account_id)
    print(chat_room)
else:
    print(res.text)
    print("Error")
    
WebSocket Connection

Once, authorization, it obtained we need to initialize the connection to Socket IO Server. Please keep in mind, websocket server allows only a single connection per fan and any following connection will eliminate the past one.

import requests
import socketio
import asyncio

sio = socketio.AsyncClient(request_timeout=1)

account_id = 1
session_uid = "28c02479-068d-4600-bcab-fc4fcfbc43af"
room_name = "public_chat:room:12272"

def emit_callback(res):
    print("Result:", res)

async def async_run():
    await sio.connect('https://websockets.tbits.me/')
    data = {"account_id": account_id, "session_uid": session_uid, "room_name": room_name}
    await sio.emit("join", data, callback=emit_callback)
    message = "Hello World"
    data = {"account_id": account_id, "room_name": room_name, "message": message}
    await sio.emit('chat_message', data, callback=emit_callback)
    await sio.wait()

asyncio.run(async_run())

    

With websocket connection you need to listen for the following events

chat_message: This event includes a new chat message. Chat from the user is generated as the same event.

{
    chat_message_uid: "[uuid]",
    message: "html escaped message",
    room_name: "[room_name]",
    display_name: "user handle for the creator",
    unix_timestamp: "creation timestamp",
    fan_id: "ID for the user, who created a message",
    moderator_status: "null|moderator"
}

tbits_live_update: This event is sent on the control room and will include a state change for the performance

// 1. Status change for the campaign:
{ action: "state_change",
  state: "off|pending|active|finished"
}

// 2. Live Feed update (new Feed):
{ action: "update_live_feed",
  'live_feed': {
    'feed_name': "character feed",
    'vimeo_endpoint_uid': "XXXX-XXXX-XXXX-XXXXXXXX",
    'vimeo_key': null,
    'vimeo_event_key': 1234,
  }
  'live_overlay': {
  }
}

// 3. Live Overlay update (new Clicker):
{ action: "update_live_overlay",
  'live_feed': {},
  'live_overlay': {
        'overlay_type': 'clicker',
        'clicker_instance_uid': "XXXX-XXXX-XXXX-XXXXXXXX",
        'clicker_name': "test,
        'clicker_time': 30,
        'clicker_goal': 100000,
        'background_media_uid': 'XXXXX-XXXX-XXXXX-XXXXXXXXX',
        'sponsor_media_uid': 'XXXXX-XXXX-XXXXX-XXXXXXXXX',
        'sponsor_image_url': "http://www.google.ca",
        'sponsor_name': 'google'
  }
}

// 4. Live Overlay update (new Static Overlay):
{ action: "update_live_overlay",
  'live_feed': {},
  'live_overlay': {
        'overlay_type': 'tab_item',
        'title': 'test',
        'header_title': 'test',
        'button_url': 'https://www.google.ca',
        'button_text': 'test',
        'background_media_uid': 'XXXXX-XXXX-XXXXX-XXXXXXXXX',
        'sponsor_media_uid': 'XXXXX-XXXX-XXXXX-XXXXXXXXX',
        'sponsor_image_url': "http://www.google.ca",
        'sponsor_name': 'google'
  }
}

// 5. Live Overlay update (new Question):
{ action: "update_live_overlay",
  'live_feed': {},
  'live_overlay': {
        'overlay_type': 'quiz_question',
        'quiz_question_id': 123121,
        'question_time': 30,
        'title': "what is the answer to the ultimate question in the universe,
        'options': [{"answer_idx":1,"answer":42}],
        'sponsor_media_uid': 'XXXXX-XXXX-XXXXX-XXXXXXXXX',
        'content_media_uid': 'XXXXX-XXXX-XXXXX-XXXXXXXXX',
        'sponsor_image_url': "http://www.google.ca",
        'sponsor_name': 'google',
        'show_results': true
  }
}

Communication with campaign elements

Following are API calls, which allow to communicate various activities: clicker, quiz, etc. They all follow a similar pattern, so examples are grouped together

https://tradablebits.com/application/fanxp_home_items/[page_tab_id] Get static elements to be displayed on the home tab

https://tradablebits.com/application/fanxp_clicker/[page_tab_id] Push clicker counter into the server

https://tradablebits.com/application/fanxp_fan_answer/[page_tab_id] Get quiz question result for a given question

https://tradablebits.com/application/fanxp_profile/[page_tab_id] Get or Set fan profile fields

https://tradablebits.com/application/fanxp_leaderboard/[page_tab_id] Get Leaderboard

https://tradablebits.com/application/fanxp_submit_answer/[page_tab_id] Submit Quiz/Poll answer

https://tradablebits.com/application/fanxp_report_message/[page_tab_id] Report a message in the chat

import requests
# get home items
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af"}
res = requests.request("GET","https://tradablebits.com/application/fanxp_home_items/12272",params=data)
result = res.json()
print('home tabs',result)

# get leaderboard
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af"}
res = requests.request("GET","https://tradablebits.com/application/fanxp_leaderboard/12272",params=data)
result = res.json()
print('res',result)

# get profile
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af"}
res = requests.request("GET","https://tradablebits.com/application/fanxp_profile/12272",params=data)
result = res.json()
print('res',result)

# submit results for a given question
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af","quiz_question_id":350,"answer_idx":1}
res = requests.request("POST","https://tradablebits.com/application/fanxp_submit_answer/12272",data=data)
result = res.json()
print('res',result)

# submit results for a given clicker (instance_uid is delivered via web socket message)
# Results for clicker are delivered via WS message
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af","instance_uid":"","click_count":10}
res = requests.request("POST","https://tradablebits.com/application/fanxp_clicker/12272",data=data)
result = res.json()
print('res',result)

# get quiz result for a given question
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af","quiz_question_id":350}
res = requests.request("GET","https://tradablebits.com/application/fanxp_fan_answer/12272",params=data)
result = res.json()
print('res',result)

# report a given message in the chat
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af","chat_message_uid":""}
res = requests.request("POST","https://tradablebits.com/application/fanxp_report_message/12272",data=data)
result = res.json()
print('res',result)

        
Video Stream integration

Video stream is currently delivered in the form of HLS feed. Authenticated request to following endpoint will return either redirect or raw origin manifest file, which can and should be integrated into native player. Depending of the device you may want to include "prefetch" parameter to obtain origin manifest directly in the body of the response versus redirect

First, you can and should get a list of available video feeds

import requests
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af"}
res = requests.request("GET","https://tradablebits.com/application/fanxp_live_vimeo_endpoint/12272",params=data)
if res.status_code == 200:
    result = res.json()
    print('feeds',result)
else:
    print(res.text)
    print("Error")

Getting the manifest itself

import requests
data = {"session_uid":"28c02479-068d-4600-bcab-fc4fcfbc43af","prefetch":"true","vimeo_endpoint_uid":"xxxxxx" }
res = requests.request("GET","https://tradablebits.com/application/vimeo_hls_url/12345",params=data)
if res.status_code == 200:
    result = res.text
    print('manifest',result)
else:
    print(res.text)
    print("Error")