> For the complete documentation index, see [llms.txt](https://onestore-dev.gitbook.io/dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://onestore-dev.gitbook.io/dev/eng/tools/webshop/validation.md).

# User Validation

Verifies whether the game ID and server information entered by the user are valid and whether the item can be purchased.

* Game ID is the value used to identify the final recipient (user or character) who will receive the item. In ONEshop, it is transmitted as `serviceUserId`.\
  *<mark style="color:$info;">(Depending on the game structure, it may be used as a UID or a Character ID.)</mark>*
* ONEshop does not hold the user's game account information and decides whether to proceed with the purchase based on the game server's response. The game server must verify that the received game ID and server actually exist and that the item can be purchased before responding.

{% hint style="info" %}
Titles without a registered validation URL cannot process payments. You can register the URL in `ONEconsole > Webshop > Developer > Server Integration`.
{% endhint %}

**Call Timing**

Validation is called when the user enters the game ID and when the user purchases an item. You can tell the two requests apart by whether `param.prodId` is included.

<table><thead><tr><th width="160">Timing</th><th width="200">param.prodId</th><th>Game server handling</th></tr></thead><tbody><tr><td>UID login</td><td>Not included</td><td><p>Called when the user enters the game ID (UID) in ONEshop and logs in. Respond after checking only whether the game ID and server are valid.</p><ul><li>Item information is not available at this point, so respond with <code>0000</code> or <code>1000</code>.</li><li>If you respond with <code>1001</code> at this point, the ONEshop flow stops. Determine whether the item can be purchased (<code>1001</code>) at the time of item purchase.</li></ul></td></tr><tr><td>Item purchase</td><td>Included</td><td>Called when the user requests an item purchase. Check both the validity of the game ID and server and whether the item can be purchased before responding.</td></tr></tbody></table>

**Request URI**

{% hint style="warning" %}
**Notice**

* According to the ONEshop security policy, only the **HTTPS protocol and port 443** are supported. Using any other configuration may result in improper operation.
* The game server must respond within **5 seconds** with HTTP 200 and the `Content-Type: application/json` header. A response that takes longer than 5 seconds, returns a status code other than HTTP 200, or has a non-JSON body is treated as an integration error, and ONEshop does not retry the request.
  {% endhint %}

<table data-header-hidden><thead><tr><th width="185"></th><th></th></tr></thead><tbody><tr><td><strong>HTTP Type</strong></td><td>HTTPS</td></tr><tr><td><strong>HTTP Method</strong></td><td><mark style="color:$primary;"><code>POST</code></mark></td></tr><tr><td><strong>URL</strong></td><td>You can register the server URL in <code>ONEconsole > Webshop > Developer > Server Integration</code>. For setup instructions, refer to the <a href="https://onestore-dev.gitbook.io/dev/eng/webshop/integration">Server Integration</a> guide.</td></tr><tr><td><strong>Header</strong></td><td><p>Content-Type: application/json; charset=UTF-8</p><p>Accept: application/json</p></td></tr></tbody></table>

**Request**

<table><thead><tr><th width="203">Name</th><th width="134">Type</th><th width="127">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>param.clientId</code></td><td>String</td><td>M</td><td>ONEshop Title ID (e.g., <code>WS00000001</code>)</td></tr><tr><td><code>param.prodId</code></td><td>String</td><td>Optional</td><td><p>ONEshop Item ID</p><ul><li>Included only at the time of item purchase.</li><li>Requests at UID login do not include this field.</li></ul></td></tr><tr><td><code>param.serviceUserId</code></td><td>String</td><td>M</td><td>User's Game ID (up to 100 bytes)</td></tr><tr><td><code>param.serviceServerId</code></td><td>String</td><td>Optional</td><td><p>User's Server ID (up to 100 bytes)</p><ul><li>Passed when a <code>Server List</code> type is set in the Player Identity Field.</li></ul></td></tr><tr><td><code>param.serviceCustomFields</code></td><td>String (JSON String)</td><td>Optional</td><td><p>User Custom Field</p><ul><li>Passed when you have added a Custom Field in <code>ONEconsole > Webshop > Developer > Player Identity Field</code>.</li><li>A JSON string in the format <code>{"field key": "input value"}</code>.</li><li>For details, see <a href="https://onestore-dev.gitbook.io/dev/eng/webshop/player-id-fields">Player Identity Field</a>.</li></ul></td></tr><tr><td><code>signature</code></td><td>String</td><td>M</td><td><p>Signature to prevent tampering</p><ul><li>You can find the signature key in the License tab of <code>ONEconsole > Webshop > Developer > Server Integration</code>.</li><li>For the signing target and verification method, see <a href="https://onestore-dev.gitbook.io/dev/eng/tools/webshop/validation#signature">Signature Verification</a> below.</li></ul></td></tr></tbody></table>

**Example**

{% tabs %}
{% tab title="UID login" %}

```bash
curl -X POST \
  'https://example.com/gameuser/check' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "param": {
      "clientId": "WS00000001",
      "serviceUserId": "USR1234567890",
      "serviceServerId": "asia01",
      "serviceCustomFields": "{\"characterId\":\"char_1001\"}"
    },
    "signature": "ajkfl;askfjkladfjksl"
  }'
```

{% endtab %}

{% tab title="Item purchase" %}

```bash
curl -X POST \
  'https://example.com/gameuser/check' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "param": {
      "clientId": "WS00000001",
      "prodId": "item1000",
      "serviceUserId": "USR1234567890",
      "serviceServerId": "asia01",
      "serviceCustomFields": "{\"characterId\":\"char_1001\"}"
    },
    "signature": "ajkfl;askfjkladfjksl"
  }'
```

{% endtab %}
{% endtabs %}

**Signature Verification**

| Item             | Details                                                                                                           |
| ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| Algorithm        | `SHA512withRSA`                                                                                                   |
| Verification key | The license key (Base64 public key) in the License tab of `ONEconsole > Webshop > Developer > Server Integration` |
| Signing target   | The `{"param":{...}}` string (UTF-8), which is the request body excluding `signature`                             |
| Signature value  | Base64                                                                                                            |

* Use the raw request body (bytes) exactly as received for signature verification. Parsing the JSON and serializing it again is not recommended because the field order, whitespace, and Unicode escaping may change, causing verification to fail. If you must re-serialize, keep the field order, use no whitespace, and do not escape Unicode characters such as Korean.
* Fields without a value (such as `prodId` and `serviceServerId`) are included in neither the request nor the signing target.
* If signature verification fails, respond with HTTP 200 and set `result.code` to `2000`. Any code other than `0000`, `1000`, and `1001` is treated as a validation failure.

**Response**

<table><thead><tr><th width="203">Name</th><th width="134">Type</th><th width="127">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>result.code</code></td><td>String</td><td>M</td><td><p><code>0000</code>: Success</p><p><code>1000</code>: Non-member (game ID not registered on the game server)</p><p><code>1001</code>: Not allowed to purchase</p><ul><li>If you respond with any value other than these three, or do not respond, it is treated as a validation failure and the purchase does not proceed.</li></ul></td></tr><tr><td><code>result.message</code></td><td>String</td><td>M</td><td><ul><li>When <code>result.code</code> is <code>1001</code>, this message is displayed to the user.</li><li>It is recommended to provide the message in a language appropriate for the target users.</li><li><p><strong>Example messages</strong></p><ul><li>"구매 가능한 횟수를 초과하였습니다."(You have exceeded the maximum number of purchases allowed.)</li><li>"이미 구매한 상품입니다."(This product has already been purchased.)</li><li>"이벤트 기간이 종료된 상품입니다."(This product is no longer available as the event period has ended.)</li></ul></li></ul></td></tr><tr><td><code>developerPayload</code></td><td>String</td><td>Optional</td><td><p>An identifier for a purchase provided by the developer in the validation response.</p><ul><li>It is passed as is in the payment request, and is also included in the PNS after payment completion and used for purchase verification.</li><li>If you do not provide it, it is difficult to match a purchase in the sales history with a developer order, so providing it is recommended.</li></ul></td></tr></tbody></table>

**Example**

```json
// Success
{
  "result": {
    "code": "0000",
    "message": "User found"
  },
  "developerPayload": "OS_000211234"
}

// Non-member
{
  "result": {
    "code": "1000",
    "message": "User not found"
  }
}

// Not allowed to purchase
{
  "result": {
    "code": "1001",
    "message": "구매 가능한 횟수를 초과하였습니다." // You have exceeded the maximum number of purchases allowed.
  }
}
```
