This topic describes how to implement a billing system for managing products, sales, and payments, by using Samsung Checkout in your application.
Tizen.TV.Service.Billing Namespace
Tizen.TV.Service.Sso Namespace
Implementing the Purchase Process for Web applications
Samsung Checkout DPI Portal Guide
Samsung Checkout DPI Portal
Samsung Checkout .NET Application
Samsung Checkout Web Application
Implement a billing system for in-app purchases in your application, by using Samsung Checkout through the DPI service APIs and the purchase API and GUI.
To implement in-app purchases:
Before you start implementing Samsung Checkout in your application, start registering your application at the Samsung Apps TV Seller Office. You do not need to complete the registration with your source code at this point. To be able to use the DPI portal, you need to proceed to the second step of the App Registration Page and set the "Billing" field to "Use" and the "Samsung Checkout on TV" field to "Yes". You can save the registration at this point and return to it later when your source code is complete. For more information, see the Samsung Checkout DPI Portal guide.
To manage your product for billing, go to the Samsung Checkout DPI Portal.
Install the following NuGet packages:
To access the device and user information, and use the methods of the Tizen.TV.Service.Billing and Tizen.TV.Service.Sso namespaces, the application has to request permission by adding the following privileges to the "tizen-manifest.xml" file:
<tizen:privilege name="http://developer.samsung.com/privilege/sso.partner"/> <tizen:privilege name="http://developer.samsung.com/privilege/productinfo"/> <tizen:privilege name="http://developer.samsung.com/privilege/billing"/>
Initialize the required variables:
Retrieve the User ID:
using Tizen.TV.Service.Sso; string loginUid = Sso.GetLoginUid(); // Get UID value from TV
Retrieve the country code:
using Tizen.TV; string country = Environment.SmartHubConfig.Country;
Retrieve the server type:
using Tizen.TV; SmartHubConfig.ServerType tvServerType = Environment.SmartHubConfig.Server;
Set the service environment:
using Tizen.TV; SmartHubConfig.ServerType tvServerType = Environment.SmartHubConfig.Server; BillingRequestServerType serverType; string securityKey; switch(tvServerType) { case SmartHubConfig.ServerType.Operating: serverType = BillingRequestServerType.Prd; securityKey = "***********"; break; case SmartHubConfig.ServerType.Developement: serverType = BillingRequestServerType.Dev; securityKey = "***********"; break; }
The Tizen.TV.Service.Billing namespace enables you to access the APIs provided by the DPI service, to manage products and sales.
The check value is used by the DPI service to verify Purchase List and Products List API requests. It is a Base64 hash generated by applying the HMAC SHA256 algorithm on a concatenated string of parameters using the DPI security key.
The application can also use the check value to verify that API response data from the DPI server is legitimate. To ensure the data integrity of requests and responses in real time, generate and verify the check value for API requests and responses during runtime.
The DPI security key is used only by Samsung Smart TV applications for Samsung Checkout features. Do not expose this key. You can use a key management server for greater security.
To generate the check value, the following 2 items are used as parameters:
To generate the HMAC SHA256 hash:
using System; using System.Security.Cryptography; private string GetCheckValue(string strMsg, string strKey) { var encoding = new System.Text.ASCIIEncoding(); byte[] byteKey = encoding.GetBytes(strKey); byte[] dataToHmac = encoding.GetBytes(strMsg); HMACSHA256 hmac = new HMACSHA256(byteKey); return Convert.ToBase64String(hmac.ComputeHash(dataToHmac)); }
The Purchase List API requests the list of purchased items for a specific user, usually the currently logged-in user. The API response identifies whether purchased products have been applied or have been refunded.
For subscription products, the default value of the "AppliedStatus" parameter is "true", but the "CancelStatus" parameter does not indicate the refund status in purchase history. Instead, it indicates the cancellation status for the next subscription cycle. The "SubsStatus" and "SubsEndTime" parameters detail the subscription expiration status.
To call the Purchase List API, use the GetPurchaseList() method:
GetPurchaseList()
using System; using System.Security.Cryptography; using Tizen.TV.Service.Billing; using Tizen.TV.Service.Sso; using Tizen.TV; public void Request_Purchase_list() { BillingPlugin pIBilling = new BillingPlugin(); pIBilling.RequestAPIEventHandler += new BillingRequestAPICallbackEventHandler(RequestPurchaseListCallbackEvent); string strAppId = "**********"; // Your application ID string strUniqueCustomID = Sso.GetLoginUid(); string strCountryCode = Environment.SmartHubConfig.Country; string strItemType = "2"; string strSecurityKey = "**********"; // Your security key issued by DPI portal int iPageNumber = 1; string strCheckValue = GetCheckValue(strAppId + strUniqueCustomID + strCountryCode + strItemType + iPageNumber, strSecurityKey); bool bRet = pIBilling.GetPurchaseList(strAppId, strUniqueCustomID, strCountryCode, iPageNumber, strCheckValue, servertype); if (bRet) { // API call success } else { // API call fail } } private string GetCheckValue(string strMsg, string strKey) { var encoding = new System.Text.ASCIIEncoding(); byte[] byteKey = encoding.GetBytes(strKey); byte[] dataToHmac = encoding.GetBytes(strMsg); HMACSHA256 hmac = new HMACSHA256(byteKey); return Convert.ToBase64String(hmac.ComputeHash(dataToHmac)); } private void RequestPurchaseListCallbackEvent(object sender, BillingRequestAPICallbackEventArgs e) { // Do something }
The following tables describe the Purchase List API parameters. The response data is in JSON format.
Purchase List API request parameters:
BuyItem()
Table 1. Purchase List API request parameters
Purchase List API response parameters:
Table 2. Purchase List API response parameters
The Products List API requests product information from the DPI server. When the API is in "show" status, it returns the information for the products on sale. This API is generally used to generate a list of buyable products in the application.
To call the Products List API, use the GetProductsList() method:
GetProductsList()
using System; using System.Security.Cryptography; using Tizen.TV.Service.Billing; using Tizen.TV; public void Request_product_list() { BillingPlugin pIBilling = new BillingPlugin(); pIBilling.RequestAPIEventHandler += new BillingRequestAPICallbackEventHandler(RequestProductListCallbackEvent); string strAppId = "**********"; // Your application ID string strCountryCode = Environment.SmartHubConfig.Country; string strSecurityKey = "**********"; // Your security key issued by DPI portal string strCheckValue = GetCheckValue(strAppId + strCountryCode, strSecurityKey); int iPageSize = 100; int iPageNumber = 1; bool bRet = pIBilling.GetProductsList(strAppId, strCountryCode, iPageSize, iPageNumber, strCheckValue, servertype); if (bRet) { // API call success } else { // API call fail } } private string GetCheckValue(string strMsg, string strKey) { var encoding = new System.Text.ASCIIEncoding(); byte[] byteKey = encoding.GetBytes(strKey); byte[] dataToHmac = encoding.GetBytes(strMsg); HMACSHA256 hmac = new HMACSHA256(byteKey); return Convert.ToBase64String(hmac.ComputeHash(dataToHmac)); } private void RequestProductListCallbackEvent(object sender, BillingRequestAPICallbackEventArgs e) { // Do something after parsing e.Result JObject ProductListObj = JObject.Parse(e.Result); JArray jArray = JArray.Parse(ProductListObj.GetValue("ItemDetails").ToString()); ProductInfos = jArray.Select(p => new ProductInfo { ItemType = (string)p["ItemType"], Price = (string)p["Price"], ItemTitle = (string)p["ItemTitle"], ItemID = (string)p["ItemID"], CurrencyID = (string)p["CurrencyID"] }).ToList(); }
The following tables describe the Products List API parameters. The response data is in JSON format.
Products List API request parameters:
Table 3. Products List API request parameters
Products List API response parameters:
Table 4. Products List API response parameters
The Verify Purchase API checks whether a purchase, corresponding to the requested "InvoiceID", was successful.
To call the Verify Purchase API, use the VerifyInvoice() method:
VerifyInvoice()
using System; using Tizen.TV.Service.Billing; using Tizen.TV.Service.Sso; using Tizen.TV; public void Request_Verify_Purchase(string strInvoiceID) { BillingPlugin pIBilling = new BillingPlugin(); pIBilling.RequestAPIEventHandler += new BillingRequestAPICallbackEventHandler(RequestVerifyInvoiceCallbackEvent); string strAppId = "**********"; // Your application ID strUniqueCustomID = Sso.GetLoginUid(); // strInvoiceID = issued by GetPurchaseList string strCountryCode = Environment.SmartHubConfig.Country; bool bRet = pIBilling.VerifyInvoice(m_strAppId, strUniqueCustomID, strInvoiceID, strCountryCode, servertype); if (bRet) { // API call success } else { // API call fail } } private void RequestVerifyInvoiceCallbackEvent(object sender, BillingRequestAPICallbackEventArgs e) { // Do something }
The following tables describe the Verify Purchase API parameters. The response data is in JSON format.
Verify Purchase API request parameters:
Table 5. Verify Purchase API request parameters
Verify Purchase API response parameters:
Table 6. Verify Purchase API response parameters
The Apply Product API supports product management to help guarantee secure sales of your products. Normally, the DPI service is notified that the purchased product has been successfully applied. The Apply Product API is used in situations where purchase result delivery to the application encounters issues and is not successful. For example, if the network connection is interrupted, the application can fail to receive the "payment complete" message, even though the payment was completed. In this situation, the product is not applied to the application. You can check for unapplied products using the "AppliedStatus" parameter of the Purchase List API response and apply the product at that time.
For subscription products, the product is considered applied at the time of purchase and the "AppliedStatus" is set to "true" by default. Consequently, it is not necessary to check whether a subscription product purchase corresponding to the requested "InvoiceID" was successful.
To avoid applying the same product more than once in error, after 3 failed attempts to request the Apply Product API, wait until the network is reconnected before trying again.
To call the Apply Product API, use the ApplyInvoice() method:
ApplyInvoice()
using System; using Tizen.TV.Service.Billing; using Tizen.TV.Service.Sso; using Tizen.TV; public void Request_Apply_Purchase(string strInvoiceID) { BillingPlugin pIBilling = new BillingPlugin(); pIBilling.RequestAPIEventHandler += new BillingRequestAPICallbackEventHandler(RequestApplyInvoiceCallbackEvent); string strAppId = "**********"; // Your application ID string strUniqueCustomID = Sso.GetLoginUid(); // strInvoiceID = issued by GetPurchaseList string strCountryCode = Environment.SmartHubConfig.Country; bool bRet = pIBilling.ApplyInvoice(strAppId, strUniqueCustomID, strInvoiceID, strCountryCode, servertype); if (bRet) { // API call success } else { // API call fail } } private void RequestApplyInvoiceCallbackEvent(object sender, BillingRequestAPICallbackEventArgs e) { // Do something }
The following tables describe the Apply Product API parameters. The response data is in JSON format.
Apply Product API request parameters:
Table 7. Apply Purchase API request parameters
Apply Product API response parameters:
Table 8. Apply Product API response parameters
You can only use the Subscription Cancel API with subscription products, to request canceling the subscription. The DPI server returns the subscription expiry time and the current subscription status.
To call the Subscription Cancel API, use the CancelSubscription() method:
CancelSubscription()
using System; using Tizen.TV.Service.Billing; using Tizen.TV.Service.Sso; using Tizen.TV; public void Request_Cancel_Subscription(string strSubscriptionID) { BillingPlugin pIBilling = new BillingPlugin(); pIBilling.RequestAPIEventHandler += new BillingRequestAPICallbackEventHandler(RequestCancelSubscriptionCallbackEvent); string strAppId = "**********"; // Your application ID string strUniqueCustomID = Sso.GetLoginUid(); // strSubscriptionID = issued by GetPurchaseList string strCountryCode = Environment.SmartHubConfig.Country; bool bRet = pIBilling.CancelSubscription(strAppId, strUniqueCustomID, strSubscriptionID, strCountryCode, servertype); if (bRet) { // API call success } else { // API call fail } } private void RequestCancelSubscriptionCallbackEvent(object sender, BillingRequestAPICallbackEventArgs e) { // Do something }
The following tables describe the Subscription Cancel API parameters. The response data is in JSON format.
Subscription Cancel API request parameters:
Table 9. Subscription Cancel API request parameters
Subscription Cancel API response parameters:
Table 10. Subscription Cancel API response parameters
The following table lists result codes and messages that are returned by the DPI service.
Table 11. DPI result codes and messages
For explanations of additional DPI result codes, at the DPI portal, go to "Help > Error Code".
When the user wants to make a purchase, authenticate the user and show the common purchase GUI with the BuyItem() method of the Tizen.TV.Service.Billing namespace.
When the BuyItem() method is called, the common purchase GUI is shown in the application automatically. Do not change the purchase GUI appearance until the purchase transaction is complete and the application receives the response.
You can customize the product image in Samsung Checkout by providing the URI to an image on your own content server.
Table 12. Display your own product image
To show the common purchase GUI, call the BuyItem() method:
using System.Text; using System.IO; using Newtonsoft.Json; using Tizen.TV.Service.Billing; using Tizen.TV.Service.Sso; using Tizen.TV; public void Request_Buy_Item() { BillingPlugin pIBilling = new BillingPlugin(); pIBilling.BuyItemEventHandler += new BillingClientClosedEventHandler(BuyItemCallbackEvent); StringBuilder sb = new StringBuilder(); StringWriter sw = new StringWriter(sb); string appId = "**********"; // Your application ID string uniqueCustomID = Sso.GetLoginUid(); // Unique customer ID BillingRequestServerType servertype = GetBillingServerType(); using (JsonWriter writer = new JsonTextWriter(sw)) { writer.Formatting = Formatting.Indented; writer.WriteStartObject(); writer.WritePropertyName("OrderTotal"); writer.WriteValue(price); // Issued by GetProductList writer.WritePropertyName("OrderItemID"); writer.WriteValue(itemID); // Issued by GetProductList writer.WritePropertyName("OrderTitle"); writer.WriteValue(itemTitle); // Issued by GetProductList writer.WritePropertyName("OrderCurrencyID"); writer.WriteValue(currencyID); // Issued by GetProductList writer.WritePropertyName("OrderCustomID"); writer.WriteValue(uniqueCustomID); writer.WriteEndObject(); } bool bRet = pIBilling.BuyItem(appId, servertype, sb.ToString()); if (bRet) { // API call success } else { // API call fail } } private void BuyItemCallbackEvent(object sender, BillingClientClosedEventArgs e) { // Do something } private BillingRequestServerType GetBillingServerType() { var tvServerType = Environment.SmartHubConfig.Server; BillingRequestServerType serverType; switch (tvServerType) { case SmartHubConfig.ServerType.Operating: serverType = BillingRequestServerType.Prd; break; case SmartHubConfig.ServerType.Developement: serverType = BillingRequestServerType.Dev; break; default: serverType = BillingRequestServerType.Prd; break; } return serverType; }
The BuyItem() method request and response data are in JSON format:
BuyItem() method request parameters:
Table 13. BuyItem() method request parameters
BuyItem() method response parameters:
Table 14. buyItem() response parameters
The following table lists countries with their corresponding country code, currency, and currency code.
Table 15. Country and currency codes