Enable Buy Button with custom checkout

Why is it important

Following recent updates to Apple’s policies in certain regions, developers are now permitted to guide users from their apps to external websites to accept payments for virtual items.

You can add visible buttons, banners, messages, and other calls to action that take users directly from your game to item purchase using a secure, browser-based checkout (to your Web Shop or payment UI) in a single click — without violating Apple’s rules or risking enforcement.

Buy Button integration via Headless checkout is ideal if you want to create your own custom payment UI and create a unique user experience. This integration option allows users to seamlessly proceed from the game to purchase in a browser using a wide range of payment methods, including one-click payments via Apple Pay, for fast and familiar mobile checkout experience.

Headless checkout is a payment acceptance solution based on the headless application architecture, where functionality is accessible via API. This approach separates the backend and business logic from the UI.

To use Headless checkout for iOS game applications:

  1. Create your own store.
  2. Integrate Headless checkout into your store.
  3. Add a link in your game that takes users to your store.

If you are looking for the fastest low-code integration option, check the Web Shop-based integration.

If you’‎re using a custom Web Shop that is not built with Xsolla Site Builder and want to integrate a ready-made payment UI into your game, check the integration via the Xsolla Mobile SDK.

How it works

Notice

Apple’s requirements:

  • In-app WebViews for external purchases are not allowed — payments must occur via Safari or the default browser.

  • External purchase links are currently permitted only for iOS applications on the United States storefront. Note that Apple’s app review guidelines refer to the United States storefront, not user location.

User flow:

  1. The user opens the game application on iOS.
  2. The user clicks the purchase button next to the desired item.
  3. Your store opens in a web browser. To ensure a seamless user experience, implement end-to-end authorization.
  4. The user selects an item and makes a purchase without leaving the store.
  5. The user is redirected to the game application after successful transaction.
  6. The application receives the purchase confirmation via a webhook.

Integration flow

Notice
Before starting the integration, you need to build your own store and implement the logic of catalog display.
  1. Create a project in Publisher Account and sign a licensing agreement with Xsolla.
  2. Create an item catalog.
  3. Implement backend interactions: create a token and set up webhooks.
  4. Install SDK.
  5. Integrate SDK on the application side.
  6. Add a link in your game that takes users to your store where Headless checkout is integrated.

Create project and sign licensing agreement

Publisher Account is the main tool to configure Xsolla features, as well as to work with analytics and transactions.

Notice
Before you sign the licensing agreement, you can open the payment UI only in sandbox mode.

To sign up, go to Publisher Account and create an account. To create a project, click Create project in the side menu and provide any necessary information. You can modify the settings later.

Notice
For detailed information, refer to the instructions.

To sign the licensing agreement, go to the Agreements & Taxes > Agreements section and complete the agreement form.

Create item catalog

In-App Purchase (IAP) products are represented through virtual items in the Xsolla ecosystem. They have a name, description, SKU, and price. To set up your IAP SKU product catalog, you can:

  1. Upload a JSON file to quickly add your catalog to Publisher Account.
  2. Create an item catalog using the API calls from the Virtual items & currency > Admin documentation section.

Implement backend interaction

Create token

When the user clicks the purchase button, a payment token must be created. This token is used to open the payment UI and contains information about the user, the item, and additional parameters passed to Xsolla. Refer to the documentation for detailed information. To use sandbox mode, pass the “mode”: “sandbox” parameter in the body of the request for getting a token.

Configure webhooks

To enable webhooks:

  1. In your project inside Publisher Account, go to the Project setting > Webhooks section.
  2. In the Webhook server field, specify the server URL — where you want to receive webhooks in the https://example.com format. You can also specify the URL you find in a tool for testing webhooks.
  3. A secret key to sign project webhooks is generated by default. If you want to generate a new secret key, click the refresh icon.
  4. Click Enable webhooks.

For the full operation of the in-game store and payment management, it is necessary to implement the processing of the main webhooks:

Webhook nameDescription
User validation > User validation (user_validation)Is sent at different stages of the payment process to ensure the user is registered in the game.
Game services > Combined webhooks > Successful payment for order (order_paid)It contains payment data, transaction details, and information about purchased items. Use the data from the webhook to add items to the user.
Game services > Combined webhooks > Order cancellation (order_canceled)It contains data of the canceled payment, transaction details, and information about purchased items. Use the data from the webhook to remove the purchased items.
Note
For the full list of webhooks and general information about working with them, refer to the webhooks documentation.

Install SDK

  1. Install the SDK as an npm package by running the command:
Copy
Full screen
Small screen
    1npm install --save @xsolla/pay-station-sdk
    
    1. Initialize the SDK by passing environment parameters:
    Copy
    Full screen
    Small screen
    1import { headlessCheckout } from '@xsolla/pay-station-sdk';
    2
    3await headlessCheckout.init({
    4  sandbox: true,
    5});
    
    1. Pass the payment token for the initialized SDK:
    Example:
    Copy
    Full screen
    Small screen
    1await headlessCheckout.setToken(accessToken);
    

    Integrate SDK on application side

    Notice
    Apple Pay is a required payment method for this integration scenario. Additionally, you can configure other payment methods. To do this, refer to the instructions.
    Note
    Examples provided below can be used only in sandbox mode.

    After installing and initializing SDK:

    1. Initialize the payment UI specifying the payment method ID. The headlessCheckout.form.init method returns an object used for further interaction with the payment UI.
    Example:
    Copy
    Full screen
    Small screen
    1await headlessCheckout.form.init({
    2  paymentMethodId: 3175, // Apple Pay payment ID
    3});
    
    1. Add the handling of the show_fields event for displaying additional fields.
    Example:
    Copy
    Full screen
    Small screen
    1headlessCheckout.form.onNextAction((nextAction) => {
    2  switch (nextAction.type) {
    3    case 'show_fields':
    4      this.handleShowFieldsAction(nextAction);
    5  }
    6});
    
    1. Add the following components to the HTML markup of the payment UI:
      • Mandatory components:
        • psdk-legal — to display information about legal documents.
        • psdk-total — to display the total purchase amount.
      • Payment form components. You can either use the built-in psdk-payment-form component or manually create payment UI elements using the ready-to-use components.
      • The payment button component — psdk-apple-pay. You can also use the psdk-submit-button component that already includes psdk-apple-pay.
    Example:
    Copy
    Full screen
    Small screen
    1<psdk-legal></psdk-legal>
    2<psdk-total></psdk-total>
    3
    4
    5<psdk-payment-form></psdk-payment-form>
    6<psdk-apple-pay text="Apple Pay"></psdk-apple-pay>
    
    1. Add the handling of the check_status event for the payment status change.
    Example:
    Copy
    Full screen
    Small screen
    1headlessCheckout.form.onNextAction((nextAction) => {
    2  switch (nextAction.type) {
    3    case 'check_status': {
    4      showStatus = true;
    5    }
    6  }
    7});
    
    1. Add the psdk-status component to the HTML markup of the payment UI to display a payment status.
    Example:
    Copy
    Full screen
    Small screen
    1@if (showStatus) {
    2  <psdk-status></psdk-status>
    3}
    

    How to detect iOS storefront

    To determine the current iOS storefront and adjust SDK functionality based on the region, use the following code snippets:

    Copy
    Full screen
    Small screen

    obj-c

    • obj-c
    • swift
    1[SKPaymentQueue loadCurrentStorefrontCountryCodeWithCompletion:^(NSString* _Nullable countryCode) {
    2    settings.enablePayments = countryCode && [countryCode isEqualToString:@"USA"];
    3
    4    [[SKPaymentQueue defaultQueue] startWithSettings:settings];
    5}];
    
    1SKPaymentQueue.loadCurrentStorefrontCountryCode { countryCode in
    2    settings.enablePayments = countryCode == "USA"
    3
    4    SKPaymentQueue.default().start(settings)
    5}
    

    The loadCurrentStorefrontCountryCode method asynchronously retrieves the three-letter country code for the current storefront. You can use this information to enable or disable SDK functionality for specific regions.

    Alternatively, you can use Apple’s native Storefront directly, as shown below:

    Notice
    We recommend avoiding the Objective-C SKStorefront implementation, as it performs synchronous loading that blocks the main thread. This can lead to UI freezes and degraded user experience, as noted in Apple’s official documentation.
    Copy
    Full screen
    Small screen
    1let storefront = await Storefront.current   
    2let countryCode = storefront?.countryCode
    3
    4settings.enablePayments = countryCode == "USA"
    5
    6SKPaymentQueue.default().start(settings)
    

    One-click payment via Apple Pay

    One-click payment allows users to pay with Apple Pay, a familiar and secure native payment method, on supported devices. To configure one-click payment:

    1. Create a request to enable this option. To do so:

      a. Open your Publisher Account and go to the Support Hub section.

      b. Click Submit request.

      c. In the window that opens, fill in the fields:

      • Summary. For example, Apple Pay one-click payment setup.
      • Description. Specify the domain used for opening the payment UI, e.g., amazing.store.com.
      • Project ID. Select a project ID from the drop-down list. If you want to configure the one-click payment option for multiple projects, specify their IDs in the Description field.

      d. Click Send.

    2. Wait for your domain association file. This step is performed by Xsolla:
      1. Xsolla registers your domain with Apple.
      2. Xsolla receives the domain association file from Apple.
      3. Xsolla emails you the domain association file and provides instructions on where to upload it.
    3. Update the SDK initialization script as shown below:
    Copy
    Full screen
    Small screen
    1const config: InitialOptions = {
    2  isWebview: false,
    3  theme: 'default',
    4  language: parameters.language,
    5  topLevelDomain: 'amazing.store.com',
    6  isApplePayInstantFlowEnabled: true
    7};
    8
    9await initHeadlessCheckoutLib(config);
    
    1. Reply to Xsolla email and confirm that you have uploaded the domain association file to the specified location and updated the SDK initialization script.
    2. Wait for confirmation from Xsolla that one-click payment has been successfully enabled in your project.
    Was this article helpful?
    Thank you!
    Is there anything we can improve? Message
    We’re sorry to hear that
    Please explain why this article wasn’t helpful to you. Message
    Thank you for your feedback!
    We’ll review your message and use it to help us improve your experience.
    Last updated: July 4, 2025

    Found a typo or other text error? Select the text and press Ctrl+Enter.

    Report a problem
    We always review our content. Your feedback helps us improve it.
    Provide an email so we can follow up
    Thank you for your feedback!
    We couldn't send your feedback
    Try again later or contact us at [email protected].
    OSZAR »