---
metadata:
  - name: generator
    content: Diplodoc Platform v5.52.0
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: ko/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/ko/llms.txt

# 게임 내 구매

사용자에게 게임 내 구매 옵션을 제공하여 수익을 올릴 수 있습니다. 예를 들어, 레벨을 완료하는 데 필요한 추가 시간이나 캐릭터의 액세서리를 구매할 수 있습니다. 이렇게 하려면 다음과 같이 하세요.

- Yandex Games 개발자 대시보드에서 [게임 내 구매를 활성화](https://yandex.com/dev/games/doc/ko/console/purchases.md#connect)합니다.
- 구매와 함께 작동하도록 SDK를 구성합니다.
- [미처리된 구매 검사](#check-purchases)를 추가하세요.
- [구매 테스트](https://yandex.com/dev/games/doc/ko/console/purchases.md#test)를 하세요.

{% note alert "알림" %}

구매를 테스트하는 것은 그들의 [소비](#check-purchases)를 연결한 후에만 가능합니다. 그렇지 않으면 처리되지 않은 결제가 발생할 수 있으며, 이는 [심사를 통과하는 것을](https://yandex.com/dev/games/doc/ko/concepts/requirements.md#1-13-1) 불가능하게 만들 수 있습니다.

{% endnote %}

## 조건 {#conditions}

게임 드래프트를 추가하고 발행한 후에는 구매 연결 요청을 포함한 이메일을 [games-partners@yandex-team.com](mailto:games-partners@yandex-team.com)로 보내주시기 바랍니다. 이메일에는 반드시 게임의 이름과 식별자(ID)를 명시해 주세요.

[games-partners@yandex-team.com](mailto:games-partners@yandex-team.com)에서 구매가 허용되었다는 확인 회신을 받은 후에, 구매 설정 및 테스트를 진행할 수 있습니다.

## 초기화 {#install}

플레이어가 인앱 구매를 할 수 있도록 하려면 `payments` 객체를 사용하세요. 다음과 같은 방법으로 사용할 수 있습니다:

- 직접 `ysdk.payments`에 접근할 수 있습니다. 결제 관련 메서드가 처음 호출될 때 초기화되므로 첫 호출은 약간 느릴 수 있습니다.

- `ysdk.getPayments()` 메서드를 사용하여 객체를 초기화할 수 있습니다. 이 방법은 `payments` 메서드에 필요한 데이터를 미리 로드하므로 첫 호출 시 지연이 발생하지 않습니다.

{% note alert "제한" %}

`YaGames.init()`과 `ysdk.getPayments()`에는 선택적 매개변수 `signed: boolean`을 전달할 수 있으며, 이는 [사기 방지](#signature)를 위한 목적으로 사용됩니다. 이 값의 선택은 결제 처리가 어디에서 이루어지는지에 따라 달라집니다:

- 클라이언트 측에서 처리하는 경우 — 매개변수 없이 메서드를 호출하거나 `signed: false`를 전달하세요. 결제 메서드는 데이터를 공개된 형태로 반환합니다.

- 서버 측에서 처리하는 경우 — `signed: true`를 전달하세요. 이 경우 [payments.getPurchases()](#getpurchases)와 [payments.purchase()](#payments-purchase) 메서드의 응답에서 모든 데이터는 `_signature` 매개변수에 암호화된 형태로만 반환됩니다.

{% endnote %}

{% list tabs group=purchases %}

- 클라이언트 측 처리

  기본값(`signed: false`)으로 초기화합니다.

  **방법 1: 간편한 방법**

  ```javascript
  YaGames.init() // 또는 YaGames.init({ signed: false }).
      .then(ysdk => {
          // 결제 메서드는 ysdk.payments에서 사용할 수 있습니다.
          console.log(ysdk.payments);
      }).catch(err => {
          // [결제를 사용할 수 없음](*key_explanation).
      });
  ```

  **방법 2: getPayments()를 통한 사전 로드**

  ```javascript
  var payments = null;
  YaGames.init()
      .then(ysdk => {
          ysdk.getPayments()
              .then(_payments => {
                  // 결제 메서드는 payments에서 사용할 수 있습니다.
                  payments = _payments;
                  console.log(payments);
              }).catch(err => {
                  // [결제를 사용할 수 없음](*key_explanation).
              });
      });
  ```

- 서버 측 처리

  `signed: true` 매개변수로 초기화합니다.

  **방법 1: SDK 초기화 시**

  ```javascript
  YaGames.init({ signed: true }) // 결제에 대한 서명 작업을 활성화합니다.
      .then(ysdk => {
          // 결제 메서드는 ysdk.payments에서 사용할 수 있습니다.
          console.log(ysdk.payments);
      }).catch(err => {
          // [결제를 사용할 수 없음](*key_explanation).
      });
  ```

  **방법 2: getPayments()를 통한 세부 설정**

  ```javascript
  var payments = null;
  YaGames.init()
      .then(ysdk => {
          ysdk.getPayments({ signed: true })
              .then(_payments => {
                  // 결제 메서드는 payments에서 사용할 수 있습니다.
                  payments = _payments;
                  console.log(payments);
              }).catch(err => {
                  // [결제를 사용할 수 없음](*key_explanation).
              });
      });
  ```

{% endlist %}

&nbsp; {.empty}

## 구매 프로세스 활성화 {#payments-purchase}

게임 내 구매를 활성화하려면 `payments.purchase({ id, developerPayload })` 메서드를 사용하세요.

- `id: string` — [개발자 대시보드](https://yandex.com/dev/games/doc/ko/console/purchases.md#connect)에 설정된 제품 ID입니다.
- `developerPayload: string` — 선택적 파라미터. 서버로 전송할 추가 구매 데이터([signature](*key_sign) 파라미터로 전송됨).

이 메소드는 결제 게이트웨이를 여는 프레임을 엽니다.

{% list tabs group=purchases %}

- 클라이언트에서의 처리

  [초기화](#install) 기본 매개변수(`signed: false`)를 사용하여.

  `Promise<Purchase>`를 반환합니다.

  `Purchase: object` — 구매에 대한 정보. 다음 속성을 포함합니다:
  - `productID: string` — 제품 ID.
  - `purchaseToken: string` — 구매자에게 [구매](#consumepurchase)를 사용할 수 있는 권한을 부여하는 토큰입니다.
  - `developerPayload: string` — 추가 구매 데이터.

- 서버에서 처리

  [초기화](#install) 매개변수 `signed: true`를 사용하여.

  `Promise<{ signature }>`를 반환합니다.

  `signature: string` — 구매 데이터 및 [플레이어 인증](#purchase-data-example)을 위한 서명.

{% endlist %}

플레이어가 구매에 성공하면 `Promise`은 "해결됨" 상태로 전환됩니다. 플레이어가 구매를 하지 않고 창을 닫은 경우, `Promise` 상태는 "거부됨"이 됩니다.


{% note alert "알림" %}

인터넷 연결이 불안정할 경우, 플레이어가 구매를 진행했지만 게임에 등록되지 않는 상황이 발생할 수 있습니다. 이를 방지하기 위해 [미처리 구매 확인](#check-purchases) 및 [구매 처리 및 게임 내 재화 적립](#consumepurchase)에 설명된 방법을 사용하여 구매를 처리해 주세요.

이 지침을 따르지 않으면 앱의 게임 내 구매가 비활성화되거나 목록에서 삭제될 수 있습니다.

{% endnote %}

사용자는 인증 없이 구매할 수 있지만, 사전에 [계정 로그인](https://yandex.com/dev/games/doc/ko/sdk/sdk-player.md#open-auth-dialog)을 권장합니다.

#### 예시

일반:

```javascript
[payments](*key_payments).purchase({ [id](*key_id): 'gold500' })
    .then(purchase => {
        // 구매 성공!
    }).catch(err => {
        // 구매 실패: 개발자 대시보드에 이 ID의 제품이 존재하지 않습니다.
        // 사용자가 로그인하지 않았거나 마음이 바뀌어 결제 창을 닫았습니다.
        // 구매 시간이 초과되었거나, 자금이 부족하거나, 기타 다른 이유가 있습니다.
    });
```

선택적 파라미터인 `developerPayload`를 사용합니다.

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

## 구매한 아이템 목록 가져오기 {#getpurchases}

`payments.getPurchases()` 메서드를 사용하여:

- 플레이어가 이미 한 구매를 확인하십시오;

- [미처리 구매](#check-purchases)의 존재를 확인하십시오;

- 지속적인 구매를 처리하십시오.

{% list tabs group=purchases %}

- 클라이언트에서의 처리

  [초기화](#install) 기본 매개변수(`signed: false`)를 사용하여.

  `Promise<Purchase[]>`를 반환합니다.

  `Purchase[]: array` — 플레이어가 한 구매 목록입니다. 각 구매 `Purchase`는 다음 속성을 포함합니다:
  - `productID: string` — 제품 ID.
  - `purchaseToken: string` — 구매자에게 [구매](#consumepurchase)를 사용할 수 있는 권한을 부여하는 토큰입니다.
  - `developerPayload: string` — 추가 구매 데이터.

  **예시**

  ```javascript
  var SHOW_ADS = true;
  [payments](*key_payments).getPurchases()
      .then(purchases => {
          if (purchases.some(purchase => purchase.productID === 'disable_ads')) {
            SHOW_ADS = false;
          }
      }).catch(err => {
          // 로그오프한 사용자에 대해 USER_NOT_AUTHORIZED 예외가 발생합니다.
      });
  ```

- 서버에서 처리

  [초기화](#install) 매개변수 `signed: true`를 사용하여.

  `Promise<{ signature }>`를 반환합니다.

  `signature: string` — 구매 데이터 및 [플레이어 인증](#purchase-data-example)을 위한 서명.

  **예시**

  ```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}

## 모든 제품 카탈로그 가져오기 {#getcatalog}

사용 가능한 구매 목록과 해당 비용을 가져오려면 `payments.getCatalog()` 메서드를 사용합니다.

이 메서드는 `Promise<Product[]>`를 반환합니다.

`Product[]: array` — 사용자가 사용할 수 있는 제품 목록입니다. 개발자 대시보드의 **In-app purchases** 탭에 있는 표를 기반으로 생성됩니다. 각 `Product`에는 속성이 있습니다:
- `id: string` — 제품 ID.
- `title: string` — 제품 이름.
- `description: string` — 제품 설명.
- `imageURI: string` — 제품 이미지의 URL.
- `price: string` — `<price> <currency code>` 형식의 제품 가격입니다.
- `priceValue: string` — `<price>` 형식의 제품 가격입니다.
- `priceCurrencyCode: string` — 통화 코드.

`Product.getPriceCurrencyImage(size)` — 화폐 아이콘 주소 획득 방법.

- `size: string` — 선택 사항입니다. 가능한 값:

    - `small` (기본값) — 작은 아이콘을 받아옵니다.

    - `medium` — 중간 크기 아이콘 가져오기.

    - `svg` — 벡터 아이콘 반환.

이 방법은 `string`을 반환합니다 — 아이콘 주소, 예를 들면 `//yastatic.net/s3/games-static/static-data/images/payments/sdk/currency-icon-s@2x.png`.

#### 예시

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

## 포털 화폐의 표시 {#currency-designation}

게임 내에서 포털 화폐의 이름과 아이콘을 표시하기 위해 SDK의 기능을 사용하세요:

- `Product.price: string` — 화폐 코드가 포함된 가격.
- `Product.priceCurrencyCode: string` — 화폐 코드.
- `Product.getPriceCurrencyImage()`는 `string`을 반환 — 화폐 아이콘의 주소.

`Product` 객체에 대한 자세한 내용은 [모든 상품 카탈로그 받기](#getcatalog) 섹션을 참조하세요.


## 구매 처리 및 게임 내 통화 적립하기 {#consumepurchase}

구매에는 영구 구매(예: 광고 비활성화)와 소모성 구매(예: 게임 내 화폐)의 두 가지 유형이 있습니다.

영구 구매를 처리하려면 [payments.getPurchases()](#getpurchases) 메서드를 사용합니다.

소모성 구매를 처리하려면 `payments.consumePurchase()` 메서드를 사용합니다.

#### payments.consumePurchase()

이 메서드는 "해결됨" 상태(처리가 성공한 경우) 또는 "거부됨" 상태(오류가 발생한 경우)의 `Promise`를 반환합니다.


{% note alert "알림" %}

`payments.consumePurchase()` 메서드를 호출하면 처리된 구매는 영구 삭제됩니다. 따라서 먼저 [player.setStats()](https://yandex.com/dev/games/doc/ko/sdk/sdk-player.md#ingame-data) 또는 [player.incrementStats()](https://yandex.com/dev/games/doc/ko/sdk/sdk-player.md#ingame-data) 메서드를 사용하여 플레이어 데이터를 수정한 후 구매를 처리해야 합니다.

{% endnote %}

#### 예시

```javascript
[payments](*key_payments).purchase({ id: 'gold500' })
    .then(purchase => {
        // 구매 성공!
        // 계정에 500 골드를 추가하고 구매를 사용합니다.
        addGold(500).then(() => payments.consumePurchase(purchase.[purchaseToken](*key_purchaseToken)));
    });

function addGold(value) {
    return player.incrementStats({ gold: value });
    // 자세한 내용은 플레이어 데이터를 참조하세요.
}
```

`purchaseToken: string` — [payments.purchase()](#payments-purchase) 및 [payments.getPurchases()](#getpurchases) 메서드가 반환한 토큰입니다.

## 처리되지 않은 구매 확인하기 {#check-purchases}

게임 내 구매 중에 사용자의 인터넷 연결이 실패하거나 서버가 오프라인 상태가 되면 구매가 처리되지 않은 상태로 남아있을 수 있습니다. 이를 방지하려면 [payments.getPurchases()](#getpurchases) 메서드를 사용하여 처리되지 않은 구매가 있는지 확인하세요(예: 게임을 시작할 때마다).

{% note alert "알림" %}

구매를 추가하기 전에, 미처리 결제 검사를 설정하세요.

이 검사는 모더레이션을 통과하기 위해 [필수적입니다](https://yandex.com/dev/games/doc/ko/concepts/requirements.md#1-13-1), 그러므로 테스트 구매를 위해서라도 설정하는 것이 중요합니다. 게임에 구매를 추가하고 소비 설정을 하기 전에 테스트를 진행한다면, 테스트 후에 처리되지 않은 결제가 남아 모더레이션을 통과하는 것이 불가능해질 수 있습니다.

{% endnote %}

{% list tabs group=purchases %}

- 클라이언트에서의 처리

  [초기화](#install) 기본 매개변수(`signed: false`)를 사용하여.

  **예시**

  ```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)
              });
      }
  }
  ```

- 서버에서 처리

  [초기화](#install) 매개변수 `signed: true`를 사용하여.

  **예시**

  ```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}

## 사기 방지 {#signature}

게임 내에서 가능한 지표 조작을 방지하기 위해 서버 측에서 구매 처리를 하세요:

1. Initialize `YaGames.init()` or `ysdk.getPayments()` with the `{ signed: true }` parameter.
2. [payments.purchase()](#payments-purchase) 와 [payments.getPurchases()](#getpurchases) 응답에서 받은 서명을 자신의 서버로 전송하고, 비밀 키를 사용하여 이를 해독합니다.
3. 자신의 서버에서 플레이어에게 게임 내에서 얻은 아이템을 지급하세요.

```javascript
// 구매가 { signed: true } 파라미터를 사용하여 초기화되었는지 확인합니다

[payments](*key_payments).purchase({ id: 'gold500' })
    .then(purchase => {
         // 구매 성공!
         // 서버에 500골드 추가...
         serverPurchase(purchase.signature); // 서명을 확인하고 플레이어에게 데이터를 지급합니다.
    });

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

서버로 전송되는 요청의 `signature` 파라미터에는 구매 데이터와 서명이 포함됩니다. `base64` 인코딩의 두 문자열입니다: `<signature>.<JSON with the purchase data>`.

#### 서명 예시

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

#### 전송된 구매 데이터 예시(`JSON` 형식) {#purchase-data-example}

`serverPurchase(signature)` 함수에 사용되는 `signature` 파라미터의 데이터 형식은 [payments.getPurchases()](#getpurchases) 메서드에서 사용되는 형식과 다르므로 주의하시기 바랍니다.

`payments.getPurchases()` 메서드에서 `signature` 파라미터는 `data` 필드에 구매 개체 배열을 포함합니다. `serverPurchase(signature)` 함수에서는 구매 객체입니다.

```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": "No ads",
      "description": "Disable ads in the game",
      "가격": {
        "코드": "YAN",
        "값": "49"
      },
      "imagePrefix": "https://avatars.mds.yandex.net/get-games/1892995/2a0000016d1c1717bd7a0149ccadc86078a1/"
    },
    "developerPayload": "TEST DEVELOPER PAYLOAD"
  }
}
```

#### 비밀 키 예시

`t0p$ecret`

서명을 확인하는 데 사용되는 비밀 키는 게임마다 고유합니다. 개발자 대시보드에서 구매 생성 시 자동으로 생성됩니다. 구매 표 아래에서 찾을 수 있습니다.

#### 서버의 서명 확인 예제

{% list tabs %}

* Python 3

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

   usedTokens = {}

   key = 't0p$ecret' # 키는 비밀로 유지하세요.
   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('Signature check ok!')

     if not purchaseData['data']['token'] in usedTokens:
       usedTokens[purchaseData['data']['token']] = True; # 데이터베이스를 사용합니다.
       print('Double spend check ok!')

       print('Apply purchase:', purchaseData['data']['product'])
       # 여기서 안전하게 구매를 신청하실 수 있습니다.
   ```

* Node.js

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

   const usedTokens = {};

   const key = 't0p$ecret'; // 키는 비밀로 유지하세요.
   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('Signature check ok!');

     if (!usedTokens[purchaseData.data.token]) {
       usedTokens[purchaseData.data.token] = true; // 데이터베이스를 사용합니다.
       console.log('Double spend check ok!');

       console.log('Apply purchase:', purchaseData.data.product);
       // 여기서 안전하게 구매를 신청하실 수 있습니다.
     }
   }
   ```

{% endlist %}

---

<!-- source: ko/_includes/concepts/troubleshooting/id-troubleshooting/support.md -->
{% note info "참고" %}

지원팀은 완성된 게임을 Yandex Games에 게시하는 데 도움을 드릴 수 있습니다. 개발이나 테스트에 대해 궁금한 점이 있다면, [Discord 채널](https://discord.com/invite/wU4p3whr4T)에서 질문해 주세요.

{% endnote %}


지원 서비스는 얀덱스 게임에서 완성 된 게임을 게시 할 수 있습니다. 개발 또는 테스트에 대한 질문이 있는 경우
<!-- endsource: ko/_includes/concepts/troubleshooting/id-troubleshooting/support.md -->

<!-- source: ko/_includes/button-fos.md -->
Yandex Games SDK 사용과 관련하여 문제가 발생하거나 질문이 있는 경우 다음 방법으로 지원팀에 문의하세요.


<a href="https://yandex.com/chat/#/user/a4fa5c06-75db-9b38-6eea-b1673785f7d5">
  <span class="button">채팅 상담</span>
</a>
<!-- endsource: ko/_includes/button-fos.md -->

[*key_id]: `id: string` — [개발자 대시보드](https://yandex.com/dev/games/doc/ko/console/purchases.md#connect)에 설정된 제품 ID입니다.

[*key_developerPayload]: `developerPayload: string` — 선택적 파라미터. 서버로 전송할 추가 구매 데이터(`signature` 파라미터로 전송).

[*key_sign]: 서버로 전송되는 요청의 `signature` 파라미터에는 구매 데이터와 서명이 포함됩니다. `base64` 인코딩의 두 문자열입니다: `<signature>.<JSON with the purchase data>`.

[*key_purchaseToken]: `purchaseToken: string` — [payments.purchase()](#payments-purchase) 및 [payments.getPurchases()](#getpurchases) 메서드가 반환한 토큰입니다.

[*key_payments]: `ysdk.getPayments()`로 결제를 초기화하지 않은 경우, 직접 `ysdk.payments`를 호출하세요.

[*key_explanation]: - [수익화 설정](https://yandex.com/dev/games/doc/ko/console/purchases.md#connect)
- [개발자 콘솔](https://games.yandex.com/console)에서 **In-app purchases** 탭으로 이동 후 다음 사항을 확인하세요:
    - 인앱 상품이 하나 이상 등록된 테이블이 존재하는지
    - **Purchases are enabled** 문구가 표시되는지