Subscriptions

The Subscriptions module allows you to sell subscriptions to users, providing them with access to your service for a certain period of time. In particular, you can:

  • Let users manage their subscriptions from a dashboard. They will be able to see detailed subscription information, view payment history, change the plan, and pause/resume/cancel the subscription.
  • Manage user subscriptions using your Xsolla Publisher Account. You can create and configure plans for each currency, set trial periods, configure grace periods, view subscribed users, and change subscription statuses for specific users.
  • Enable automatic renewal using a saved payment account.
  • Renew subscriptions manually.

Subscription Statuses

A subscription can have one of the following statuses:

  • Active. Primary status. The subscription is created and activated after the first successful payment. Further charges are only possible for active subscriptions.
  • Canceled. The subscription has been canceled with immediate effect due to one of the following reasons:

    • Via an API method or from the Xsolla Publisher Account.
    • Canceled by the user.
    • Subscription expired (if an expiration date was set in the parameters).
    • Maximum number of charging attempts exceeded (3 by default; please contact the account manager to change).
    • User not found in the game.
    • Saved payment account deleted.
  • Non renewing. Subscription renewal canceled. The subscription will last until the current payment cycle ends before the status changes to Canceled. A renewal can be canceled due to one of the following reasons:

    • Via an API method or from the Xsolla Publisher Account.
    • Canceled by user via email link.
    • Saved payment account deleted.

Integration Guide

To integrate the module:

  1. Register an Xsolla Publisher Account.
  2. Create a new project.
  3. Set up the module.
  4. Get a token.
  5. Set up the opening of the store UI.
  6. Set up webhook handling.
  7. Test the payment process.
  8. Launch the module and sign the agreement.

The following parameters are required for the integration:

  • 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.

Creating a Project

  1. Go to Projects and click Create new project.
  2. In set up mode:
    a. Specify the webhook URL.
    b. Generate a secret key to sign project webhooks.
    c. Enable the Subscriptions module.

Setting Up the Module

  1. Go to the Subscriptions module settings and click Create new plan. Specify the following parameters:
    • Name.
    • Payment cycle.
  2. Click Create.
  3. Click Back to plans list to return to basic module settings and create other plans as needed.

Important! A plan can have one currency only. You must create a separate set of plans for each project currency.

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.

Opening the Store UI

There are three ways of opening a store:

  • Use the PayStation Embed script.
  • New window.
  • Iframe.

To open the store in sandbox mode, use the following URL: https://sandbox-secure.xsolla.com/.

PayStation Embed

The PayStation Embed script determines the type of device and opens the store UI in a lightbox (on desktop screens) or in a new window (on mobile and tablet screens). We recommend using asynchronous script loading.

Asynchronous script loading example:

 <script>
     var options = {
         access_token: 'ACCESS_TOKEN', //TODO use access token, received on previous step
         sandbox: true //TODO please do not forget to remove this setting when going live
     };
     var s = document.createElement('script');
     s.type = "text/javascript";
     s.async = true;
     s.src = "https://static.xsolla.com/embed/paystation/1.0.7/widget.min.js";
     s.addEventListener('load', function (e) {
         XPayStationWidget.init(options);
     }, false);
     var head = document.getElementsByTagName('head')[0];
     head.appendChild(s);
 </script>

<button data-xpaystation-widget-open>Buy Credits</button>

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

New Window

To open the store UI in a new window, use the following link: https://secure.xsolla.com/paystation2/?access_token=ACCESS_TOKEN, where ACCESS_TOKEN is the token obtained in the previous step.

Iframe

To open the store UI in an iframe, you must implement the following mechanisms on your side:

  • Specify the device type (desktop vs mobile) and send it within the token’s settings.ui.version parameter;
  • Receiving events from the payment UI via postMessage.

To open the store UI in a new window, use the following link: https://secure.xsolla.com/paystation2/?access_token=ACCESS_TOKEN, where ACCESS_TOKEN is the token obtained in the previous step.

Setting Up Webhooks

Xsolla sends the following webhooks to your project:

  • Payment
  • Subscription created
  • Subscription updated/extended
  • Refund
  • Subscription canceled

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.

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.

Subscription Created

The Xsolla server sends a webhook including subscription details whenever a user creates a subscription.

Request example

PHP
CURL
<?php
$request = array(
    'notification_type' => 'create_subscription',
    'user' => (
        'id' => '1234567',
        'name' => 'Xsolla User'
    ),
    'subscription' => (
        'plan_id' => 'b5dac9c8',
        'subscription_id' => '10',
        'product_id' => 'Demo Product',
        'date_create' => '2014-09-22T19:25:25+04:00',
        'date_next_charge' => '2015-01-22T19:25:25+04:00',
        'trial' =>  (
                'value' =>  90,
                'type' =>  'day'
            )
    )
);
$ curl -v 'https://your.hostname/your/uri' \
-X POST \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Signature 13342703ccaca5064ad33ba451d800c5e823db8f' \
-d '{
        "notification_type":"create_subscription",
        "user":{
            "id":"1234567",
            "name":"Xsolla User"
        },
        "subscription":{
            "plan_id":"b5dac9c8",
            "subscription_id":"10",
            "product_id":"Demo Product",
            "date_create":"2014-09-22T19:25:25+04:00",
            "date_next_charge":"2015-01-22T19:25:25+04:00",
            "trial": {
                    "value": 90,
                    "type": "day"
                }
        }
    }'

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

Subscription Updated/Extended

The Xsolla server sends a webhook whenever a user changes the subscription plan, extends the subscription, or when the next billing date changes.

Request example

PHP
CURL
<?php
$request = array(
    'notification_type' => 'update_subscription',
    'user' => (
        'id' => '1234567',
        'name' => 'Xsolla User'
    ),
    'subscription' => (
        'plan_id' => 'b5dac9c8',
        'subscription_id' => '10',
        'product_id' => 'Demo Product',
        'date_next_charge' => '2015-01-22T19:25:25+04:00'
    )
);
$ curl -v 'https://your.hostname/your/uri' \
-X POST \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Signature 13342703ccaca5064ad33ba451d800c5e823db8f' \
-d '{
        "notification_type":"update_subscription",
        "user":{
            "id":"1234567",
            "name":"Xsolla User"
        },
        "subscription":{
            "plan_id":"b5dac9c8",
            "subscription_id":"10",
            "product_id":"Demo Product",
            "date_next_charge":"2015-01-22T19:25:25+04:00"
        }
    }'

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.

Subscription Canceled

The Xsolla server sends a webhook whenever a subscription is canceled.

Request example

PHP
CURL
<?php
$request = array(
    'notification_type' => 'cancel_subscription',
    'user' => (
        'id' => '1234567',
        'name' => 'Xsolla User'
    ),
    'subscription' => (
        'plan_id' => 'b5dac9c8',
        'subscription_id' => '10',
        'product_id' => 'Demo Product',
        'date_create' => '2014-09-22T19:25:25+04:00',
        'date_end' => '2015-01-22T19:25:25+04:00',
    )
);
$ curl -v 'https://your.hostname/your/uri' \
-X POST \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Signature 13342703ccaca5064ad33ba451d800c5e823db8f' \
-d '{
        "notification_type":"cancel_subscription",
        "user":{
            "id":"1234567",
            "name":"Xsolla User"
        },
        "subscription":{
            "plan_id":"b5dac9c8",
            "subscription_id":"10",
            "product_id":"Demo Product",
            "date_create":"2014-09-22T19:25:25+04:00",
            "date_end":"2015-01-22T19:25:25+04:00"
        }
    }'

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

Testing Webhooks

To test the webhook handler:

  1. Open module settings in your Publisher Account.
  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.

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 "mode" = "sandbox" when getting the token.

To test a bank card payment:

  1. Open the store in sandbox mode.
  2. Choose the item to purchase.
  3. Click Credit/debit cards.
  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.

Launching the Module

To launch the module after its successful testing, open its settings in the Publisher Account, go to the Launch tab, and click On.

Important! Before you can accept real payments, you must:

  1. Remove "mode" = "sandbox".
  2. Sign the agreement.

Preventing Fraud Using In-Game Parameters

You can use the custom_parameters object passed in the token to send the user's in-game data and detect suspicious activity. For example, a player who spends little time in the game but has a high level may be a scammer who has created an account in order to sell it after leveling up the character using a stolen bank card.

List of available parameters

Let your account manager know what parameters you plan to pass, and the trigger values for each of them. We will use this information to configure your anti-fraud filters.

Paying Using a Selected Method

When you open the store, you can send the payment method ID in the settings.payment_method parameter. In this case, the user will be immediately redirected to the payment form of the selected payment method.

Request example

CURL
    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"
            },
        },
        "settings": {
            "project_id": 14004,
            "payment_method": 24
        }
    }'

You can get the list of payment method IDs in Publisher Account > Payment systems or using the List all payment systems API method.

Purchasing a Selected Plan

When you open the store, you can send the plan ID in the purchase.subscription.plan_id parameter. In this case, the user is immediately redirected to the payment UI.

Request example

CURL
    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"
            },
        },
        "settings": {
            "project_id": 14004
        },
        "purchase": {
            "subscription": {
                "plan_id": 123
                },
        }
    }'

Canceling the Last Payment if Subscription Is Canceled

When a subscription is canceled, you can also cancel the last payment. To do this, use the cancel_subscription_payment parameter in the Update subscription method. You can also let the user choose to have their last payment refunded if their subscription is canceled. To enable the feature, please contact your account manager.

Changing the Plan

You can change the subscription plan using the Update plan method. The new plan will come into effect starting from the next period.

You cannot change the plan if:

  • The user has an active subscription with this plan,
  • The subscription status is Canceled or Non renewing, or
  • This is a trial subscription.

If the attempt to change the plan fails, the subscription is canceled.

Renewing a Subscription Manually

By default, the subscription is renewed automatically using the user's saved payment details. You can allow the user to manually renew their subscription using payment methods that cannot be saved and do not support automatic write-offs. To renew the subscription at the end of the payment cycle, the user will need to follow a link in the email notification. To enable the feature, please contact your account manager.

Using Products

If you use the same plans in several subscriptions, you can sell the subscriptions as part of a product. A product is a collection of plans that a user can subscribe to and which belong to one group. You can use the same plan for different products.

Use the following API methods to configure products: Create/Update/Delete product; List products.

Rewards

The subscription module allows you to reward users for renewing their subscription with in-game currency or items. To enable the feature, first enable the Virtual Currency and/or Virtual Items module(s). If there is any confusion, contact your account manager.