Preorders

Preorders is a Xsolla Pay2Play-based solution allowing publishers to sell games before their official release date. When a user preorders a game, they receive a unique number confirming their purchase. Once the game is released, we automatically deliver the PIN code to the user so that they can access the game.

Creating a Project

  1. Go to Projects and click Create new project.
  2. In set up mode:
    a. Set Webhooks to Off.
    b. Set Serverless integration to On.
  3. Turn the Pay2Play module on.

Configuring the Module

  1. Go to Pay2Play settings and configure the following parameters:
    a. Game name.
    b. Game description.
    c. System requirements.
    d. SKU — a unique identifier.
    e. Release date.
    f. Image.
    g. DRM platforms.
    h. Operating systems/game console versions supported by selected DRM platforms.
  2. Click Next.
  3. Set prices for the selected DRM platforms.

Integrating the Pay2Play Widget

The Pay2Play widget opens your store in a lightbox (on desktop screens) or a new window (on mobile and tablet screens). The widget automatically determines the type of device.

To get the widget code, open module settings in your Publisher Account and go to the Publish tab. Copy the code of the desired widget and add it to your game’s website. We recommend using asynchronous loading.

Asynchronous script loading example:

 <script>
         var access_data = {"settings":{"project_id":14004,"mode":"sandbox"},"purchase":{"pin_codes":{"codes":[{"digital_content":"game_sku"}]}}};
         var target_element = "#widget-example-element";
         var s = document.createElement('script');
         s.type = "text/javascript";
         s.async = true;
         s.src = "//static.xsolla.com/embed/pay2play/2.1.0/widget.min.js";
         s.addEventListener('load', function (e) {
                 var widgetInstance = XPay2PlayWidget.create(access_data,target_element);
         }, false);
         var head = document.getElementsByTagName('head')[0];
         head.appendChild(s);
 </script>

You can find the complete list of widget initialization parameters in the API Reference. Instructions on installing the widget can be found on GitHub.

Important! You need to sign the agreement before you can accept real payments.

Testing Payment Process

Xsolla Sandbox is a standalone environment that supports all features of the live environment, except real payments. You can access the Sandbox by sending "settings.mode" = "sandbox" within the access_data object. The JSON structure and parameters in access_data are the same as in the Token request.

To test a bank card payment:

  1. Open the store in sandbox mode.
  2. Choose the item to purchase.
  3. Choose the Credit/debit cards group of payment methods.
  4. Enter the bank card details and any values in the remaining fields. You can also specify incorrect details (card number, expiration date, or CVV) in order to generate an error.

List of bank cards to be used for testing

Important! Sandbox bank card payments can only be made in USD, EUR, RUB, GBP, SGD, HKD, or THB.

Uploading PIN Codes

Once the game is released, open the Pay2Play module settings and upload the PIN codes for the selected DRM platforms on the Codes uploading tab.

Making Payments for an Authorized User

For users with an existing game account, you can send user information to make an authorized transaction. To enable the feature:

  1. Set up the project.
  2. Get a token.
  3. Set up webhook handling.

You will need the following parameters:

  • Merchant ID — shown in the Publisher Account URL: https://publisher.xsolla.com/{merchant_id}/.
  • API key — generated in Publisher Account > Settings > Company.
  • Project ID — shown in the Publisher Account URL when viewing project settings: https://publisher.xsolla.com/{merchant_id}/projects/{project_id}/.
  • Project secret key — generated in project settings.

Setting Up a Project

To set up a project:

  1. Set Webhooks to On.
  2. Specify the webhook URL.
  3. Generate a secret key to sign project webhooks.
  4. Set Serverless integration to Off.

Get Token to Open Store

To integrate the store UI into your game, you will need an access token. An access token is a string that identifies the game, user and purchase parameters.

Xsolla API uses HTTP Basic Authentication. Provide your Merchant ID as the basic auth username and the API key as your password.

Set the value to "mode":"sandbox" to test the payment process.

Token endpoint URL:

https://api.xsolla.com/merchant/merchants/{merchant_id}/token

In an HTTP POST request, you can use parameters for store UI. Request and response payloads are formatted as JSON.

Example Request

Below you can find sample code of how to get a token in PHP with the help of Xsolla PHP SDK. If you're using another programming language, please take a look at the CURL example by clicking on the CURL tab.

PHP
CURL
<?php

use Xsolla\SDK\API\XsollaClient;
use Xsolla\SDK\API\PaymentUI\TokenRequest;

$tokenRequest = new TokenRequest($projectId, $userId);
$tokenRequest->setUserEmail('email@example.com')
    ->setExternalPaymentId('12345')
    ->setSandboxMode(true)
    ->setUserName('USER_NAME')
    ->setCustomParameters(array('key1' => 'value1', 'key2' => 'value2'));

$xsollaClient = XsollaClient::factory(array(
    'merchant_id' => MERCHANT_ID,
    'api_key' => API_KEY
));
$token = $xsollaClient->createPaymentUITokenFromRequest($tokenRequest);
    curl -v https://api.xsolla.com/merchant/merchants/{merchant_id}/token \
    -X POST \
    -u your_merchant_id:merchant_api_key \
    -H 'Content-Type:application/json' \
    -H 'Accept: application/json' \
    -d '
    {
        "user": {
            "id": {
                "value": "1234567"
            },
            "email": {
                "value": "email@example.com"
            }
        },
        "settings": {
            "project_id": 14004,
            "mode": "sandbox"
        }
    }'

You can find the full list of parameters in the API Reference.

Setting Up Webhooks

Xsolla sends the following webhooks to your project:

  • User Validation
  • Payment
  • Refund

To acknowledge that you received webhook notifications without any problem, your server should return a 204 HTTP status code without body. The full description of webhook mechanism with samples is described in detail in the API Reference.

Creating a Signature

To create a signature:

  1. Concatenate the data sent in the Xsolla server’s request and the project’s secret key (generated in project settings).
  2. Hash the string using the SHA1 algorithm.
  3. Send the signature in the Signature header.

When handling a webhook, make sure that the signature received matches the one set in the Signature header.

User Validation

The Xsolla server sends a request to the project’s webhook URL to verify that a user exists in the game.

Request example

PHP
CURL
$request = array(
    'notification_type' => 'user_validation',
    'user' => array(
        'ip' => '127.0.0.1',
        'phone' => '18777976552',
        'email'=> 'email@example.com',
        'id'=> '1234567',
        'country' => 'US'
    )
)
curl -v https://example.com/ \
-X POST \
-H 'Content-Type:application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Signature 13342703ccaca5064ad33ba451d800c5e823db8f' \
-d '
{
    "notification_type": "user_validation",
    "user": {
        "ip": "127.0.0.1",
        "phone": "18777976552",
        "email": "email@example.com",
        "id": "1234567",
        "country": "US"
    }
}'

You can find the full list of parameters in the API Reference.

Payment

The Xsolla server sends a webhook including payment details whenever a user completes a payment.

Request example

PHP
CURL
$request = array(
    'notification_type' => 'payment',
    'purchase' => array(
        'virtual_items' => array(
            'items' => array(
                0 => array(
                    'sku' => 'test_item1',
                    'amount' => 1,
                    ),
                1 => array(
                    'sku' => 'test_item2',
                    'amount' => 1,
                    ),
                2 => array(
                    'sku' => 'test_item3',
                    'amount' => 1,
                    ),
            )
        ),
        'total' => array(
            'currency' => 'USD',
            'amount' => 9.99
        )
    ),
    'user' => array(
        'ip' => '127.0.0.1',
        'phone' => '18777976552',
        'email' => 'email@example.com',
        'id' => '1234567',
        'country' => 'US'
    ),
    'transaction' => array(
        'id' => 87654321,
        'payment_date' => '2014-09-23T19:25:25+04:00',
        'payment_method' => 1380,
        'dry_run' => 1
    ),
    'payment_details' => array(
        'payment' => array(
            'currency' => 'USD',
            'amount' => 9.99
        ),
        'vat' => array(
            'currency' => 'USD',
            'amount' => 0
        ),
        'payout_currency_rate' => 1,
        'payout' => array(
            'currency' => 'USD',
            'amount' => 9.49
        ),
        'xsolla_fee' => array(
            'currency' => 'USD',
            'amount' => 0.19
        ),
        'payment_method_fee' => array(
            'currency' => 'USD',
            'amount' => 0.31
        )
    )
)
curl -v https://example.com/ \
-X POST \
-H 'Content-Type:application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Signature 13342703ccaca5064ad33ba451d800c5e823db8f' \
-d '
{
    "notification_type": "payment",
    "purchase": {
        "virtual_items": {
            "items": [
                {
                    "sku": "test_item1",
                    "amount": 1
                },
                {
                    "sku": "test_item2",
                    "amount": 1
                },
                {
                    "sku": "test_item3",
                    "amount": 2
                },
            ]
        },
        "total": {
            "currency": "USD",
            "amount": 9.99
        }
    },
    "user": {
        "ip": "127.0.0.1",
        "phone": "18777976552",
        "email": "email@example.com",
        "id": "1234567",
        "country": "US"
    },
    "transaction": {
        "id": 87654321,
        "payment_date": "2014-09-23T19:25:25+04:00",
        "payment_method": 1380,
        "dry_run": 1
    },
    "payment_details": {
        "payment": {
            "currency": "USD",
            "amount": 9.99
        },
        "vat": {
            "currency": "USD",
            "amount": 0
        },
        "payout_currency_rate": 1,
        "payout": {
            "currency": "USD",
            "amount": 9.49
        },
        "xsolla_fee": {
            "currency": "USD",
            "amount": 0.19
        },
        "payment_method_fee": {
            "currency": "USD",
            "amount": 0.31
        }
    }
}'

You can find the full list of parameters in the API Reference.

Refund

If the user cancels the payment, the Xsolla server sends a webhook notification with information about the payment.

Request example

PHP
CURL
$request = array(
    'notification_type' => 'refund',
    'purchase' => array(
        'virtual_currency' => array(
            'name' => 'Coins',
            'quantity' => 100,
            'currency' => 'USD',
            'amount' => 9.99
        ),
        'total' => array(
            'currency' => 'USD',
            'amount' => 9.99
        )
    ),
    'user' => array(
        'ip' => '127.0.0.1',
        'phone' => '18777976552',
        'email' => 'email@example.com',
        'id' => '1234567',
        'country' => 'US'
    ),
    'transaction' => array(
        'id' => 87654321,
        'payment_date' => '2014-09-23T19:25:25+04:00',
        'payment_method' => 1380,
        'dry_run' => 1
    ),
    'refund_details' => (
            'code' => 1,
            'reason' => 'Fraud'
    ),
    'payment_details' => array(
        'payment' => array(
            'currency' => 'USD',
            'amount' => 9.99
        ),
        'vat' => array(
            'currency' => 'USD',
            'amount' => 0
        ),
        'payout_currency_rate' => 1,
        'payout' => array(
            'currency' => 'USD',
            'amount' => 9.49
        ),
        'xsolla_fee' => array(
            'currency' => 'USD',
            'amount' => 0.19
        ),
        'payment_method_fee' => array(
            'currency' => 'USD',
            'amount' => 0.31
        )
    )
);
curl -v https://example.com/ \
-X POST \
-H 'Content-Type:application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Signature 13342703ccaca5064ad33ba451d800c5e823db8f' \
-d '
{
    "notification_type":"refund",
    "purchase":{
        "virtual_currency":{
            "name": "Coins",
            "quantity":10,
            "currency":"USD",
            "amount":100
        },
        "subscription":{
            "plan_id": "b5dac9c8",
            "subscription_id": "10",
            "date_create": "2014-09-22T19:25:25+04:00",
            "currency": "USD",
            "amount": 9.99
        },
        "checkout":{
            "currency":"USD",
            "amount":50
        },
        "virtual_items":{
            "items":[
                {
                    "sku": "test_item1",
                    "amount":1
                }
            ],
            "currency":"USD",
            "amount":50
        },
        "total":{
            "currency":"USD",
            "amount":200
        }
    },
    "user": {
        "ip": "127.0.0.1",
        "phone": "18777976552",
        "email": "email@example.com",
        "id": "1234567",
        "name": "Xsolla User",
        "country": "US"
    },
    "transaction":{
        "id":1,
        "external_id":1,
        "dry_run":1,
        "agreement":1
    },
    "refund_details":{
        "code":1,
        "reason":"Fraud"
    },
    "payment_details":{
        "xsolla_fee":{
            "currency":"USD",
            "amount":"10"
        },
        "payout":{
            "currency":"USD",
            "amount":"200"
        },
        "payment_method_fee":{
            "currency":"USD",
            "amount":"20"
        },
        "payment":{
            "currency":"USD",
           "amount":"230"
        }
    }
}'

You can find the full list of parameters in the API Reference.

Testing Webhooks

To test the webhook handler:

  1. In the Publisher Account, open the module settings.
  2. Go to the Testing tab.
  3. Enter the test data and click Test. The Xsolla server will send all possible webhooks.
  4. The test is marked green in case of a valid response and red in case of an error.

Tips to the Developer

A project can receive tips for each purchase. To enable the feature, open module settings, go to the Prices tab, and set Use tips in the Pay2play widget to On. Three tip amount options are available for each enabled currency.

The user will be able to choose the tip amount before entering the store. The tips will be added to the purchase price.

Limiting the Number of Preorders

You can limit the number of preorders for any given project. You will receive the following email notifications: when 100 or fewer preorders are remaining, and when no preorders are left. If a user tries to exceed the preorder limit, payment is not processed.

Regional Restrictions on Sales

The Preorders module allows you to set up regional restrictions on preorder sales. In particular, you can:

  • Set a different cost for individual countries or groups of countries;
  • Prohibit sales in certain countries.

Once the project is properly configured, the user trying to make a preorder in a restricted country will see a corresponding warning. In countries where preorders are prohibited, payment is not processed.

To enable the feature, contact your account manager. We will need the following information for each platform with regional restrictions applied:

  • Restriction type:
    • Activation: A PIN code can be activated in certain countries only.
    • Launch: A PIN code can be activated in any country, but the game can be launched only in certain countries.
    • Activation and launch: A PIN code can be activated and the game can be launched only in certain countries.
  • List of country groups with a different preorder price.
  • Settings for each group of countries:
    • Group name.
    • SKU — a unique group identifier.
    • List of prices in different currencies. Be sure to include the price in the default currency set in module settings.
    • List of countries within each group.
  • List of countries where preorders are disabled (if any).

For any single platform, a country can belong either to a different-price group or to the preorders-disabled group. If a country is not listed in any of the groups, preorders are available without any restrictions, at the prices set in default module settings.

Important! Be sure to upload PIN codes to our system with regional restrictions already configured if PIN code activation and game launch are performed by you or the platform.