LogoLogo
My AppsLive demoNewsArticles
  • Introduction
  • 📌Product updates: 2025
    • 2024
    • 2023
  • Getting Started
    • Registration
    • Adding a space
    • Adding an app to the space
  • Basic Events & Custom Events
  • Integration
    • Expert Tips
      • What to track
      • Payments & Anti-cheat
      • Check your integration
    • Integration of SDK 2.0+
      • SDK Integration
        • Android
        • iOS
        • macOS
        • Windows
        • Web
          • Web SDK Integration
          • Web SDK Releases
        • Unity
        • Unreal Engine
        • Godot Engine
      • Automatic payment tracking
        • App Store
        • Google Play
      • Setting up Events
        • Basic methods
        • Secondary methods
        • User profile
        • Anticheat methods
        • Track sessions
      • Push notifications
        • Android
        • iOS
        • Windows (UWP)
        • Unity
          • Android
          • iOS
          • Windows (UWP/WSA)
        • Unreal Engine
      • A/B testing
        • Description of A/B testing on the SDK side
        • Working with A/B tests in the devtodev interface
        • A/B testing examples
    • Test Devices
    • Server API
      • Data API 2.0
      • Subscription API
      • Push API
        • IOS
        • Android
        • Windows UWP
        • Windows
      • Raw Export
      • Labels API
      • Data API
    • Import historical data via API
    • Data Export
      • Data Export to Cloud Storage (BigQuery / Amazon S3)
    • Integration of SDK 1.0+ (deprecated)
      • SDK Integration
        • iOS
        • Android
        • Windows 8.1 and 10
        • Web
        • Unity
        • Mac OS
        • Adobe Air
        • UE4
      • Setting up Events
        • Basic methods
        • Secondary methods
        • User profile
        • Anti-cheat Methods
      • Push Notifications
        • IOS
        • Android
        • Windows 8.1 and Windows 10
        • Unity
        • Abode Air
        • UE4
  • 3rd Party Sources
    • Attribution Trackers
      • AppsFlyer
      • Adjust
      • Branch.io
      • Kochava
      • Tenjin
      • Tune (MAT)
      • Singular
      • Custom postback API
      • Facebook Ads referral decryption
    • App Marketplace Data
      • App Store Connect Stats
      • App Store Subscriptions
      • Google Play Console Stats
      • Google Play Subscriptions
      • AppGallery Connect Stats
    • Ad revenue
      • AdColony
      • AdMob
      • Facebook
      • MoPub
      • Unity Ads
      • Vungle
      • Ad revenue API
    • Cohort export
  • Reports and Functionality
    • Space-related Reports and Functionality
      • Overview
      • Custom dashboards & Reports
      • SQL
        • SQL tips
        • SQL Query examples
      • Audience overlap
    • Project-related Reports and Functionality
      • Overview
        • Real-Time Dashboard
        • Acquisition reports
        • Engagement reports
        • Monetization reports
        • In-game analysis reports
        • Cohort analysis
      • Reports
      • Push Notifications
        • Android Notifications
        • IOS Notifications
        • Windows Notifications
        • Button Templates
      • Predictions
      • Users & Segments
      • Filters
      • A/B Testing
      • Tuning
      • Settings
  • Metrics and Glossary
    • Ad networks metrics
    • Market Metrics
    • Prediction Metrics
    • SDK Metrics
    • Subscription metrics
  • Space Management
  • User Profile Management
  • Limits
  • Scenarios and Best Practices
    • Analytics use cases
    • Match-3
    • MMORPG Games
    • Hyper-Casual games
    • Social Casino
    • RPG games
    • Farming games
    • Non-gaming app
  • FAQ
    • Identification
    • Raw Data
    • All about data discrepancies
  • Slack
Powered by GitBook
On this page
  • Recommended sequence of actions when working with transactions
  • Payment Validation

Was this helpful?

Export as PDF
  1. Integration
  2. Integration of SDK 2.0+
  3. Setting up Events

Anticheat methods

Recommended sequence of actions when working with transactions

  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. If the transaction has not passed verification, do not perform the Payment event.

Payment Validation

The devtodev service allows you to validate transactions to prevent fraud from influencing your statistics. For this, you need to integrate DTDAntiCheat module.

We strongly discourage you from using verification results for deciding on allowing or denying users to receive their purchases! We do not recommend to mark users as cheaters based on the results of this verification! Employ this method exclusively for preventing fraud transaction data from being sent to devtodev!

To validate the transaction you can use the verifyPayment(completionHandler: @escaping (DTDVerifyResponse) -> Void) method immediately during the transaction processing, e.g.:

extension Purchases: SKPaymentTransactionObserver {
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
                case .purchased:
                    DTDAntiCheat.verifyPayment { response in
                            switch response.receiptStatus {
                                case .receiptInternalError: 
                                  // your code
                                  break
                                case .receiptValid:
                                  // your code
                                  break
                                case .receiptSandbox:
                                  // your code
                                  break
                                case .receiptServerError:
                                  // your code
                                  break
                                case .receiptNotValid: 
                                  // your code
                                  break
                                @unknown default: break
                            }
                            SKPaymentQueue.default().finishTransaction(transaction)
                        }

                case .restored:
                    SKPaymentQueue.default().finishTransaction(transaction)

                case .failed:
                    SKPaymentQueue.default().finishTransaction(transaction)

                default:
                    break
            }
        }
    }
}

DTDVerifyResponse

The DTDVerifyResponse object returned while validating the transaction has two properties:

Property

Description

receiptStatus

Enum type DTDReceiptStatus that represents the result of the transaction validation.

verificationResult

Additional information from the validation server.

DTDReceiptStatus

The enum type returned as a result of validation can receive the following values:

Value

Description

receiptValid

The payment is valid, the transaction is genuine.

receiptNotValid

The payment is invalid, the transaction may be a duplicate or fraud.

receiptServerError

Server error when validating the payment.

receiptSandbox

Test payment.

receiptInternalError

Internal SDK error.

We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid or receiptSandbox as a result of the validation.

To validate the transaction you can use the (void)verifyPaymentCompletion:( void (^ _Nonnull)(DTDVerifyResponse * _Nonnull))completionHandler; method immediately during the transaction processing, e.g.:

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    for(SKPaymentTransaction *transaction in transactions) {
        switch(transaction.transactionState){
            case SKPaymentTransactionStatePurchasing: {
                // Your code ...
                break;
            }

            case SKPaymentTransactionStatePurchased: {
                // Your code ...
                [DTDAntiCheat verifyPaymentCompletion:^(DTDVerifyResponse * _Nonnull response) {
                    switch ([response receiptStatus]) {
                        case ReceiptStatusReceiptInternalError: {

                            break;
                        }
                        case ReceiptStatusReceiptValid: {

                            break;
                        }
                        case ReceiptStatusReceiptSandbox: {

                            break;
                        }
                        case ReceiptStatusReceiptServerError: {

                            break;
                        }
                        case ReceiptStatusReceiptNotValid: {

                            break;
                        }
                    }
                }];
                break;
            }

            case SKPaymentTransactionStateRestored: {
                // Your code ...
                break;
            }

            case SKPaymentTransactionStateFailed: {
                // Your code ...
                break;
            }

            case SKPaymentTransactionStateDeferred: {
                // Your code ...
                break;
            }
        }
    }
}

DTDVerifyResponse

The DTDVerifyResponse object returned while validating the transaction has two properties:

Property

Description

receiptStatus

Enum type DTDReceiptStatus that represents the result of the transaction validation.

verificationResult

Additional information from the validation server.

DTDReceiptStatus

The enum type returned as a result of validation can receive the following values:

Value

Description

receiptValid

The payment is valid, the transaction is genuine.

receiptNotValid

The payment is invalid, the transaction may be a duplicate or fraud.

receiptServerError

Server error when validating the payment.

receiptSandbox

Test payment.

receiptInternalError

Internal SDK error.

We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid or receiptSandbox as a result of the validation.

When Google Play sends the transaction back to your onActivityResult, validate it by calling the following method: verifyPayment(receipt: String, signature: String, publicKey: String, completionHandler:(DTDVerifyResponse) -> Unit) immediately during the transaction processing, e.g.:

DTDAntiCheat.verifyPayment(
    receipt = "receipt", 
    signature = "signature", 
    publickKey = "publickKey"
) { dtdVerifyResponse ->
    val verificationResult = dtdVerifyResponse.verificationResult
    /* your code here */
    when (dtdVerifyResponse.receiptStatus) {
        DTDReceiptStatus.ReceiptValid -> { /* your code here */ }
        DTDReceiptStatus.ReceiptNotValid -> { /* your code here */ }
        DTDReceiptStatus.ReceiptServerError -> { /* your code here */ }
        DTDReceiptStatus.ReceiptInternalError -> { /* your code here */ }
    }
}

DTDVerifyResponse

The DTDVerifyResponse object returned while validating the transaction has two properties:

Property

Description

receiptStatus

Enum type DTDReceiptStatus that represents the result of the transaction validation.

verificationResult

Additional information from the validation server.

DTDReceiptStatus

The enum type returned as a result of validation can receive the following values:

Value

Description

receiptValid

The payment is valid, the transaction is genuine.

receiptNotValid

The payment is invalid, the transaction may be a duplicate or fraud.

receiptServerError

Server error when validating the payment.

receiptInternalError

Internal SDK error.

We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid as a result of the validation.

When Google Play sends the transaction back to your onActivityResult, validate it by calling the following method: verifyPayment(receipt: String, signature: String, publicKey: String, completionHandler:(DTDVerifyResponse) -> Unit) immediately during the transaction processing, e.g.:

DTDAntiCheat.INSTANCE.verifyPayment("receipt", "signature", "publickKey",
                dtdVerifyResponse -> {
                // your code
                    switch (dtdVerifyResponse.getReceiptStatus()) {
                        case ReceiptValid:
                            // your code
                            break;
                        case ReceiptNotValid:
                            // your code
                            break;
                        case ReceiptInternalError:
                            // your code
                            break;
                        case ReceiptServerError:
                            // your code
                            break;
                    }
                    return null;
                });

DTDVerifyResponse

The DTDVerifyResponse object returned while validating the transaction has two properties:

Property

Description

receiptStatus

Enum type DTDReceiptStatus that represents the result of the transaction validation.

verificationResult

Additional information from the validation server.

DTDReceiptStatus

The enum type returned as a result of validation can receive the following values:

Value

Description

receiptValid

The payment is valid, the transaction is genuine.

receiptNotValid

The payment is invalid, the transaction may be a duplicate or fraud.

receiptServerError

Server error when validating the payment.

receiptInternalError

Internal SDK error.

We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid as a result of the validation.

Example of verification:

var result = await DTDAntiCheat.VerifyPayment("receipt");
switch (result)
{
    case DTDReceiptStatus.Valid:
        break;
    case DTDReceiptStatus.Invalid:
        break;
    case DTDReceiptStatus.ServerError:
        break;
    case DTDReceiptStatus.InternalError:
        break;
    default:
        throw new ArgumentOutOfRangeException();
}

DTDVerifyResponse

The DTDVerifyResponse object returned while validating the transaction has two properties:

Property

Description

ReceiptStatus

Enum type DTDReceiptStatus that represents the result of the transaction validation.

VerificationResult

Additional information from the validation server.

DTDReceiptStatus

The enum type returned as a result of validation can receive the following values:

Value

Description

Valid = 0L

The payment is valid, the transaction went through successfully

Invalid = 1L

The payment is invalid, the transaction may be a duplicate or fraud

ServerError = 2L

Server error when validating the payment

InternalError = 4L

Internal SDK error

We recommend calling the Real Currency Payment method in all cases except when you receive Invalid as a result of the validation.

Google Play

If you use Unity IAP for payment validation, call the following method: void VerifyPayment(string publicKey, string receipt, Action completionHandler)

Example:

public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
    DTDAntiCheat.VerifyPayment(yourPublicKey, e.purchasedProduct.receipt, result =>
    {
        if (result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptValid ||
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptInternalError || 
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptServerError)
        {
            // Code for valid result.
        }
        else
        {
            // Code for invalid result.
        }
    });
}

To validate data received from Google Play, use void VerifyPayment(string publicKey, string receipt, string signature,Action<DTDVerifyResponse> completionHandler) when handling the transaction.

public void MyNativeCallback (string publicKey, string receipt, string signature)
{
    DTDAntiCheat.VerifyPayment(publicKey, receipt, signature, result =>
    {
        if (result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptValid ||
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptInternalError || 
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptServerError)
        {
            // Code for valid result.
        }
        else
        {
            // Code for invalid result.
        }
    });
}

Here's how to find your app's public key for licensing (for Google Play platform only, for other platforms the publicKey is not used):

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

  2. In the app details page, locate the Services & APIs link and click 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.

App Store

If you use Unity IAP for payment validation, call the following method: void VerifyPayment(string receipt, Action completionHandler)

public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
    DTDAntiCheat.VerifyPayment(e.purchasedProduct.receipt, result =>
    {
        if (result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptValid ||
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptInternalError || 
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptServerError)
        {
            // Code for valid result.
        }
        else
        {
            // Code for invalid result.
        }
    });
}

Windows Store (UWP)

If you use Unity IAP for payment validation, call the following method: void VerifyPayment(string receipt, Action completionHandler)

public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
    DTDAntiCheat.VerifyPayment(e.purchasedProduct.receipt, result =>
    {
        if (result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptValid ||
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptInternalError || 
            result.ReceiptStatus == DTDReceiptVerificationStatus.ReceiptServerError)
        {
            // Code for valid result.
        }
        else
        {
            // Code for invalid result.
        }
    });
}

N.B. You can pass a native XML recipe to the receipt argument.

DTDVerifyResponse

The DTDVerifyResponse object returned while validating the transaction has two properties:

Property

Description

receiptStatus

Enum type DTDReceiptStatus that represents the result of the transaction validation.

verificationResult

Additional information from the validation server.

DTDReceiptStatus

The enum type returned as a result of validation can receive the following values:

Value

Description

receiptValid

The payment is valid, the transaction is genuine.

receiptNotValid

The payment is invalid, the transaction may be a duplicate or fraud.

receiptServerError

Server error when validating the payment.

receiptSandbox

Test payment.

receiptInternalError

Internal SDK error.

We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid or receiptSandbox as a result of the validation.

PreviousUser profileNextTrack sessions

Last updated 1 month ago

Was this helpful?

devtodev sends a request for transaction verification to the payment platform and then forwards the answer to the app. To validate the transaction you can use the Task<DTDReceiptStatus> VerifyPayment(string: receipt) method. As an argument pass the PurchaseResults.ReceiptXml property. More information about it .

here