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);
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 Character | Name |
---|---|
' | Single quotation mark |
\ | Backslash |
Valid special characters
Special Character | Name |
---|---|
. | 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
Value | Type | Description |
---|---|---|
isGlobal | bool | 'true' if the payment occurred overseas, 'false' if the payment occurred in Korea |
productId | string | OneStore.Purchasing.PurchaseData.purchase.ProductId |
purchaseToken | string | OneStore.Purchasing.PurchaseData.purchase.PurchaseToken |
receiptDescription | string | Additional details to be stored |
iapPrice | string | Price of the item |
iapCurrency | string | Currency 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