Roku SDK Documentation : Roku Pay and In-Channel Purchasing

Table of Contents


Overview of Roku Pay

The core services of Roku Pay are the billing of customers for subscriptions and the management of invoicing. You can bill customers within your Roku channel for a subscription or prior to installing your channel. You must create your channel prior to monetizing it. For developers new to Roku development, see the overview on Monetization.

In-Channel Purchasing Work Flow

In-channel purchasing can be processed and verified programmatically through the SceneGraph control node ChannelStore and the Roku Web Service API. The sample described in this document uses ChannelStore to show a simple sign up scenario, not the entire in-channel purchasing workflow and not the use of the Web Service API. This document describes the code to implement purchasing during sign up

The following diagram shows the use of ChannelStore and Web Service API to implement in-channel purchasing.

Create, then Monetize a Channel

You can monetize a public or non-certified channel. Before you can monetize your new channel, you need to create it using Developer Dashboard and then write the code. Your new channel can be a public channel, but it does not need to be published or certified prior to adding monetization. 

Creating a New Channel

If you are creating a new channel, follow the steps shown below. You will need a catalog feed for your content so, if you have not created a feed yet, you can use one from a Roku sample.

Go through the development process for creating a public channel, but do not publish or certify it. Later, once you have tested it and monetized it, you can certify and publish it.

Pre-requisites:

  1. Create a Roku customer account: my.roku.com/signup

  2. Upgrade to a Roku developer account: developer.roku.com/enrollment/standard
  3. Enroll in the Roku Partner Payouts Program to receive payments for channels, games, content, and ads: developer.roku.com/developer/billing
  4. Create a public channel using SceneGraph, including creating or using a catalog of content (see thchannel tutorial for a sample feed)
  5. Then package it but do not publish it or get it certified.
  6. Monetize in Developer Dashboard.

Testing a Channel

Once you have updated your channel to include the code necessary to implement billing, you'll want to test it. For this, navigate to the Developer Dashboard, find the channel, and designate it as the "billing testing" channel. For detailed instructions on how to test in-channel billing implementations, see Testing In-Channel Purchasing.

Note: Be sure to register anyone (including yourself) who will be testing transactions in your channel as a Test User before testing the new billing code, otherwise they will be charged for the test transactions they make.

Purchasing in the Sign Up Sample

Sample Application: ChannelStore_SignupFlow.zip

The ChannelStore_SignupFlow sample shows the code you need to implement to sign up a new user and allow the purchase of a subscription using the SceneGraph ChannelStore object.

Side-load this sample channel to see the sign up screens, including the purchase of a subscription. You might be asked for your Roku PIN, so have it available.

1- Once the channel is installed, launch it and you will see the screen for login or sign up. This sample only handles sign up, not login, so choose "New subscriber (sign up)."




2- Selecting "New subscriber (sign up)" brings up the "Request for information" screen. Enter the testing account’s email address and click "Allow" to use.



3- Enter a password and click "Continue."



4- If you see the example "Terms Of Use" screen, select "Accept" to display the products associated with the channel.

5- The "Subscription" screen lists the products available for purchase. Choose a product.




6- Enter your Roku PIN to confirm the purchase.

7- Once the purchase is confirmed, the in-channel purchase is complete.

 

How the ChannelStore_SignupFlow Sample Works

The ChannelStore_SignupFlow sample's package contains:

  • main.brs file typical for SceneGraph channels.
  • other typical SceneGraph folders, such as /components containing the custom components for the sample and /images for the splash screens used as backgrounds for the dialogs.
  • custom component HomeScene to control the dialogs and flow as the user moves through the sample.
  • mockup APIs so the sample doesn't store any data in the Roku device's persistent memory. In API.brs the mockups are described with information on to how to implement them in a real channel.
  • /docs directory that contains additional documentation about the sample. (Be sure you remove the /docs folder from any real channel you might create based on this sample.) 

As with all Roku chanels, the sample's flow of control begins in main.brs when the user launches the channel. The main.brs file calls the API object, defined in API.brs, to use mockup APIs for the sake of simplifying this sample. Main also creates the component HomeScene to control the other components. HomeScene gathers results from other components to control the flow of the sample and display the dialogs as the user moves through the sample.  

RokuSignUp Component

In this example of in-channel purchasing a custom component, RokuSignUp, controls the user sign up and purchase of a subscription as defined in RokuSignUp.xml 

RokuSignUp.xml

The RokuSignUp component is a SceneGraph node written to implement the standard Roku billing sign up flow. It allows interaction with the channel-specific API for user sign up (login is not shown in this sample). All user interaction dialogs and their generic properties are customizable using interface fields in the RokuSignUp API as defined in RokuSignUp.xml. You can customize the interface fields for your own channel.

Two script commands in RokuSignUp.xml link to the BrightScript code:

<script type="text/brightscript" uri="pkg:/components/RokuSignUp/RokuSignUp.brs"/>
<script type="text/brightscript" uri="pkg:/components/RokuSignUp/utils.brs"/>


RokuSignUp.brs

The file RokuSignUp.brs contains the key purchasing code, including custom functions and fields. The core APIs for in-channel purchasing are the ChannelStore commands:

  • getPurchases
  • getUserData

  • getCatalog
  • doOrder

The billing Object

The sample's RokuSignUp.xml file defines a child ChannelStore object with the ID billing

The RokuSignUp.brs file includes several ObserveField commands for billing. These set up handlers to watch for changes to properties of the billing component, such as "userData". The changes will be triggered by the handlers in RokuSignUp.brs as the user progresses through the sign up process. 

    m.billing = m.top.FindNode("billing")

    m.billing.ObserveField("userData", "On_billing_partialUserData")

    m.billing.ObserveField("catalog", "On_billing_catalog")

    m.billing.ObserveField("purchases", "On_billing_purchases")

    m.billing.ObserveField("orderStatus", "On_billing_purchaseResult")

For instance, the userData field changes in the handler On_billing_partialUserData() and the user data (the email in the sample) is retrieved when the user clicks "Allow".

sub On_billing_partialUserData()

    userEmail = ""

    if m.billing.userData <> invalid then

        userEmail = m.billing.userData.email

    end if

    m.signupAuthFlow.kbdialogEmail.text = userEmail

    m.signupAuthFlow.show = true

end sub

Sample's Runtime Flow of Control

At launch, the flow through the sample uses the custom RokuSignUp component to check if there is an active Roku subscription for the account, gather the user's name, email and password for a new account, locate the purchasing products available in the channel, and sign up the user for the product.


As you examine the code in RokuSignUp.brs, you will find:

  • The function GetParsedProducts() returns the list of products available for purchase.  
  • The last ChannelStore command for the RokuSignUp component is doOrder, which places the order. 
m.billing.command = "doOrder"
  • On_billing_products() sets the field isSubscribed to true when the user has successfully signed up. 
  • The isSubscribed field is handled by main.brs to finalize the transaction.

The following table shows which screens in the sample are driven by which commands in RokuSignUp.

 

EventCommand to useWhat it doesScreen in sample
Launch ChannelIn main.brs and other components.
In RokuSignUp:
m.top.visible 

Launches channel and draws UI.

Identifies the channel.

RokuSignUp sets up handlers.

New subscriber (sign up)

Identifies Account and gets current entitlements and purchased products

getPurchases

Checks for active Roku subscription for the account:

  • If not active, sign up.
  • If active, show content.

New subscriber (sign up)

Request User Info

getUserData

Requests name and email to sign up.

Get the password for the new account.

Request for information

Create the password

Get CataloggetCatalog

Shows products available for purchase in the channel. 

Subscription

PurchasedoOrder

Checks that order is valid, places order.

Enter Roku PIN

EntitleWeb Service API

In a real channel, the channel would now validate the user request on the channel's backend using the metadata contained in the automated Web Service API push notification returned for the transaction.

(Not shown in sample)

Show Contentmain.brs

Field isSubscribed is now true.

Content is displayed.

Subscribed successfully

Code Examples in RokuSignUp

The following examples of code demonstrate key billing functionality through the use of the core APIs for in-channel purchasing, the ChannelStore commands:

getPurchases

getUserData

getCatalog

doOrder

Using getPurchases

getPurchases is the handler for processing the catalog result. The catalog field is a content node containing the command completion status. If successful, the catalog field's ContentNode will have a child ContentNode containing information about each available in-channel purchasing product.

getPurchases issues a request for the list of purchases associated with the current user's account is issued.

sub On_billing_catalog()

    if m.billing.catalog = invalid OR m.billing.catalog.status = invalid then

        m.top.isSubscribed = false

        return

    end if

 

    if m.billing.catalog.status = 1 then

        m.billing.command = "getPurchases"

    else

        m.top.isSubscribed = false

    end if

 

end sub

 

Using getUserData

getUserData is the handler for getting the user's email.

sub On_dialogSelectSub_buttonSelected()

    if GetParentScene() = invalid then

        return

    end if

    if m.top.dialogSelectSub.buttonSelected < 0 then

        On_SubscriptionFailed()

    else

        m.billing.requestedUserData = "email"

        m.billing.command = "getUserData"

    end if

end sub

Using getCatalog

getCatalog() is called from On_Signup(), which is the handler for processing button selection. 

sub On_Signup()

    if GetParentScene() = invalid then

        return

    end if

 

    m.parentScene.dialog = m.top.pdialogCheckSubs

    GetCatalog()

end sub

Then the getCatalog() handler requests the list of in-channel products that are linked to the channel using getCatalog.

sub GetCatalog()

    print ">> Getting Products (Catalog and Purchases)"

    m.billing.command = "getCatalog"

end sub

 

Using doOrder

doOrder places the order for the in-channel purchasing product specified by "indexPurchase". Notice that order is cleared by setting it to invalid prior to setting myOrder.

sub PurchaseProduct(index As Integer)  

    ' clear order

    m.billing.order = invalid

 

    myOrder = CreateObject("roSGNode", "ContentNode")

    myFirstItem = myOrder.createChild("ContentNode")

    myFirstItem.addFields({ "code": m.billingProducts.availForPurchase.list[index].code, "qty": 1})

   

    m.billing.order = myOrder

 

    m.billing.command = "doOrder"

end sub

Field Values for RokuSignUp

The following fields are used in the custom RokuSignUp component, grouped as WRITE-ONLYREAD-ONLY and OBSERVE-ONLY.

WRITE-ONLY Fields:

Field

Type

Default

Use

isAuthNeeded

boolean

false

WRITE-ONLY. Specifies usage of channel-specific API on sign up or login. True = use channel API (see also "isLoginAPISuccess", "isSignupAPISuccess"), this will enable sign up or login selection screen; False = use Roku Billing only.

regexEmail

string

^[A-Za-z0-9_%+-]+(\.[A-Za-z0-9_%+-]+)*@([A-Za-z0-9-]+\.)+[A-Za-z]{2,6}$

WRITE-ONLY. Specifies regular expression for email address validation.

regexPassword

string

.{1,}

WRITE-ONLY. Specifies regular expression for password validation.

textTermsOfUse

string

 

WRITE-ONLY. Specifies the text of Terms-Of-Use agreement for related dialog (see dialogTermsOfUse). If empty string, the Terms-Of-Use dialog is not used and not shown.

dialogsConfig

assocarray

 

WRITE-ONLY. Sets generic attributes for all component dialogs.

dialogsButtonConfig

assocarray

 

WRITE-ONLY. Sets generic attributes for all buttons of component dialogs.

show

boolean

false

WRITE-ONLY. Shows or hides the component on the scene. True = show and start sign up flow; False = hide.

isLoginAPISuccess

boolean

 

WRITE-ONLY. Use only if isAuthNeeded = true. Allows to set result of channel-specific login API. Used for interaction with the Main thread where API call should be implemented (see also "loginUserData"). True = user is successfully logged in via channel API; False = failed to log in via API. Invokes setting "isAuthorized" and "isAfterLoginAuthFlow" fields.

isSignupAPISuccess

boolean

 

WRITE-ONLY. Use only if isAuthNeeded = true. Allows to set result of channel-specific sign up API. Used for interaction with the Main thread where API call should be implemented (see also "signupUserData"). True = user is successfully signed up via channel API (means user account was created and user was logged in with it); False = failed to sign up via API. Invokes setting "isAuthorized" and "isAfterLoginAuthFlow" fields.

 

READ-ONLY Fields:

 

Field

Type

Default

Use

posterSplash

node

 

READ-ONLY. Provides access to background splash Poster.

buttonLoginFlow

node

 

READ-ONLY. Provides access to login flow selection Button.

buttonSignupFlow

node

 

READ-ONLY. Provides access to sign up flow selection Button.

kbdialogLoginEmail

node

 

READ-ONLY. Provides access to login flow email address entry KeyboardDialog. Should have 2 buttons, they will be used for "Continue" and "Back" actions respectively.

kbdialogLoginPassword

node

 

READ-ONLY. Provides access to login flow password entry KeyboardDialog. Should have 3 buttons, they will be used for "Show/hide password", "Continue" and "Back" actions respectively.

dialogLoginErrEmail

node

 

READ-ONLY. Provides access to login flow email address validation error message Dialog. Should have one button, it will be used for confirmation ("OK") action.

dialogLoginErrPassword

node

 

READ-ONLY. Provides access to login flow password validation error message Dialog. Should have one button, it will be used for confirmation ("OK") action.

pdialogLogin

node

 

READ-ONLY. Provides access to login operation ProgressDialog.

dialogLoginFailed

node

 

READ-ONLY. Provides access to login failure message Dialog. Should have 2 buttons, they will be used for "Try again" and "Cancel" actions respectively.

kbdialogSignupEmail

node

 

READ-ONLY. Provides access to sign up flow email address entry KeyboardDialog. Should have 2 buttons, they will be used for "Continue" and "Back" actions respectively.

kbdialogSignupPassword

node

 

READ-ONLY. Provides access to sign up flow password entry KeyboardDialog. Should have 3 buttons, they will be used for "Show/hide password", "Continue" and "Back" actions respectively.

dialogSignupErrEmail

node

 

READ-ONLY. Provides access to sign up flow email address validation error message Dialog. Should have one button, it will be used for confirmation ("OK") action.

dialogSignupErrPassword

node

 

READ-ONLY. Provides access to sign up flow password validation error message Dialog. Should have one button, it will be used for confirmation ("OK") action.

pdialogSignup

node

 

READ-ONLY. Provides access to sign up operation ProgressDialog.

dialogSignupFailed

node

 

READ-ONLY. Provides access to sign up failure message Dialog. Should have 2 buttons, they will be used for "Try again" and "Cancel" actions respectively.

dialogTermsOfUse

node

 

READ-ONLY. Provides access to Terms-Of-Use message Dialog. Should have 2 buttons, they will be used for "Accept" and "Decline" actions respectively. If dialog's "message" field is empty string then Terms-Of-Use dialog is not used and not shown (see also "textTermsOfUse")

dialogSelectSub

node

 

READ-ONLY. Provides access to Roku Billing subscription selection Dialog. Buttons will be replaced with actual subscription products.

dialogNoSubToPurchase

node

 

READ-ONLY. Provides access to error message Dialog indicating that there are no available Roku Billing subscriptions to purchase, and user needs to check their Roku account for previously purchased products. Should have one button, it will be used for confirmation ("OK") action.

dialogBillingNA

node

 

READ-ONLY. Provides access to error message Dialog indicating that Roku Billing subscription service is currently unavailable. Should have one button, it will be used for confirmation ("OK") action.

pdialogCheckSubs

node

 

READ-ONLY. Provides access to Roku Billing subscription checking operation ProgressDialog

pdialogPurchase

node

 

READ-ONLY. Provides access to Roku Billing purchase operation ProgressDialog

isAuthorized

boolean

false

READ-ONLY. Valid only if channel-specific API is used on sign up or login (see "isAuthNeeded", "isLoginAPISuccess", "isSignupAPISuccess"). Provides the authorization flow (sign up or login) result. True = user was successfully authorized; False = not authorized. Flow type (login or sign up) is stored in "isAfterLoginAuthFlow" field.

 

OBSERVE-ONLY Fields:

 

FieldTypeDefaultUse

loginUserData

assocarray

 

OBSERVE-ONLY. Valid only if channel-specific API is used on login/sign up (see "isAuthNeeded"). Set when user data is obtained from login flow. Used to pass user data to the Main thread where login API call should be implemented (see also isLoginAPISuccess).

signupUserData

assocarray

 

OBSERVE-ONLY. Valid only if channel-specific API is used on login/sign up (see "isAuthNeeded"). Set when user data is obtained from signup flow. Used to pass user data to the Main thread where sign up API call should be implemented (see also isLoginAPISuccess)

isAfterLoginAuthFlow

boolean

 

OBSERVE-ONLY. Valid only if channel-specific API is used on login/sign up (see "isAuthNeeded"). Set when user authorization flow (login/sign up) is complete, and specifies its type: login or sign up. True = login flow; False = sign up flow. The flow result (whether user was authorized via API) is stored in "isAuthorized" field.

isSubscribed

boolean

false

OBSERVE-ONLY. Set when user billing subscription flow is complete. True = success (user subscribed); False = failure (user not subscribed).

 

 

Attachments:

thirdtest.png (image/png)
inchanprodaddprod.png (image/png)
addinchanprod.png (image/png)
manageinchanprods.png (image/png)
devhomebilling.png (image/png)
pubchanedit.png (image/png)
removechannel1.png (image/png)
useraddchannel.png (image/png)
privchansubmitted.png (image/png)
privchannelsubmitgreen.png (image/png)
privchanneldescripsfilled.png (image/png)
privchanneldescrips.png (image/png)
privchannelprops.png (image/png)
pubchanapproved.png (image/png)
pubchancancelsubmit.png (image/png)
pubchansubmitgreen.png (image/png)
pubchansubmit.png (image/png)
channelscreenshots.png (image/png)
addpubchandescripts.png (image/png)
addpubchanpropsoptions.png (image/png)
addpubchanpropsfilled.png (image/png)
addpubchanprops.png (image/png)
managechannelshome.png (image/png)
developerhome.png (image/png)
rokubillinghome.png (image/png)
rokudeveloperhome.png (image/png)
rokulinkdevice.png (image/png)
rokuaccountoptions.png (image/png)
rokuaccounthome.png (image/png)
package_inspector.png (application/octet-stream)
Roku Integrated Billing April 2013.pdf (application/octet-stream)
worddave038f3aa81ed3d32e44695053fbfedfb.png (application/octet-stream)
pkg_pkg.jpg (application/octet-stream)
pkg_nopkg.jpg (application/octet-stream)
inst_nokey.jpg (application/octet-stream)
noapp.jpg (application/octet-stream)
inst_nokey2.jpg (application/octet-stream)
noapp2.jpg (application/octet-stream)
inst2.jpg (application/octet-stream)
util_nofile.jpg (application/octet-stream)
util_nofile2.jpg (application/octet-stream)
pkg_pkg2.jpg (application/octet-stream)
pkg_nopkg2.jpg (application/octet-stream)
worddav9caaf5ac4211488b5913dada2a43fa04.png (application/octet-stream)
worddav7ad197e62b92bd644ece5b26d095a34d.png (application/octet-stream)
worddavef7a7053263247e25a246589cc62d2e7.png (application/octet-stream)
worddav64163c6ade0c1cb109caab0eff053bac.png (application/octet-stream)
worddav88b05c81f7ada13fc983542701f6e328.png (application/octet-stream)
worddavbe46dcd86d2cce6625d24cf54cb82f34.png (application/octet-stream)
worddav4a433c5106afa644e4b374c7180fdd08.png (application/octet-stream)
worddav28d1f1b7cb141db20a75167c01070147.png (application/octet-stream)
worddavedc2ae8c8293e8363fe16ec328e70101.png (application/octet-stream)
worddav7dba05cfe8d89fa7f5baa3db042c1e8d.png (application/octet-stream)
worddav2a2701ca78126a3f829650e64921631b.png (application/octet-stream)
worddav2cf5d5dbe889d37e8a8147ecc3685f64.png (application/octet-stream)
inst.jpg (application/octet-stream)
worddav78d201bc04a4e2fc05f70bcc1391e7ce.png (application/octet-stream)
worddav39c597cf739fd1979a29c23e6c018c16.png (application/octet-stream)
worddavd34c5fc68ffd697aff0f7463cc9538f5.png (application/octet-stream)
worddavb4cdf653c7167d21f934fcb142989fd9.png (application/octet-stream)
worddav65b700e317517ab8daf315d8282b4aaf.png (application/octet-stream)
worddavfc4074710ee8080fec6ab35cd6a8c98b.png (application/octet-stream)
worddav356bde7056d214fdff0d30bb2770005c.png (application/octet-stream)
worddav81b0e2cd76f584a9e514d27b7edf8c19.png (application/octet-stream)
worddav05f2a297492dfa22902e24eec9515cbf.png (application/octet-stream)
worddav282d6bfa7de108e6da6996439c7e7699.png (application/octet-stream)
worddaved33ec0abc417fb400f1a035316bb045.png (application/octet-stream)
worddavd5be699b750fb2040b52ac5915843eef.png (application/octet-stream)
worddavd475a32955fd430a91bdcced43d6f046.png (application/octet-stream)
worddave733f84e5306fc044d52214e658ab7e2.png (application/octet-stream)
worddav53b871ae9447068a7eb4739675c3220f.png (application/octet-stream)
worddavf29e5c023d5a41275e48e4ecb5d11f8a.png (application/octet-stream)
development-application-installer.png (image/png)
putty-telnet.png (image/png)
terminal-telnet.png (image/png)
putty-genkey.png (image/png)
terminal-genkey.png (image/png)
sideloaded-channel.png (image/png)
application-packager.png (image/png)
application-packaged.png (image/png)
add-new-channel.png (image/png)
add-custom-sdk-private-channel.png (image/png)
private-channel-properties.png (image/png)
private-channel-ch-store-info.png (image/png)
private-channel-monetization.png (image/png)
package-upload.png (image/png)
private-channel-preview-publish.png (image/png)
add-product.png (image/png)
manage-products.png (image/png)
roku-billing-guide.jpg (image/jpeg)
create-password.jpg (image/jpeg)
terms-of-use.jpg (image/jpeg)
select-subscription.jpg (image/jpeg)
pay-to-install.png (image/png)
share-info.jpg (image/jpeg)
roku-billing1.png (image/png)
roku-billing2.png (image/png)
roku-billing2.png (image/png)
roku-billing2.png (image/png)
roku-billing2.png (image/png)
roku-billing3.png (image/png)
finalfinal.png (image/png)
yoooo.png (image/png)
please.png (image/png)
roku-channel-billing-flow.pdf (application/pdf)
purchasing_code_Flow.png (image/png)
billing swimlanes.png (image/png)
billing 1.jpg (image/jpeg)
billing 2.png (image/png)
billing 3.jpg (image/jpeg)
billing 4.jpg (image/jpeg)
billing 5.jpg (image/jpeg)
billing 6.jpg (image/jpeg)
runtime flow of control.png (image/png)