DISTRIBUTION OF TIZEN-BASED WATCH APPS HAS BEEN DISCONTINUED
Native IAP for Galaxy Watch
Samsung In-App Purchase (IAP) for Galaxy Watch is a Galaxy Store service that allows third-party watch applications to sell in-app items.
IAP for Galaxy Watch only works if your Galaxy Watch is paired with your phone.
The IAP Client for watch communicates with the IAP Client for phone, which internally manages communication with supporting IAP services and the Samsung ecosystem (such as Samsung Account, Samsung Checkout, and Samsung Rewards). In other words, it acts as an intermediary between the watch app and Samsung IAP phone system.
You can concentrate on integrating IAP API calls and IAP Server API calls into your watch app.
To integrate IAP for Galaxy Watch:
- Using Tizen Extension SDK, IAP Native APIs enables you to easily integrate IAP functionality into your watch app, such as configuring IAPs, getting item details, offering and selling items, and managing purchased items.
- Using Galaxy Watch Studio (formerly Galaxy Watch Designer), you can make your own watch face that prompts for payment after a free trial period, without the complexity of coding.
For more details, see the Galaxy Watch Studio online tutorial.
By integrating IAP features, your watch apps can sell these types of in-app items:
Item type | Description |
---|---|
Consumable | App users can use items only one time (for example, coins, special powers, or gems). |
Nonconsumable | App users can use items any number of times (for example, e-books or game boards). Items cannot be repurchased. NoteDuring IAP integration testing, if your application is set to TEST mode, the purchase record is initialized every 60 minutes to allow repurchase. |
Autorecurring subscription | These items are purchased automatically at specific intervals. App users can access items (such as magazines, e-zines, or newspapers) any number of times during a free trial or while their paid subscriptions are active. App users can cancel at any time after purchase during subscription period. App users can repurchase items after cancellation. NoteDuring IAP integration testing, if your application is set to TEST mode, the subscription cycle is automatically renewed every 10 minutes, and the subscription is automatically canceled after 12 renewals. |
Integrate IAP into your watch app
This section explains how to prepare your app to sell in-app items using Tizen Extension SDK. You can use Galaxy Watch Studio to make a watch face that prompts for payment after a free trial period, without the complexity of coding. See the Galaxy Watch Studio online tutorial for more information.
To prepare for integrating IAP features and testing the integration, perform the following steps:
1. Create a project
Create a project in Tizen Studio.
The application API version must be at least 2.3.2 in the tizen-manifest.xml
file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<manifest xmlns="http://tizen.org/ns/packages" api-version="4.0.0" package="org.tizen.nativeiap" version="1.0.0">
</manifest>
2. Add Permissions to tizen-manifest.xml
<privileges>
<privilege>http://tizen.org/privilege/billing</privilege>
</privileges>
3. Register app and in-app items in Seller Portal
During IAP integration, you may need to test IAP features. Samsung IAP needs information about your app and in-app items registered in Seller Portal.
As IAP integration proceeds, you can upload new versions of your app and new in-app items as needed.
To register an app and its in-app items:
-
Sign in to Seller Portal (https://seller.samsungapps.com) using your Samsung account.
-
Click Add New Application.
-
Click Galaxy Watch, select the default language, and click Next.
-
In the Binary tab, upload your app TPK.
-
In the App Information tab, enter fundamental app details.
-
In the Country / Region & Price tab, specify a free or paid app, a paid app price, and countries to sell your items.
-
In the In App Purchase tab, register one or more in-app items.
CautionDon't click *Submit Beta Test * or *Submit * in this step.
4. Integrate IAP features
#include <iap-galaxyapps.h>
Operation mode
IAP supports three operational modes. One is for enabling billing for item purchases, and the other two are for testing IAP functions without billing app users for item purchases.
Mode | Description |
---|---|
IAP_ |
Financial transactions do occur for successful requests, and actual results are returned (successful or failed). The app gets in-app item information of the app whose status in Seller Portal is For sale. |
IAP_ |
Financial transactions do not occur (app users are not billed for item purchases), and successful results are always returned. The app gets in-app item information of the app whose status in Seller Portal is Registering or Updating. |
IAP_ |
All IAP requests fail. Negative testing to ensure that your app can handle errors such as improper input and user actions. |
IAP_GALAXYAPPS_SUCCESS_TEST_MODE
IAP_GALAXYAPPS_FAILURE_TEST_MODE
If you set the mode to
IAP_GALAXYAPPS_COMMERCIAL_MODE
, it is automatically changed to IAP_GALAXYAPPS_SUCCESS_TEST_MODE
.Get in-app items available for purchase
To get all registered in-app items from Galaxy Store, use the iap_galaxyapps_get_item_list()
method.
Pass in the index of the first and last item, the item type, service mode, callback function, and user data as parameters.
When the reply is delivered, the iap_galaxyapps_reply_cb
callback is invoked with the iap_galaxyapps_h
object that stores the query results:
-
To get the request result from the
iap_galaxyapps_h
object, use theiap_galaxyapps_get_value()
method. -
If the request was successful, you can get all the item details from the
iap_galaxyapps_h
object using theiap_galaxyapps_foreach_item_info()
method.
Request
For details, see the iap_galaxyapps_get_item_list()
int iap_galaxyapps_get_item_list (int start_number,
int end_number,
const char *item_type,
iap_galaxyapps_mode_e mode,
iap_galaxyapps_reply_cb reply_cb,
void *user_data)
Response
typedef void(* iap_galaxyapps_reply_cb)(iap_galaxyapps_h reply,
iap_galaxyapps_error_e result,
void *user_data)
- Common result
Key | Value type | Description |
---|---|---|
mErrorCode | int | Error code number |
mErrorString | String | Error message |
mExtraString | String | Extra result |
mStartNumber | int | Index of the first item on the list |
mEndNumber | int | Index of the last item on the list |
mTotalCount | int | Total number of items based on the first and last item index |
- Item details
Key | Value type | Description |
---|---|---|
mItemId | String | Item ID number This is the same as the item ID used in the request. |
mItemName | String | Name provided during the item registration in the Seller Portal |
mItemPrice | String | Item price in a local currency |
mItemPriceString | String | Currency code + price For example: €7.99 |
mCurrencyUnit | String | Device user currency unit For example: $, Won, or Pound |
mCurrencyCode | String | Currency code For example: EUR or GBP |
mItemDesc | String | Item description provided during the item registration |
mItemImageUrl | String | Item image URL provided during the item registration |
mItemDownloadUrl | String | Item download URL provided during the item registration |
mType | String | Item type: 00: Consumable 01: Non-consumable 02: Non-recurring Subscription 03: Auto-recurring Subscription 10: All |
mSubscriptionDurationUnit | String | Subscription duration unit, defined as an upper case string: MONTH |
mSubscriptionDurationMultiplier | String | If the item type (mType) is 02 or 03, this is the item duration. Combined with mSubscriptionDurationUnit, it expresses the subscription duration, for example, 1MONTH. |
mJsonString | String | Original JSON string |
Code snippet
-
To handle the request output data, define a structure for it:
struct output_data { char* mErrorCode; char* mErrorString; char* mExtraString; char* mStartNumber; char* mEndNumber; char* mTotalCount; char* mItemId; char* mItemName; char* mItemPrice; char* mItemPriceString; char* mCurrencyUnit; char* mCurrencyCode; char* mItemDesc; char* mItemImageUrl; char* mItemDownloadUrl; char* mPaymentId; char* mPurchaseId; char* mPurchaseDate; char* mVerifyUrl; char* mType; char* mSubscriptionDurationUnit; char* mSubscriptionDurationMultiplier; char* mSubscriptionEndDate; char* mJsonString; }; typedef struct output_data_s;
-
Request the available items, and retrieve the item details in the reply callback:
/* Request the available item list */ int ret = iap_galaxyapps_get_item_list(1, 10, "10", IAP_GALAXYAPPS_COMMERCIAL_MODE, __get_item_list_cb, NULL); if (ret != IAP_GALAXYAPPS_ERROR_NONE) { /* Error handling */ return; }
static bool __foreach_item(iap_galaxyapps_h handle, void *user_data) { output_data value = {0,}; /* Get item properties */ iap_galaxyapps_get_value(handle, "mItemId", &value.mItemId); iap_galaxyapps_get_value(handle, "mItemName", &value.mItemName); iap_galaxyapps_get_value(handle, "mItemPriceString", &value.mItemPriceString); iap_galaxyapps_get_value(handle, "mItemDesc", &value.mItemDesc); /* Handle properties */ return true; } /* Callback */ static void __get_item_list_cb(iap_galaxyapps_h reply, iap_galaxyapps_error_e result, void *user_data) { if (result != IAP_GALAXYAPPS_ERROR_NONE) { char *mErrorString = NULL; iap_galaxyapps_get_value(reply, "mErrorString", &mErrorString); /* Error handling */ return; } /* Retrieve all items contained in the handle */ int ret = iap_galaxyapps_foreach_item_info(reply, __foreach_item, NULL); if (ret != IAP_GALAXYAPPS_ERROR_NONE) { /* Error handling */ return; } return; }
Purchase an in-app item
To purchase items from Galaxy Store, use the iap_galaxyapps_start_payment()
method.
Pass in the index of the item ID, service mode, callback function, and user data as parameters.
When the reply is delivered, the iap_galaxyapps_reply_cb
callback is invoked with the iap_galaxyapps_h
object that stores the query results:
- To get both the request result and the purchased item details from the
iap_galaxyapps_h
object, use theiap_galaxyapps_get_value()
method.
Request
For details, see the iap_galaxyapps_start_payment()
int iap_galaxyapps_start_payment(const char *item_id,
iap_galaxyapps_mode_e mode,
iap_galaxyapps_reply_cb reply_cb,
void *user_data)
Response
typedef void(* iap_galaxyapps_reply_cb)(iap_galaxyapps_h reply,
iap_galaxyapps_error_e result,
void *user_data)
- Common result
Key | Value type | Description |
---|---|---|
mErrorCode | int | Error code number |
mErrorString | String | Error message |
mExtraString | String | Extra result |
- Purchased item details
Key | Value type | Description |
---|---|---|
mItemId | String | Item ID number This is the same as the item ID used in the request. |
mItemName | String | Name provided during the item registration in the Seller Office |
mItemPrice | Double | Item price in a local currency |
mItemPriceString | String | Currency code + price For example: €7.99 |
mCurrencyUnit | String | Device user currency unit For example: $, Won, or Pound |
mCurrencyCode | String | Currency code For example: EUR or GBP |
mItemDesc | String | Item description provided during the item registration |
mItemImageUrl | String | Item image URL provided during the item registration |
mItemDownloadUrl | String | Item download URL provided during the item registration |
mPaymentId | String | ID of the payment |
mPurchaseId | String | Purchase ticket ID used to verify the purchase with the Store IAP server |
mPurchaseDate | String | Date of purchase For example: "2020-11-15 10:31:23" |
mVerifyUrl | String | Server's URL, which can be used in combination with other parameters to verify the purchase with the IAP server |
mJsonString | String | Original JSON string |
Code snippet
/* Purchase an item */
int ret = iap_galaxyapps_start_payment("item_id", IAP_GALAXYAPPS_COMMERCIAL_MODE, __purchase_cb, NULL);
if (ret != IAP_GALAXYAPPS_ERROR_NONE) {
/* Error handling */
return;
}
/* Callback */
static void
__purchase_cb(iap_galaxyapps_h reply, iap_galaxyapps_error_e result, void *user_data)
{
output_data value = {0,};
if (result != IAP_GALAXYAPPS_ERROR_NONE) {
iap_galaxyapps_get_value(reply, "mErrorString", &value.mErrorString);
/* Error handling */
return;
}
/* Get properties of the purchased item */
iap_galaxyapps_get_value(reply, "mItemId", &value.mItemId);
iap_galaxyapps_get_value(reply, "mItemName", &value.mItemName);
iap_galaxyapps_get_value(reply, "mItemPriceString", &value.mItemPriceString);
iap_galaxyapps_get_value(reply, "mItemDesc", &value.mItemDesc);
/* Handle properties */
return;
}
Get a list of purchased items
To get a list of all items purchased from Galaxy Store, use the iap_galaxyapps_get_purchased_item_list()
or iap_galaxyapps_get_purchased_item_list_by_item_ids()
method:
- For
iap_galaxyapps_get_purchased_item_list()
, pass in the index of the first and last item, the item type, the start and end date, the callback function, and user data as parameters. - For
iap_galaxyapps_get_purchased_item_list_by_item_ids()
, pass in the item IDs separated by comma (,), the callback function, and user data as parameters.
When the reply is delivered, the iap_galaxyapps_reply_cb
callback is invoked with the iap_galaxyapps_h
object that stores the query results:
-
To get the request result from the
iap_galaxyapps_h
object, use theiap_galaxyapps_get_value()
method. -
If the request was successful, you can get all the item details from the
iap_galaxyapps_h
object using theiap_galaxyapps_foreach_item_info()
method.
Request
For details, see the iap_galaxyapps_get_purchased_item_list() and iap_galaxyapps_get_purchased_item_list_by_item_ids()
int iap_galaxyapps_get_purchased_item_list(int start_number,
int end_number,
const char *start_date,
const char *end_date,
iap_galaxyapps_reply_cb reply_cb,
void *user_data)
int iap_galaxyapps_get_purchased_item_list_by_item_ids(const char *item_ids,
iap_galaxyapps_reply_cb reply_cb,
void *user_data)
Response
typedef void(* iap_galaxyapps_reply_cb)(iap_galaxyapps_h reply,
iap_galaxyapps_error_e result,
void *user_data)
- Common result
Key | Value type | Description |
---|---|---|
mErrorCode | int | Error code number |
mErrorString | String | Error message |
mExtraString | String | Extra result |
mStartNumber | int | Index of the first item on the list |
mEndNumber | int | Index of the last item on the list |
mTotalCount | int | Total number of items based on the first and last item index |
- Purchased item details
Key | Value type | Description |
---|---|---|
mItemId | String | Item ID number This is the same as the item ID used in the request. |
mItemName | String | Name provided during the item registration in the Seller Portal |
mItemPrice | String | Item price in a local currency |
mItemPriceString | String | Currency code + price |
mCurrencyUnit | String | Device user currency unit |
mCurrencyCode | String | Currency code |
mItemDesc | String | Item description provided during the item registration |
mItemImageUrl | String | Item image URL provided during the item registration |
mItemDownloadUrl | String | Item download URL provided during item registration |
mType | String | Item type: 00: Consumable 01: Nonconsumable 02: Nonrecurring subscription 03: Autorecurring subscription 10: All |
mPaymentId | String | ID of the payment |
mPurchaseId | String | ID of the purchase |
mPurchaseDate | String | Date of purchase For example: "2020-11-15 10:31:23" |
mSubscriptionEndDate | String | If the item type (mType) is 02 or 03, this is the due date |
mJsonString | String | Original JSON string |
Code snippet
int ret = iap_galaxyapps_get_purchased_item_list(1, 10, "20200101", "20221231", __get_purchased_item_list_cb, NULL);
if (ret != IAP_GALAXYAPPS_ERROR_NONE) {
/* Error handling */
return;
}
// item IDs can be obtained by seperating the values returned by the iap_galaxyapps_get_item_list() with comma(,).
int ret = iap_galaxyapps_get_purchased_item_list_by_item_ids("item1,item2,item3", __get_purchased_item_list_cb, NULL);
if (ret != IAP_GALAXYAPPS_ERROR_NONE) {
/* Error handling */
return;
}
static bool
__foreach_purchased_item(iap_galaxyapps_h handle, void *user_data) {
output_data value = {0,};
/* Get properties of the item */
iap_galaxyapps_get_value(handle, "mItemId", &value.mItemId);
iap_galaxyapps_get_value(handle, "mItemName", &value.mItemName);
iap_galaxyapps_get_value(handle, "mItemPriceString", &value.mItemPriceString);
iap_galaxyapps_get_value(handle, "mItemDesc", &value.mItemDesc);
/* Handle properties */
return true;
}
/* Callback */
static void
__get_purchased_item_list_cb(iap_galaxyapps_h reply, iap_galaxyapps_error_e result, void *user_data)
{
if (result != IAP_GALAXYAPPS_ERROR_NONE) {
char *mErrorString = NULL;
iap_galaxyapps_get_value(reply, "mErrorString", &mErrorString);
/* Error handling */
return;
}
/* Retrieve all items contained in the handle */
int ret = iap_galaxyapps_foreach_item_info(reply, __foreach_purchased_item, NULL);
if (ret != IAP_GALAXYAPPS_ERROR_NONE) {
/* Error handling */
return;
}
return;
}
Handling errors
During the IAP process, various errors can occur, for example, due to an unstable network, connection error, invalid account, or invalid product.
If an error occurs, your application receives the iap_galaxyapps_error_e
error type in the iap_galaxyapps_reply_cb
callback. Handle all errors appropriately.
-
Error Code
Error Code
Description
IAP_GALAXYAPPS_ ERROR_ NONE Successful IAP_GALAXYAPPS_ ERROR_ PAYMENT_ IS_ CANCELED Payment canceled IAP_GALAXYAPPS_ ERROR_ NETWORK_ NOT_ AVAILABLE Network is not available IAP_GALAXYAPPS_ ERROR_ IO_ ERROR IOException IAP_GALAXYAPPS_ ERROR_ TIMED_ OUT Timeout exception IAP_GALAXYAPPS_ ERROR_ INITIALIZATION Failure during IAP initialization IAP_GALAXYAPPS_ ERROR_ NEED_ APP_ UPGRADE Samsung IAP upgrade is required IAP_GALAXYAPPS_ ERROR_ COMMON Error while running IAP IAP_GALAXYAPPS_ ERROR_ ALREADY_ PURCHASED Error when a non-consumable product is repurchased or a subscription product is repurchased before the product expiration date IAP_GALAXYAPPS_ ERROR_ REQUEST_ PAYMENT_ WITHOUT_ INFO Error when payment is requested without bundle information IAP_GALAXYAPPS_ ERROR_ PRODUCT_ DOES_ NOT_ EXIST Error when the requested item list is not available IAP_GALAXYAPPS_ ERROR_ CONFIRM_ INBOX The payment result is not received after requesting payment from the server, and the purchased item list is not confirmed IAP_GALAXYAPPS_ ERROR_ NOT_ EXIST_ LOCAL_ PRICE The item is not for sale in the country IAP_GALAXYAPPS_ ERROR_ NOT_ AVAILABLE_ SHOP IAP is not supported in the country IAP_GALAXYAPPS_ ERROR_ INVALID_ PARAMETER Invalid parameter IAP_GALAXYAPPS_ ERROR_ KEY_ NOT_ FOUND Specified key is not found IAP_GALAXYAPPS_ ERROR_ NOT_ SUPPORTED_ DEVICE The device does not support IAP IAP_GALAXYAPPS_ ERROR_ OUT_ OF_ MEMORY Out of memory IAP_GALAXYAPPS_ ERROR_ PERMISSION_ DENIED Permission denied
Verify a purchase
This server API enables your server and client app to verify that a specified in-app item purchase and payment transaction were successfully completed.
The API returns a JSON object with a successful status and details about a successful transaction and the item or with a failure status.
This API can help to prevent malicious purchases and ensure that purchase and payment transactions were successful when the client app experiences network interruptions after an item purchase and payment transaction.
Request
https://iap.samsungapps.com/iap/appsItemVerifyIAPReceipt.as?protocolVersion=2.0&purchaseID={purchaseID}
- The
purchaseID
is assigned by Samsung IAP.
Your app receives it in theiap_galaxyapps_h
object as response ofiap_galaxyapps_start_payment()
and the key ismPurchaseId
.
Response
-
Success
{ "itemId" : "item01", "paymentId":"ZPMTID20131122GBI0015292", "orderId": "S20200106KRA1908790", "itemName":"Test Pack", "itemDesc":"IAP Test Item. Best value!", "purchaseDate":"2020-11-22 04:22:36", "paymentAmount":"9.000", "status":"true", "paymentMethod":"Credit Card", "mode":"REAL", }
-
Fail
{ "status":"false" }
Submit the app to Galaxy Store
1. Check the operation mode
After IAP integration, you must check the operation mode before submitting the app.
If you submit the app with IAP_GALAXYAPPS_SUCCESS_TEST_MODE
, the users will get all the items for free.
So, before beta release or normal publication, confirm if the operation mode is IAP_GALAXYAPPS_COMMERCIAL_MODE
.
2. Submit the app
When you have created an app version that is ready for review testing and normal publication, register the app and its in-app item, and then click Submit.
For more details, see the App Registration Guide.