---
metadata:
  - name: generator
    content: Diplodoc Platform v5.54.4
alternate:
  - https://yandex.com/dev/games/doc/en/sdk/sdk-purchases.md
  - https://yandex.com/dev/games/doc/hi/sdk/sdk-purchases.md
  - https://yandex.com/dev/games/doc/ko/sdk/sdk-purchases.md
  - https://yandex.com/dev/games/doc/ru/sdk/sdk-purchases.md
  - https://yandex.com/dev/games/doc/tr/sdk/sdk-purchases.md
  - https://yandex.com/dev/games/doc/vi/sdk/sdk-purchases.md
  - https://yandex.com/dev/games/doc/zh/sdk/sdk-purchases.md
  - href: vi/sdk/sdk-purchases.md
    type: text/markdown
    title: Markdown version
  - href: ../llms.txt
    type: text/markdown
    title: llms.txt
---
> **Documentation Index:** Fetch the complete configuration index at https://yandex.com/dev/games/doc/vi/llms.txt

# Mua trong game

Bạn có thể tạo doanh thu bằng cách cung cấp cho người dùng tùy chọn mua hàng trong trò chơi. Ví dụ: họ có thể mua thêm thời gian để hoàn thành cấp độ hoặc phụ kiện cho nhân vật của mình. Để làm việc này:

- [Cho phép mua hàng trong trò chơi](https://yandex.com/dev/games/doc/vi/console/purchases.md#connect) trong Bảng điều khiển Yandex Games.
- Đặt cấu hình SDK để làm việc với giao dịch mua hàng.
- Thêm [kiểm tra mua hàng chưa xử lý](#check-purchases).
- [Kiểm tra mua hàng](https://yandex.com/dev/games/doc/vi/console/purchases.md#test).

{% note alert "Chú ý" %}

Bạn chỉ có thể kiểm tra mua hàng sau khi đã kết nối [tiêu thụ của chúng](#check-purchases). Nếu không, những thanh toán chưa xử lý có thể xuất hiện, làm cho việc qua mức kiểm duyệt [không thể](https://yandex.com/dev/games/doc/vi/concepts/requirements.md#1-13-1) được.

{% endnote %}

## Điều kiện {#conditions}

Sau khi bạn thêm thông tin mua hàng và phát hành bản nháp trò chơi, hãy gửi yêu cầu để bật chế độ mua hàng đến [games-partners@yandex-team.com](mailto:games-partners@yandex-team.com). Hãy bao gồm tên và ID trò chơi của bạn trong email.

Sau khi bạn nhận được xác nhận từ [games-partners@yandex-team.com](mailto:games-partners@yandex-team.com) cho biết chế độ mua hàng đã được bật, bạn có thể đặt cấu hình và kiểm tra chúng.

## Khởi tạo {#install}

Để người chơi có thể thực hiện in-app purchases, hãy sử dụng đối tượng `payments`. Bạn có thể:

- Truy cập trực tiếp vào `ysdk.payments`. Các giao dịch mua hàng sẽ được khởi tạo khi gọi lần đầu tiên bất kỳ phương thức nào của đối tượng, vì vậy lần gọi đầu tiên có thể hơi chậm.

- Khởi tạo đối tượng bằng phương thức `ysdk.getPayments()`. Phương thức này sẽ tải trước dữ liệu cần thiết cho các phương thức `payments`, giúp lần gọi đầu tiên không bị chậm.

{% note alert "Hạn chế" %}

Trong `YaGames.init()` và `ysdk.getPayments()`, bạn có thể truyền tham số tùy chọn `signed: boolean` nhằm [bảo vệ chống gian lận](#signature). Giá trị này phụ thuộc vào nơi xử lý thanh toán:

- Nếu xử lý phía client — gọi các phương thức không có tham số hoặc truyền `signed: false`. Các phương thức mua hàng sẽ trả về dữ liệu ở dạng mở.

- Nếu xử lý phía server — truyền `signed: true`. Trong trường hợp này, các phương thức [payments.getPurchases()](#getpurchases) và [payments.purchase()](#payments-purchase) sẽ trả về dữ liệu ở dạng mã hóa trong tham số _signature_.

{% endnote %}

{% list tabs group=purchases %}

- Xử lý phía client

  Khởi tạo với tham số mặc định (`signed: false`).

  **Cách 1: Đơn giản**

  ```javascript
  YaGames.init() // Hoặc YaGames.init({ signed: false }).
      .then(ysdk => {
          // Các phương thức mua hàng có sẵn trong ysdk.payments.
          console.log(ysdk.payments);
      }).catch(err => {
          // [Mua hàng không khả dụng](*key_explanation).
      });
  ```

  **Cách 2: Tải trước qua getPayments()**

  ```javascript
  var payments = null;
  YaGames.init()
      .then(ysdk => {
          ysdk.getPayments()
              .then(_payments => {
                  // Các phương thức mua hàng có sẵn trong payments.
                  payments = _payments;
                  console.log(payments);
              }).catch(err => {
                  // [Mua hàng không khả dụng](*key_explanation).
              });
      });
  ```

- Xử lý phía server

  Khởi tạo với tham số `signed: true`.

  **Cách 1: Khi khởi tạo SDK**

  ```javascript
  YaGames.init({ signed: true }) // Bật chế độ ký tên cho mua hàng.
      .then(ysdk => {
          // Các phương thức mua hàng có sẵn trong ysdk.payments.
          console.log(ysdk.payments);
      }).catch(err => {
          // [Mua hàng không khả dụng](*key_explanation).
      });
  ```

  **Cách 2: Cấu hình chi tiết qua getPayments()**

  ```javascript
  var payments = null;
  YaGames.init()
      .then(ysdk => {
          ysdk.getPayments({ signed: true })
              .then(_payments => {
                  // Các phương thức mua hàng có sẵn trong payments.
                  payments = _payments;
                  console.log(payments);
              }).catch(err => {
                  // [Mua hàng không khả dụng](*key_explanation).
              });
      });
  ```

{% endlist %}

&nbsp; {.empty}

## Kích hoạt quy trình mua hàng {#payments-purchase}

Để kích hoạt mua hàng trong trò chơi, sử dụng phương thức `payments.purchase({ id, developerPayload })`.

- `id: string` — ID sản phẩm được thiết lập trong [Bảng điều khiển trò chơi](https://yandex.com/dev/games/doc/vi/console/purchases.md#connect).
- `developerPayload: string` — Tham số tùy chọn. Dữ liệu mua bổ sung mà bạn muốn gửi đến máy chủ của mình (được truyền trong tham số [signature](*key_sign) ).

Phương thức mở một khung với cổng thanh toán.

{% list tabs group=purchases %}

- Xử lý trên client

  [Khởi tạo](#install) với tham số mặc định (`signed: false`).

  Trả về `Promise<Purchase>`

  `Purchase: object` — bao gồm chi tiết mua hàng. Đối tượng này chứa các thuộc tính sau:
  - `productID: string` — ID sản phẩm.
  - `purchaseToken: string` — mã thông báo cho [việc tiêu thụ giao dịch mua hàng](#consumepurchase).
  - `developerPayload: string` — dữ liệu mua hàng bổ sung.

- Xử lý trên server

  [Khởi tạo](#install) với tham số `signed: true`.

  Trả về `Promise<{ signature }>`.

  `signature: string` — dữ liệu mua hàng đã được mã hóa và chữ ký để [kiểm tra tính xác thực của người chơi](#purchase-data-example).

{% endlist %}

Sau khi người chơi mua hàng thành công, `Promise` sẽ chuyển sang trạng thái "đã giải quyết". Nếu người chơi không mua hàng và đóng cửa sổ, trạng thái `Promise` sẽ trở thành "bị từ chối".

{% note alert "Chú ý" %}

Kết nối internet không ổn định có thể khiến trò chơi không đăng ký được các giao dịch mua hàng thành công. Để tránh điều này, hãy sử dụng các phương thức được mô tả trong các phần [Kiểm tra các giao dịch mua hàng chưa được xử lý](#check-purchases) và [Xử lý giao dịch mua hàng và ghi có số tiền trong trò chơi](#consumepurchase).

Việc không làm theo các hướng dẫn này có thể dẫn đến việc tắt chế độ mua hàng trong ứng dụng hoặc hủy phát hành ứng dụng.

{% endnote %}

Người dùng có thể thực hiện mua hàng mà không cần đăng nhập, nhưng chúng tôi khuyên bạn nên đề xuất họ [đăng nhập vào tài khoản](https://yandex.com/dev/games/doc/vi/sdk/sdk-player.md#open-auth-dialog) trước hoặc trong khi thực hiện mua hàng.

#### Ví dụ

Tổng quát:

```javascript
[payments](*key_payments).purchase({ [id](*key_id): 'gold500' })
    .then(purchase => {
        // Mua hàng thành công!
    }).catch(err => {
        // Mua hàng không thành công: không có sản phẩm nào có id này tồn tại trong Bảng điều khiển trò chơi,
        // người dùng không đăng nhập, thay đổi ý định và đóng cửa sổ thanh toán,
        // việc mua hàng đã hết thời gian chờ, không có đủ tiền hoặc vì bất kỳ lý do nào khác.
    });
```

Sử dụng tham số tùy chọn `developerPayload`:

```javascript
[payments](*key_payments).purchase({ [id](*key_id): 'gold500', [developerPayload](*key_developerPayload): '{serverId:42}' })
    .then(purchase => {
        // purchase.developerPayload === '{serverId:42}'
    });
```

## Lấy danh sách các mặt hàng đã mua {#getpurchases}

Sử dụng phương thức `payments.getPurchases()` để:

- biết những mua hàng nào người chơi đã thực hiện;

- kiểm tra sự tồn tại của [các mua hàng chưa được xử lý](#check-purchases);

- xử lý các mua hàng vĩnh viễn.

{% list tabs group=purchases %}

- Xử lý trên client

  [Khởi tạo](#install) với tham số mặc định (`signed: false`).

  Trả về `Promise<Purchase[]>`.

  `Purchase[]: array` — danh sách các giao dịch mua hàng do người chơi thực hiện. Mỗi `Purchase` mua sắm có các thuộc tính sau:
  - `productID: string` — ID sản phẩm.
  - `purchaseToken: string` — mã thông báo cho [việc tiêu thụ giao dịch mua hàng](#consumepurchase).
  - `developerPayload: string` — dữ liệu mua hàng bổ sung.

  **Ví dụ**

  ```javascript
  var SHOW_ADS = true;
  [payments](*key_payments).getPurchases()
      .then(purchases => {
          if (purchases.some(purchase => purchase.productID === 'disable_ads')) {
            SHOW_ADS = false;
          }
      }).catch(err => {
          // Trả về lỗi USER_NOT_AUTHORIZED đối với người dùng chưa đăng nhập.
      });
  ```

- Xử lý trên server

  [Khởi tạo](#install) với tham số `signed: true`.

  Trả về `Promise<{ signature }>`.

  `signature: string` — dữ liệu mua hàng đã được mã hóa và chữ ký để [kiểm tra tính xác thực của người chơi](#purchase-data-example).

  **Ví dụ**

  ```javascript
  [payments](*key_payments).getPurchases()
    .then(purchases => {
        fetch('https://your.game.server?purchase', {
            method: 'POST',
            headers: { 'Content-Type': 'text/plain' },
            body: purchases.signature
        });
    });
  ```

{% endlist %}

&nbsp; {.empty}

## Lấy danh mục tất cả các sản phẩm {#getcatalog}

Để lấy danh sách các mua hàng có sẵn và giá của chúng, hãy sử dụng phương thức `payments.getCatalog()`.

Phương thức trả về `Promise<Product[]>`.

`Product[]: array` — danh sách các sản phẩm có sẵn cho người dùng. Danh sách này được tạo từ bảng trong **In-app purchases** của Bảng điều khiển trò chơi. Mỗi `Product` chứa các thuộc tính sau:
- `id: string` — ID sản phẩm.
- `title: string` — tên sản phẩm.
- `description: string` — mô tả sản phẩm.
- `imageURI: string` — URL hình ảnh.
- `price: string` — giá sản phẩm ở định dạng `<price> <currency code>`.
- `priceValue: string` — Giá sản phẩm ở định dạng `<price>`.
- `priceCurrencyCode: string` — Mã tiền tệ.

`Product.getPriceCurrencyImage(size)` — phương thức lấy địa chỉ của biểu tượng tiền tệ.

- `size: string` — tham số tùy chọn. Các giá trị có thể có:

    - `small` (mặc định) — lấy biểu tượng nhỏ.

    - `medium` — lấy biểu tượng kích cỡ vừa.

    - `svg` — lấy biểu tượng dạng vector.

Phương pháp này trả về `string` — địa chỉ biểu tượng, ví dụ `//yastatic.net/s3/games-static/static-data/images/payments/sdk/currency-icon-s@2x.png`.

#### Ví dụ

```javascript
var gameShop = []
[payments](*key_payments).getCatalog()
    .then(products => {
        gameShop = products;
    });
```

## Hiển thị đơn vị tiền tệ của cổng thông tin {#currency-designation}

Để hiển thị tên và biểu tượng đơn vị tiền tệ của cổng thông tin trong trò chơi, hãy sử dụng các tính năng của SDK:

- `Product.price` (string): Giá cùng với mã tiền tệ.
- `Product.priceCurrencyCode` (string): Mã tiền tệ.
- `Product.getPriceCurrencyImage()` (string): URL của biểu tượng tiền tệ.

Để biết thêm chi tiết về đối tượng `Product`, hãy xem [Lấy danh mục của tất cả các sản phẩm](#getcatalog).

## Xử lý giao dịch mua hàng và ghi có số tiền trong trò chơi {#consumepurchase}

Có hai loại giao dịch mua hàng: hàng không tiêu hao (chẳng hạn như để tắt quảng cáo) và hàng tiêu hao (chẳng hạn như để mua tiền trong trò chơi).

Để xử lý các giao dịch mua hàng không tiêu hao, hãy sử dụng phương thức [payments.getPurchases()](#getpurchases).

Để xử lý các giao dịch mua hàng tiêu hao, hãy sử dụng phương thức `payments.consumePurchase()`.

#### payments.consumePurchase()

Phương thức trả về `Promise` ở trạng thái "đã giải quyết" (nếu quá trình xử lý thành công) hoặc trạng thái "bị từ chối" (nếu xảy ra lỗi).


{% note alert "Chú ý" %}

Sau khi gọi phương thức `payments.consumePurchase()`, giao dịch mua hàng đã xử lý sẽ bị xóa vĩnh viễn. Để thực hiện việc này, trước tiên bạn nên sửa đổi dữ liệu người chơi thông qua phương thức [player.setStats()](https://yandex.com/dev/games/doc/vi/sdk/sdk-player.md#ingame-data) hoặc [player.incrementStats()](https://yandex.com/dev/games/doc/vi/sdk/sdk-player.md#ingame-data) và sau đó xử lý giao dịch mua hàng.

{% endnote %}

#### Ví dụ

```javascript
[payments](*key_payments).purchase({ id: 'gold500' })
    .then(purchase => {
        // Mua hàng thành công!
        // Thêm 500 đồng vàng vào tài khoản và tiêu hao giao dịch mua hàng.
        addGold(500).then(() => payments.consumePurchase(purchase.[purchaseToken](*key_purchaseToken)));
    });

function addGold(value) {
    return player.incrementStats({ gold: value });
    // Để tìm hiểu thêm, hãy xem dữ liệu Player.
}
```

`purchaseToken: string` — mã thông báo được trả về từ các phương thức [payments.purchase()](#payments-purchase) và [payments.getPurchases()](#getpurchases).

## Kiểm tra các giao dịch mua hàng chưa được xử lý {#check-purchases}

Nếu người dùng mất kết nối internet khi mua hàng trong trò chơi hoặc máy chủ của bạn không hoạt đọng, giao dịch mua hàng có thể vẫn chưa được xử lý. Để tránh điều này, hãy kiểm tra các giao dịch mua hàng chưa được xử lý bằng phương thức [payments.getPurchases()](#getpurchases) (ví dụ: mỗi lần trò chơi khởi động).

{% note alert "Chú ý" %}

Trước khi thêm mua sắm, hãy thiết lập kiểm tra các thanh toán chưa xử lý.

Việc kiểm tra này [là bắt buộc](https://yandex.com/dev/games/doc/vi/concepts/requirements.md#1-13-1) để vượt qua quá trình kiểm duyệt, vì vậy hãy thiết lập nó ngay cả đối với các giao dịch mua hàng thử nghiệm. Nếu thêm mua sắm vào trò chơi và kiểm thử chúng trước khi thiết lập tiêu thụ, sau các bài kiểm thử có thể còn lại các giao dịch chưa được xử lý, điều này sẽ làm quá trình kiểm duyệt không thể thực hiện được.

{% endnote %}

{% list tabs group=purchases %}

- Xử lý trên client

  [Khởi tạo](#install) với tham số mặc định (`signed: false`).

  **Ví dụ**

  ```javascript
  [payments](*key_payments).getPurchases().then(purchases => purchases.forEach(consumePurchase));

  function consumePurchase(purchase) {
      if (purchase.productID === 'gold500') {
          player.incrementStats({ gold: 500 })
              .then(() => {
                  payments.consumePurchase(purchase.purchaseToken)
              });
      }
  }
  ```

- Xử lý trên server

  [Khởi tạo](#install) với tham số `signed: true`.

  **Ví dụ**

  ```javascript
  [payments](*key_payments).getPurchases()
      .then(purchases => {
          fetch('https://your.game.server?purchase', {
              method: 'POST',
              headers: { 'Content-Type': 'text/plain' },
              body: purchases.signature
          });
      });
  ```

{% endlist %}

&nbsp; {.empty}


## Phòng chống gian lận {#signature}

Để bảo vệ bản thân khỏi khả năng tăng số liệu trong game một cách không chính thống, hãy xử lý mua hàng trên server:

1. Khởi tạo `YaGames.init()` hoặc `ysdk.getPayments()` với tham số `{ signed: true }`.
2. Chuyển chữ ký đã nhận trong các phản hồi từ [payments.purchase()](#payments-purchase) và [payments.getPurchases()](#getpurchases) lên server của bạn, và giải mã nó bằng khóa bí mật.
3. Trên server của mình, cộng dồn các vật phẩm mà người chơi đã nhận được trong game.


```javascript
// Đảm bảo rằng các giao dịch mua hàng được khởi tạo bằng tham số { signed: true }

[payments](*key_payments).purchase({ id: 'gold500' })
    .then(purchase => {
        // Mua hàng thành công!
        // Thêm 500 đồng vàng trên máy chủ...
        serverPurchase(purchase.signature); // Kiểm tra chữ ký và cộng dữ liệu cho người chơi.
    });

function serverPurchase(signature) {
    return fetch('https://your.game.server?purchase', {
            method: 'POST',
            headers: { 'Content-Type': 'text/plain' },
            body: signature
        });
}
```

Tham số `signature` của yêu cầu được gửi đến máy chủ chứa dữ liệu mua hàng và chữ ký. Đó là hai chuỗi mã hóa `base64`: `<signature>.<JSON with the purchase data>`.

#### Ví dụ về chữ ký

```text
hQ8adIRJWD29Nep+0P36Z6edI5uzj6F3tddz6Dqgclk=.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZEF0IjoxNTcxMjMzMzcxLCJyZXF1ZXN0UGF5bG9hZCI6InF3ZSIsImRhdGEiOnsidG9rZW4iOiJkODVhZTBiMS05MTY2LTRmYmItYmIzOC02ZDJhNGNhNDQxNmQiLCJzdGF0dXMiOiJ3YWl0aW5nIiwiZXJyb3JDb2RlIjoiIiwiZXJyb3JEZXNjcmlwdGlvbiI6IiIsInVybCI6Imh0dHBzOi8veWFuZGV4LnJ1L2dhbWVzL3Nkay9wYXltZW50cy90cnVzdC1mYWtlLmh0bWwiLCJwcm9kdWN0Ijp7ImlkIjoibm9hZHMiLCJ0aXRsZSI6ItCR0LXQtyDRgNC10LrQu9Cw0LzRiyIsImRlc2NyaXB0aW9uIjoi0J7RgtC60LvRjtGH0LjRgtGMINGA0LXQutC70LDQvNGDINCyINC40LPRgNC1IiwicHJpY2UiOnsiY29kZSI6IlJVUiIsInZhbHVlIjoiNDkifSwiaW1hZ2VQcmVmaXgiOiJodHRwczovL2F2YXRhcnMubWRzLnlhbmRleC5uZXQvZ2V0LWdhbWVzLzE4OTI5OTUvMmEwMDAwMDE2ZDFjMTcxN2JkN2EwMTQ5Y2NhZGM4NjA3OGExLyJ9fX0=
```

#### Ví dụ về dữ liệu mua hàng được truyền đi (ở định dạng `JSON`) {#purchase-data-example}

Lưu ý rằng định dạng dữ liệu của tham số `signature` được sử dụng trong hàm `serverPurchase (signature)` khác với định dạng được sử dụng trong phương thức [payments.getPurchases()](#getpurchases).

Trong phương thức `payments.getPurchases()`, tham số `signature` chứa một mảng các đối tượng giao dịch mua hàng trong trường `data`. Trong hàm `serverPurchase(signature)`, đó là đối tượng purchase.

```json
{
  "algorithm": "HMAC-SHA256",
  "issuedAt": 1571233371,
  "requestPayload": "qwe",
  "data": {
    "token": "d85ae0b1-9166-4fbb-bb38-6d2a4ca4416d",
    "status": "waiting",
    "errorCode": "",
    "errorDescription": "",
    "url": "https://yandex.ru/games/sdk/payments/trust-fake.html",
    "product": {
      "id": "noads",
      "title": "Không có quảng cáo",
      "description": "Tắt quảng cáo trong trò chơi",
      "price": {
        "code": "YAN",
        "value": "49"
      },
      "imagePrefix": "https://avatars.mds.yandex.net/get-games/1892995/2a0000016d1c1717bd7a0149ccadc86078a1/"
    },
    "developerPayload": "KIỂM TRA PAYLOAD CỦA NHÀ PHÁT TRIỂN"
  }
}
```

#### Ví dụ về khóa bí mật

`t0p$ecret`

Khóa bí mật để xác minh chữ ký là duy nhất cho trò chơi. Khóa được tạo tự động khi tạo giao dịch mua hàng trong Bảng điều khiển trò chơi. Bạn có thể tìm thấy khóa trong bảng giao dịch mua hàng.

#### Ví dụ về xác minh chữ ký trên máy chủ

{% list tabs %}

* Python 3

   ```python
   import hashlib
   import hmac
   import base64
   import json

   usedTokens = {}

   key = 't0p$ecret' # Giữ khóa secret.
   secret = bytes(key, 'utf-8')
   signature = 'hQ8adIRJWD29Nep+0P36Z6edI5uzj6F3tddz6Dqgclk=.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZEF0IjoxNTcxMjMzMzcxLCJyZXF1ZXN0UGF5bG9hZCI6InF3ZSIsImRhdGEiOnsidG9rZW4iOiJkODVhZTBiMS05MTY2LTRmYmItYmIzOC02ZDJhNGNhNDQxNmQiLCJzdGF0dXMiOiJ3YWl0aW5nIiwiZXJyb3JDb2RlIjoiIiwiZXJyb3JEZXNjcmlwdGlvbiI6IiIsInVybCI6Imh0dHBzOi8veWFuZGV4LnJ1L2dhbWVzL3Nkay9wYXltZW50cy90cnVzdC1mYWtlLmh0bWwiLCJwcm9kdWN0Ijp7ImlkIjoibm9hZHMiLCJ0aXRsZSI6ItCR0LXQtyDRgNC10LrQu9Cw0LzRiyIsImRlc2NyaXB0aW9uIjoi0J7RgtC60LvRjtGH0LjRgtGMINGA0LXQutC70LDQvNGDINCyINC40LPRgNC1IiwicHJpY2UiOnsiY29kZSI6IlJVUiIsInZhbHVlIjoiNDkifSwiaW1hZ2VQcmVmaXgiOiJodHRwczovL2F2YXRhcnMubWRzLnlhbmRleC5uZXQvZ2V0LWdhbWVzLzE4OTI5OTUvMmEwMDAwMDE2ZDFjMTcxN2JkN2EwMTQ5Y2NhZGM4NjA3OGExLyJ9fX0='

   sign, data = signature.split('.')
   message = base64.b64decode(data)

   purchaseData = json.loads(message)
   result = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
   if result.decode('utf-8') == sign:
     print('Kiểm tra chữ ký ok!')

     if not purchaseData['data']['token'] in usedTokens:
       usedTokens[purchaseData['data']['token']] = True; # Sử dụng cơ sở dữ liệu.
       print('Kiểm tra chi tiêu gấp đôi ok!')

       print('Áp dụng giao dịch mua hàng:', purchaseData['data']['product'])
       # Bạn có thể áp dụng mua hàng một cách an toàn tại đây.
   ```

* Node.js

   ```javascript
   const crypto = require('crypto');

   const usedTokens = {};

   const key = 't0p$ecret'; // Giữ khóa secret.
   const signature = 'hQ8adIRJWD29Nep+0P36Z6edI5uzj6F3tddz6Dqgclk=.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZEF0IjoxNTcxMjMzMzcxLCJyZXF1ZXN0UGF5bG9hZCI6InF3ZSIsImRhdGEiOnsidG9rZW4iOiJkODVhZTBiMS05MTY2LTRmYmItYmIzOC02ZDJhNGNhNDQxNmQiLCJzdGF0dXMiOiJ3YWl0aW5nIiwiZXJyb3JDb2RlIjoiIiwiZXJyb3JEZXNjcmlwdGlvbiI6IiIsInVybCI6Imh0dHBzOi8veWFuZGV4LnJ1L2dhbWVzL3Nkay9wYXltZW50cy90cnVzdC1mYWtlLmh0bWwiLCJwcm9kdWN0Ijp7ImlkIjoibm9hZHMiLCJ0aXRsZSI6ItCR0LXQtyDRgNC10LrQu9Cw0LzRiyIsImRlc2NyaXB0aW9uIjoi0J7RgtC60LvRjtGH0LjRgtGMINGA0LXQutC70LDQvNGDINCyINC40LPRgNC1IiwicHJpY2UiOnsiY29kZSI6IlJVUiIsInZhbHVlIjoiNDkifSwiaW1hZ2VQcmVmaXgiOiJodHRwczovL2F2YXRhcnMubWRzLnlhbmRleC5uZXQvZ2V0LWdhbWVzLzE4OTI5OTUvMmEwMDAwMDE2ZDFjMTcxN2JkN2EwMTQ5Y2NhZGM4NjA3OGExLyJ9fX0=';

   const [sign, data] = signature.split('.');
   const purchaseDataString = Buffer.from(data, 'base64').toString('utf8');
   const hmac = crypto.createHmac('sha256', key);

   hmac.update(purchaseDataString);

   const purchaseData = JSON.parse(purchaseDataString);

   if (sign === hmac.digest('base64')) {
     console.log('Kiểm tra chữ ký ok!');

     if (!usedTokens[purchaseData.data.token]) {
       usedTokens[purchaseData.data.token] = true; // Sử dụng cơ sở dữ liệu.
       console.log('Kiểm tra chi tiêu gấp đôi ok!');

       console.log('Áp dụng mua hàng:', purchaseData.data.product);
       // Bạn có thể áp dụng mua hàng một cách an toàn tại đây.
     }
   }
   ```

{% endlist %}

---

<!-- source: vi/_includes/concepts/troubleshooting/id-troubleshooting/support.md -->
{% note info "Ghi chú" %}

Nhân viên hỗ trợ sẽ giúp bạn đăng bài trò chơi đã hoàn thiện lên nền tảng trò chơi của Yandex. Để đặt các câu hỏi về việc phát triển và kiểm thử, các nhà phát triển khác sẽ trả lời chuyên sâu trong [Kênh Discord](https://discord.com/invite/wU4p3whr4T).

{% endnote %}
<!-- endsource: vi/_includes/concepts/troubleshooting/id-troubleshooting/support.md -->

<!-- source: vi/_includes/button-fos.md -->
Nếu bạn đang gặp phải vấn đề hoặc có câu hỏi liên quan đến việc sử dụng Yandex Games SDK, vui lòng liên hệ với bộ phận hỗ trợ:


<a href="https://yandex.com/chat/#/user/a4fa5c06-75db-9b38-6eea-b1673785f7d5">
  <span class="button">Viết trong mục trò chuyện</span>
</a>
<!-- endsource: vi/_includes/button-fos.md -->

[*key_id]: `id: string` — ID sản phẩm được thiết lập trong [Bảng điều khiển trò chơi](https://yandex.com/dev/games/doc/vi/console/purchases.md#connect).

[*key_developerPayload]: `developerPayload: string` — tham số tùy chọn. Dữ liệu mua hàng bổ sung mà bạn muốn gửi đến máy chủ của mình (được truyền trong tham số `signature`).

[*key_sign]: Tham số `signature` trong yêu cầu được gửi đến máy chủ chứa dữ liệu mua hàng và chữ ký. Đó là hai chuỗi mã hóa `base64`: `<signature>.<JSON with the purchase data>`.

[*key_purchaseToken]: `purchaseToken: string` — mã thông báo được trả về từ các phương thức [payments.purchase()](#payments-purchase) và [payments.getPurchases()](#getpurchases).

[*key_payments]: Truy cập trực tiếp vào `ysdk.payments` nếu bạn chưa khởi tạo giao dịch mua hàng bằng `ysdk.getPayments()`.

[*key_explanation]: - [Kích hoạt tính năng kiếm tiền](https://yandex.com/dev/games/doc/vi/console/purchases.md#connect).
- Trong [Bảng Điều Khiển của nhà phát triển](https://games.yandex.com/console), chuyển đến tab **In-app purchases** và đảm bảo rằng:
    - Có ít nhất một bảng chứa mặt hàng trong game.
    - Hiển thị dòng chữ **Purchases are enabled**.