Payments & Anti-cheat

Payment event integration and using anti-cheat methods

Here you'll find the principles of processing data about real payments, tips for the integration of the Payment event and anti-cheat methods used in devtodev.

Payment event integration

Gross metrics are one of the key indicators of the app’s performance. Therefore, it is important to approach the integration of the Payment event very seriously.

There are four parameters that are sent in the Payment event:

  1. Transaction identifier

  2. Item name

  3. Item price in payment currency

  4. Payment currency identifier.

Let’s look at each of the parameters and things to keep in mind when specifying their values while integrating devtodev SDK.

Transaction identifier

This is one of the transaction parameters where invalid values occur most often.

Here are the requirements for this parameter:

  1. The transaction identifier is a string value of max 64 symbols. In case this limit is exceeded the value will be shortened to 64 symbols.

  2. The transaction identifier must be unique. Data about the transaction with already registered identifier will be discarded by the system and not included in statistics.

  3. We recommend using the identifier that has been assigned to the transaction by the payment system as the transaction identifier.

  4. In case your app is designed for Apple (iPhone, iPad, iPhone+iPad, or Mac) or Android (Google Play) platforms, the use of the transaction identifier assigned by the app store is mandatory! Transaction identifiers that come from apps on these platforms are checked by devtodev for their compliance with the format used by these markets. This allows us to discard the most obvious cheat transactions. It is also important to know that users who made these transactions are marked as cheaters and all their subsequent transactions are not included in statistics (you can disable this verification process by contacting our managers).

Item name

The item name is a string value that shouldn’t exceed 255 symbols. One of the most common mistakes when specifying the value of this parameter is specifying the localized name of the item in multi-language apps, which leads to the appearance of many records that describe the same item in different reports (for example, Purchases by level). One way to avoid this situation is to specify the name of the item bundle as its name.

Item price and currency identifier

The item price and currency identifier are related parameters, so it makes sense to describe them in one section. The item price parameter contains the sum that a user paid for the item in a payment currency. The price is specified as a floating-point number. The currency identifier parameter must specify the currency as a three-letter code according to ISO 4217 standard (examples: USD, EUR, JPY, CNY, RUB).

When the Payment event reaches devtodev servers, before transaction data is saved, the sum is automatically converted to USD at the actual currency rate at that moment.

In case of not specifying or specifying invalid currency identifier, the transaction is considered invalid and is not counted in statistics.

If after converting to USD the sum exceeds $1500, the transaction is considered invalid and is not counted in statistics as well (this verification can be disabled by contacting our managers). When the transaction is made with an in-game currency of social network, you first need to convert this currency to any real-world currency.

It is also important to remember that the sum of the purchase sent in the Payment event shows the actual sum that the user paid (this data is used to built Gross metrics). In order to see your net income (Revenue metrics), on the page with app settings in devtodev, you need to specify the coefficient of the part that you get after subtracting the percentage that goes to the platform or publisher. The coefficient can be specified as single or individual for each country (this increases the accuracy in case the part of the sum is spent on taxes and fees that are individual for each country).

Payment validation

Unfortunately, in some situations filling in the parameters of the Payment event is not enough for getting valid data in reports, since there can be cheat transactions. There are several ways to deal with this problem, but all of them are based either on preliminary verification of the transaction or detection of suspicious user actions.

To prevent cheat transactions from getting into the report, you need to either check the transaction in advance and, if the transaction turns out to be invalid, omit sending the Payment event, or mark the user/device as a cheater and exclude their further data from all reports. It is possible to combine both methods for greater reliability.

The process of detecting cheaters based on their behavior within apps depends on the specificity of a particular app. If you have implemented such an algorithm, you can mark suspicious users as cheaters to avoid getting data on their payments in reports. To do that, you just need to execute a method or mark users via API (“Information about a user” section).

One of the conditions for increasing the reliability of transaction verification is implementing it outside of the client app. You can create the system of verification and place it on your own servers or use our out-of-the-box solution - devtodev anti-cheat system.

devtodev anti-cheat allows to check the validity of transactions from the following app stores:

  • iTunes

  • Google Play Store

  • Microsoft Store.

Validating App Store transactions

At the moment of transaction completion (for example, in the method - (void)paymentQueue:(SKPaymentQueue *) queue updatedTransactions:(NSArray *)

transactions at SKPaymentTransactionObserver class) call the method from the library devtodev.framework [DevToDevCheat verifyPaymentWithCompletion: (void (^)(ReceiptStatus status)) completion];

For example:

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    for(SKPaymentTransaction *transaction in transactions){
            case SKPaymentTransactionStatePurchasing: 
                NSLog(@"Transaction state -> Purchasing");
            case SKPaymentTransactionStatePurchased:
                [DevToDevCheat verifyPaymentWithCompletion:^(ReceiptStatus status) {
                    switch (status) {
                        case ReceiptValid: 
                        case ReceiptSandbox: 
                        case ReceiptNotValid: 
                        case ReceiptServerError: 
                        case ReceiptInternalError: 
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                NSLog(@"Transaction state -> Purchased");
            case SKPaymentTransactionStateRestored:
                NSLog(@"Transaction state -> Restored");
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            case SKPaymentTransactionStateFailed:
                if(transaction.error.code == SKErrorPaymentCancelled){
                    NSLog(@"Transaction state -> Cancelled");
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            case SKPaymentTransactionStateDeferred:

Validating Google Play transactions

To verify the transaction made in Google Play you need:

  1. Response data from an In-app Billing Version 5 purchase request. The validation process requires full values of the keys INAPP_PURCHASE_DATA и INAPP_DATA_SIGNATURE

  2. Application's public key for licensing

Here's how to find your application's public key for licensing:

  1. Go to the Google Play Console and sign in. Make sure that you sign in to the account from which the application you are licensing is published (or will be published).

  2. In the application details page, locate the Services & APIs link and click on it.

  3. In the Services & APIs page, locate the Licensing & In-App Billing section. Your public key for licensing is given in the Your License Key For This Application field.

The example of implementing transaction validation:

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == IN_APP_REQUEST_CODE) {
         String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
         String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");

         if (resultCode == RESULT_OK) {
            DevToDevCheat.verifyPayment(purchaseData, dataSignature, "APP_LICENSE_KEY", new OnVerifyListener() {
                 public void onVerify(VerifyStatus verifyStatus) {
                     if (verifyStatus == VerifyStatus.Valid) {

Validating Microsoft Store transactions

The receipt is taken from the result of implementing the following method - RequestProductPurchaseAsync

PurchaseResults purchaseResult = await CurrentAppSimulator.RequestProductPurchaseAsync("some_product");

     (ReceiptVerificationStatus status) =>
         if (status == ReceiptVerificationStatus.ReceiptValid)
             // SDK.RealPayment ...
  1. Get response about a completed transaction from the payment system.

  2. Either send data about the received transaction for verification by calling devtodev anti-cheat methods or use your own tools for transaction verification.

  3. If the transaction has successfully passed verification, perform the Payment event.

  4. If the transaction hasn’t passed verification, do not perform the Payment event and mark the user as a cheater.

We do not recommend to use the result of devtodev anti-cheat verification as a condition for giving or not giving in-game currency or item purchased by user.

Last updated