Skip to main content
Version: 5.17.0

IsValidateOneStorePurchase

public BackendReturnObject IsValidateOneStorePurchase(bool isGlobal, string productId, string purchaseToken, string receiptDescription);\ public BackendReturnObject IsValidateOneStorePurchase(bool isGlobal, string productId, string purchaseToken, string receiptDescription, string iapPrice, string iapCurrency);

Note on replacing iapPrice data for certain countries\

Some countries use commas (,) instead of periods (.) to represent decimal numbers.\ In such countries, the iapPrice value provided by each store may also include commas (,).\ Since BACKND's receipt validation can only process numeric data, using iapPrice values that include commas (,) as-is may cause the amount to be processed incorrectly as 0.\ Please replace commas(,) with periods (.) in iapPrice data before use.\

Invalid special characters

Special CharacterName
'Single quotation mark
\ Backslash

Valid special characters

Special CharacterName
.Period
,Comma
"Double quotation mark
()Parentheses
!Exclamation mark
?Question mark
~Tilde
@At sign
*Asterisk
+Plus
-Hyphen
/Slash

If you are using special characters that are not listed above, manually check that the receipt verification works properly before applying.

Parameters

ValueTypeDescription
isGlobalbool'true' if the payment occurred overseas, 'false' if the payment occurred in Korea
productIdstringOneStore.Purchasing.PurchaseData.purchase.ProductId
purchaseTokenstringOneStore.Purchasing.PurchaseData.purchase.PurchaseToken
receiptDescriptionstringAdditional details to be stored
iapPricestringPrice of the item
iapCurrencystringCurrency for the item

Description

IPurchaseCallback.OnConsumeSucceeded() in the Payment service supported by ONE Store accepts the receipt for the purchased product and verifies it via the BACKND server.

  • BACKND verifies the validity of the receipt itself and the purchased productId.
  • You must be logged in to BACKND to use its receipt verification function.

Display amount of purchase (optional)

To display the transaction price in the receipt verification section of the BACKND Console, you must include the parameters iapPrice and iapCurrency.

When calling QueryProductDetails in the PurchaseClientImpl class, the OnProductDetailsSucceeded handler of the registered IPurchaseCallback is triggered, where you can check the pricing information.

public class YourCallback: IPurchaseCallback
{
public void OnProductDetailsSucceeded(List<ProductDetail> productDetails)
{
OneStoreReceiptTest.productDetailList = productDetails;
Debug.Log("OnProductDetailsSucceeded ");

foreach (var pro in productDetails)
{
Debug.Log($"{pro.title} / {pro.type} / {pro.price} / {pro.promotionPrice} / {pro.productId}");
}
}

public void OnPurchaseSucceeded(List<PurchaseData> purchases)
{
Debug.Log("OnPurchaseSucceeded ");

foreach (var pro in purchases)
{
OneStoreReceiptTest.purchaseClient.ConsumePurchase(pro);
}
}

public void OnConsumeSucceeded(PurchaseData purchase)
{
Debug.Log("OnConsumeSucceeded ");

string productPrice = "";
string productCurrency = "";
OneStoreReceiptTest.productDetailList.ForEach(productDetail =>
{
if (productDetail.productId == purchase.ProductId)
{
productPrice = productDetail.price;
productCurrency = productDetail.priceCurrencyCode;
}
});

var bro = Backend.Receipt.IsValidateOneStorePurchase(false, purchase.ProductId, purchase.PurchaseToken, data, productPrice, productCurrency);

if (bro.IsSuccess())
{
Debug.Log("ValidateOneStoreReceipt : " + bro);
}
else
{
Debug.LogError("ValidateOneStoreReceipt : " + bro);
}
}
}


public class OldOneStoreReceiptTest : MonoBehavior
{
// Start is called before the first frame update
public static PurchaseClientImpl purchaseClient = null;

public static List<ProductDetail> productDetailList = new List<ProductDetail>();
public static List<string> productList = new List<string>();

public void InitializeOneStore()
{
purchaseClient = new PurchaseClientImpl("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ~~");
purchaseClient.Initialize(new YourCallback());
purchaseClient.LaunchUpdateOrInstallFlow(action =>
{
Debug.Log("LaunchUpdateOrInstallFlow " + action.ToString());
});

productList.Add("onestore_gamepoint");
purchaseClient.QueryProductDetails(productList.AsReadOnly(), ProductType.ALL);
}

private void Purchase()
{
if (purchaseClient == null)
{
Debug.LogError("purchaseClient is null");
return;
}

Debug.Log("ONE Store login successful");

var builder = new PurchaseFlowParams.Builder();
builder.SetProductId(productList[0]);

purchaseClient.Purchase(builder.Build());

new OneStoreAuthClientImpl().LaunchSignInFlow(signInResult =>
{
if (signInResult.IsSuccessful())
{
Debug.Log("LaunchSignInFlow Success");
}
else
{
Debug.LogError("LaunchSignInFlow Fail");

}
});
}
}

Example

Synchronous

    List<ProductDetail> productDetailList;

public void BuyButton(int i)
{
string productId = "gold";

// Purchase logic
ProductType productType = ProductType.INAPP;
var purchaseFlowParams = new PurchaseFlowParams.Builder()
.SetProductId(productId) // Addition necessary
.SetProductType(productType) // Addition necessary
.SetDeveloperPayload("Insert information to write separately here") // Optional item
.Build();
purchaseClient.Purchase(purchaseFlowParams);
}

public void OnPurchaseSucceeded(List<PurchaseData> purchases)
{
bool isGlobal = false; // If the app is only released in Korea via ONE Store

/*
Processing BACKND receipt verification
*/
for(int i = 0; i < purchases.Count; i++) {

BackendReturnObject validation = Backend.Receipt.IsValidateOneStorePurchase(isGlobal, purchases[i].ProductId, purchases[i].PurchaseToken, "receiptDescription");

// When receipt verification is successful
if (validation.IsSuccess()) {
Debug.Log($"ProcessPurchase: PASS. Product: {purchases[i].ProductId}");

if (purchases[i].ProductId == "gold") {
// Give gold
}

} else {
Debug.Log($"ProcessPurchase: FAIL. Unrecognized product: {purchases[i].ProductId}");
}
}
}

Asynchronous

    public void BuyButton(int i)
{
string productId = "gold";

// Purchase logic
ProductType productType = ProductType.INAPP;
var purchaseFlowParams = new PurchaseFlowParams.Builder()
.SetProductId(productId) // Addition necessary
.SetProductType(productType) // Addition necessary
.SetDeveloperPayload("Insert information to write separately here") // Optional item
.Build();
purchaseClient.Purchase(purchaseFlowParams);
}

public void OnPurchaseSucceeded(List<PurchaseData> purchases)
{
bool isGlobal = false; // If the app is only released in Korea via ONE Store
/*
Processing BACKND receipt verification
*/
for(int i = 0; i < purchases.Count; i++) {


Backend.Receipt.IsValidateOneStorePurchase(isGlobal, purchases[i].ProductId, purchases[i].PurchaseToken, "receiptDescription", (callback) =>
{
// When receipt verification is successful
if (callback.IsSuccess()) {
Debug.Log($"ProcessPurchase: PASS. Product: {purchases[i].ProductId}");

if (purchases[i].ProductId == "gold") {
// Give gold
}

} else {
Debug.Log($"ProcessPurchase: FAIL. Unrecognized product: {purchases[i].ProductId}");
}
});
}
}

ReturnCase

Success cases

When successful\ statusCode : 201\ message : Success\ returnValue : {"usedDate":"2018-10-15T05:17:49Z"}

Error cases

When the ONE Store information in the console is invalid\ statusCode : 400\ errorCode : UndefinedParameterException\ message : undefined onestore client_id, onestore client_id cannot be checked.

If the receipt verification is invalid\ statusCode : 400\ errorCode : BadParameterException\ message : bad token, Invalid token

If the receipt token is string.Empty\ statusCode : 400\ errorCode : BadParameterException\ message : undefined token, token cannot be checked.

If the productId is string.Empty\ statusCode : 400\ errorCode : BadParameterException\ message : undefined productId, productId cannot be checked.

Tampered/forged receipt token\ statusCode : 400\ errorCode : BadParameterException\ message : bad token, Invalid token

Already used receipt token\ statusCode : 409\ errorCode : UsedReceipt\ message : This receipt has already been used. usedDate: 2018-02-15T04:01:50.000Z