# Webhooks

# Overview {% #overview %}

Webhooks are notifications about events occurring in the system. When a specific event occurs, Xsolla sends an HTTP request, in which event data is transmitted, to your application. This is usually a POST request in JSON format.

<strong>Event examples:</strong>
- user interaction with an item catalog
- payment or cancellation of an order

When a set event happens, Xsolla notifies your system about it via a webhook. As a result, you can perform actions such as:
- replenish the user's balance
- make a payment refund
- credit or debit new items from the user account
- start providing a subscription
- block a user in case of a suspicion of fraud

<b>Example of a payment processing webhook workflow:</b>

![Payment processing webhook](https://cdn.xsolla.net/developers/current/images/api_docs/webhooks-general.svg)

<div lang="en" class="note">
 <p><strong>Note</strong></p><p>Depending on the solution used and the type of its integration, the set of webhooks and  sequence of interactions may differ from the provided example.</p>
</div>

<b>Video guide for Xsolla webhooks integration:</b>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 15px; overflow: hidden;">
  <iframe src="https://player.vimeo.com/video/1034591338" style="position: absolute; top:0; left: 0; width: 100%; height: 100%; border:0; border-radius: 15px;" allowfullscreen></iframe>
</div>


<b>Webhooks settings when working with Xsolla products and solutions:</b>

<table>
  <thead>
    <tr>
        <th>Product/ Solution</th>
        <th>Required/ Optional</th>
        <th>What are webhooks used for</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td>Payments</td>
        <td>Required</td>
        <td>
          <ul>
            <li>User validation.</li>
            <li>Receiving information about transaction details in cases of successful payment or payment refund.</li>
            <li>Crediting purchased items to a user and debiting items in case of order cancellation.</li>
          </ul>
        </td>
    </tr>
    <tr>
        <td>Store</td>
        <td>Required</td>
        <td>
          <ul>
            <li>User validation.</li>
            <li>Receiving information about transaction details in cases of successful payment or payment refund.</li>
            <li>Crediting purchased items to a user and debiting items in case of order cancellation.</li>
          </ul>
        </td>
    </tr>
    <tr>
        <td>Game Sales</td>
        <td>Optional</td>
        <td>For selling game keys, user validation and crediting of items are not required. You can connect webhooks if you want to receive information about events, such as payment or order cancellation.<br/>If you connect webhooks, it is important to process all incoming <a href="/webhooks/overview/#section/List-of-required-webhooks">required webhooks</a>.
        </td>
    </tr>
    <tr>
        <td>Subscriptions</td>
        <td>Optional</td>
        <td>Receiving information about creation, update, or cancellation of a subscription. Alternatively, you can <a href="/doc/subscriptions/integration-guide/get-subscription-information/#guides_subscriptions_get_subscription_information_set_up_via_api">request information via the API</a>.
        </td>
    </tr>
    <tr>
        <td>Web Shop</td>
        <td>Required</td>
        <td>
          <ul>
            <li>User validation.</li>
            <li>Receiving information about transaction details in cases of successful payment or payment refund.</li>
            <li>Crediting purchased items to a user and debiting items in case of order cancellation.</li>
            <li>User authentication, if you use authentication via user ID. Alternatively, you can use <a href="/solutions/web-shop/authentication-and-analytics/set-up-authentication/#web_shop_guide_shop_with_auth_set_up_auth_xsolla_login_how_to_get_it">user authentication via Xsolla Login</a>.</li>
          </ul>
        </td>
    </tr>
    <tr>
        <td>Digital Distribution Hub</td>
        <td>Required</td>
        <td>
          <ul>
            <li>User validation.</li>
            <li>Linking the transaction ID on Xsolla side with the transaction ID in your system.</li>
            <li>Transferring additional transaction parameters in the order.</li>
            <li>Crediting purchased items to the user and debiting items in case of order cancellation.</li>
          </ul>
          <p>Refer to the <a href="/solutions/ddh/#integration_guide_ddh_webhook">documentation</a> for detailed information on setting up webhooks for the Digital Distribution Hub.</p>
        </td>
    </tr>
    <tr>
        <td>Login</td>
        <td>Optional</td>
        <td>
          <p>Receiving event information:</p>
          <ul>
            <li>user registration/ authorization</li>
            <li>user email address confirmation</li>
            <li>linking a user’s social media account</li>
          </ul>
          <p>Refer to the <a href="/api/login/operation/add-webhook-for-event/">Login documentation</a> for detailed information on setting up webhooks.</p>
        </td>
    </tr>
  </tbody>
</table>

# List of required webhooks {% #list-of-required-webhooks %}
If you use products and solutions that require working with webhooks, <a href="/webhooks/overview/#section/Set-up-webhooks-in-Publisher-Account">enable and test the webhooks in your Publisher Account</a> and <a href="/webhooks/overview/#section/Webhook-listener">set up their processing</a>.
When specific events occur, webhooks are sent sequentially.
Therefore, if you do not process one of the webhooks, subsequent webhooks will not be sent. The list of required webhooks is presented below.

## Store and Payments {% #store-and-payments %}
2 webhook sending options have been set up on Xsolla’s side when purchasing and returning items on the site — information with payment and transaction data and information about purchased items can come separately or can be combined into one webhook.

<b>Receiving information in combined webhooks:</b>

If you registered in <a href="https://publisher.xsolla.com/">Publisher Account</a> after January 22, 2025, you receive all the information in the <a href="/webhooks/operation/successful-order-payment">Successful payment for order</a> (`order_paid`) and <a href="/webhooks/operation/order-cancellation">Order cancellation</a> (`order_canceled`) webhooks. In this case, you do not need to process the <a href="/webhooks/operation/payment">Payment</a> (`payment`) and <a href="/webhooks/operation/refund">Refund</a> (`refund`) webhooks.

<b>Receiving information in separate webhooks:</b>

If you registered in <a href="https://publisher.xsolla.com/">Publisher Account</a> on or before January 22, 2025,  you receive the following webhooks:
- <a href="/webhooks/operation/payment">Payment</a> (`payment`) and <a href="/webhooks/operation/refund">Refund</a> (`refund`) with information about payment data and transaction details.
- <a href="/webhooks/operation/successful-order-payment-separate">Successful payment for order</a> (`order_paid`) and <a href="/webhooks/operation/order-cancellation-separate">Order cancellation</a> (`order_canceled`) with information about purchased items.

You need to process all incoming webhooks.
To switch to the new option with receiving combined webhooks, contact your Customer Success Managers or email to <a href="mailto:csm@xsolla.com">csm@xsolla.com</a>.

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

<b>If you receive combined webhooks</b>:

<table>
  <thead>
    <tr>
        <th>Webhook name and type</th>
        <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td>User validation &gt; <a href="/webhooks/operation/user-validation/">User validation</a> (<code>user_validation</code>)</td>
        <td>Is sent at different stages of the payment process to ensure the user is registered in the game.</td>
    </tr>
    <tr>
        <td>Game services &gt; Combined webhooks &gt; <a href="/webhooks/operation/successful-order-payment">Successful payment for order</a> (<code>order_paid</code>)</td>
        <td>It contains payment data, transaction details, and information about purchased items. Use the data from the webhook to add items to the user.</td>
    </tr>
    <tr>
        <td>Game services &gt; Combined webhooks &gt; <a href="/webhooks/operation/order-cancellation">Order cancellation</a> (<code>order_canceled</code>)</td>
        <td>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.</td>
    </tr>
  </tbody>
</table>


<b>If you receive separate webhooks</b>:

<table>
  <thead>
    <tr>
        <th>Webhook name and type</th>
        <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td>User validation &gt; <a href="/webhooks/operation/user-validation/">User validation</a> (<code>user_validation</code>)</td>
        <td>Is sent at different stages of the payment process to ensure the user is registered in the game.</td>
    </tr>
    <tr>
        <td>Payments &gt; <a href="/webhooks/operation/payment">Payment</a> (<code>payment</code>)</td>
        <td>It contains payment data and transaction details.</td>
    </tr>
    <tr>
        <td>Game services &gt; Separate webhooks &gt; <a href="/webhooks/operation/successful-order-payment-separate">Successful payment for order</a> (<code>order_paid</code>)</td>
        <td>It contains information about purchased items. Use the data from the webhook to add items to the user.</td>
    </tr>
    <tr>
        <td>Payments &gt; <a href="/webhooks/operation/refund">Refund</a> (<code>refund</code>)</td>
        <td>It contains payment data and transaction details.</td>
    </tr>
    <tr>
        <td>Game services &gt; Separate webhooks &gt; <a href="/webhooks/operation/order-cancellation-separate">Order cancellation</a> (<code>order_canceled</code>)</td>
        <td>It contains information about the purchased items and the ID of the canceled transaction. Use the data from the webhook to remove the purchased items.</td>
    </tr>
  </tbody>
</table>

If item catalog <a href="/doc/in-game-store/features/personalization">personalization</a> is implemented on your application’s side, set up processing of <a href="/webhooks/operation/personalized-partner-catalog">Catalog personalization on the partner’s side</a> webhook.

<div lang="en" class="note">
 <p><strong>Note</strong></p>
 <p>To receive real payments, you only need to <a href="/doc/in-game-store/integration-guide/sign-licensing-agreement/">sign the licensing agreement</a> and implement processing of the webhooks:</p>
 <p><ul><li><a href="/webhooks/operation/payment">Payment</a>, <a href="/webhooks/operation/successful-order-payment-separate">Successful payment for order</a>, and <a href="/webhooks/operation/user-validation/">User validation</a> if you receive separate webhooks</li><li><a href="/webhooks/operation/successful-order-payment">Successful payment for order</a> and <a href="/webhooks/operation/user-validation/">User validation</a> if you receive combined webhooks</li></ul></p>
</div>

## Subscriptions {% #required-webhooks-subscriptions %}
To automatically manage subscription plans, it is necessary to implement processing of the main webhooks:
- <a href="/webhooks/operation/user-validation/">User validation</a> (`user_validation`) — is sent at different stages of the payment process to ensure the user is registered in the game.
- <a href="/webhooks/operation/payment">Payment</a> (`payment`) — is sent when an order is paid and contains payment data and transaction details.
- <a href="/webhooks/operation/created-subscription/">Created subscription</a> (`create_subscription`) — is sent when a <a href="/webhooks/operation/payment">Payment</a> webhook has been successfully processed or the user has purchased a subscription with a trial period. It contains the details of the purchased subscription and user data. Use the webhook data to add a subscription to the user.
- <a href="/webhooks/operation/updated-subscription/">Updated subscription</a> (`update_subscription`) — is sent when a subscription is renewed or changed, when a <a href="https://developers.xsolla.com/webhooks/operation/payment">Payment</a> webhook has been successfully processed. It contains the details of the purchased subscription and user data. Use the webhook data to extend the user's subscription or change the subscription parameters.
- <a href="/webhooks/operation/refund">Refund</a> (`refund`) — is sent when an order is canceled and contains the canceled payment data and transaction details.
- <a href="/webhooks/operation/canceled-subscription/">Canceled subscription</a> (`cancel_subscription`) — is sent when a <a href="/webhooks/operation/refund">Refund</a> webhook has been successfully processed or the subscription was canceled for another reason. It contains information about the subscription and user data. Use the webhook data to deduct purchased subscriptions from the user.

# Set up webhooks in Publisher Account {% #set-up-webhooks-in-publisher-account %}

## General settings {% #general-settings %}

To enable receiving webhooks:
1. In the project in Publisher Account go to <a href="https://publisher.xsolla.com/0/projects/0/edit/webhooks/">Project settings &gt; Webhooks</a> section.
2. In the <b>Webhook server</b> field, specify the URL of your server 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.

<div lang="en" class="notice">
  <p><strong>Notice</strong></p>
  <p>To transfer data, HTTPS protocol is required; use of HTTP protocol is not supported.</p>
</div>

<p></p>

3. Generate a secret key:

<ol><ol type="a">
  <li>In the <strong>Secret keys</strong> section, click <strong>Add key</strong>.</li>
  <li>In the modal window that opens, enter the key name that would allow you to identify it in the general list.</li>
  <li>Click <strong>Create key</strong>.</li>
  <li>Click <strong>Copy secret</strong> and save the created key on your side.</li>
  <li>Click <strong>Done</strong>.</li>
  <li>Confirm that you have saved the key and click <strong>Ok, close</strong>.</li>
</ol></ol>

![Add key](https://cdn.xsolla.net/developers/current/images/api_docs/webhooks/add-key.svg)

<div lang="en" class="notice">
  <p><strong>Notice</strong></p>
  <p>Key recommendations:<ul>
  <li><strong>Save the generated secret key on your side</strong>. You can view the key in Publisher Account only once when it is created.</li>
  <li>Don’t share your secret key with anyone.</li>
  <li>The secret key must be stored on your server and never in binaries or on the front end.</li></ul>
  </p>
</div>

4. Click **Enable webhooks**.

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>To test webhooks, you can select any dedicated website, such as <a href="https://webhook.site/#!/">webhook.site</a>, or a platform, such as <a href="https://ngrok.com/">ngrok</a>.</p>
</div>

<p></p>

<div lang="en" class="notice">
    <p><strong>Notice</strong></p>
    <p>You can’t simultaneously send webhooks to different URLs. What you can do in Publisher Account is specify a URL for testing first, and then replace it with the real one.</p>
</div>

To disable receiving webhooks:
1.  In the project in Publisher Account go to <a href="https://publisher.xsolla.com/0/projects/0/edit/webhooks/">Project settings &gt; Webhooks</a> section.
2. Click <b>Disable webhooks</b>.

## Secret key rotation {% #secret-key-rotation %}

Updating secret keys regularly enhances the security of your integration. You can create up to 5 secret keys in your project to enable their rotation. To do this:

1. In the <a href="https://publisher.xsolla.com/0/projects/0/edit/webhooks/">Project settings &gt; Webhooks</a> section, click **Add key**.

![Add key](https://cdn.xsolla.net/developers/current/images/api_docs/webhooks/add-new-key.svg)

2. In the modal window that opens, enter the key name that would allow you to identify it in the general list.
3. Click **Create key**.
4. Click **Copy secret** and save the created key on your side.
5. Click **Done**.
6. Confirm that you have saved the key and click **Ok, close**.

<div lang="en" class="notice">
  <p><strong>Notice</strong></p>
  <p>Key recommendations:<ul>
  <li><strong>Save the generated secret key on your side</strong>. You can view the key in Publisher Account only once when it is created.</li>
  <li>Don’t share your secret key with anyone.</li>
  <li>The secret key must be stored on your server and never in binaries or on the front end.</li></ul>
  </p>
</div>

There can be only one active secret key per project. If you want to change it, click **Set as active** in the row of another key and confirm the action. Once you successfully migrate to a new key, we recommend deleting deactivated keys.

![Change active key](https://cdn.xsolla.net/developers/current/images/api_docs/webhooks/activate-key.svg)

## Advanced settings {% #advanced-settings %}

For the webhooks in the <a href="/webhooks/overview/#section/Test-webhooks-in-Publisher-Account/Store">Payments and Store</a> section, advanced settings are available.
They will automatically appear under the <a href="/webhooks/overview/#section/Set-up-webhooks-in-Publisher-Account/General-settings">General settings</a> block after you click the <b>Get webhooks</b> button.

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>If the advanced settings are not displayed, make sure that webhook reception is connected in the general settings and you are on the <b>Testing &gt; Payments and Store</b> tab.</p>
</div>

In this section, you can set up the receipt of additional information in webhooks. To do this, set the corresponding switches to the active position. The line of each permission indicates the webhooks that will be affected by changing the settings.

<table>
  <thead>
    <tr>
        <th>Toggle</th>
        <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td>Show info about the saved payment account (displayed only if you registered in Publisher Account on or before January 22, 2025 and receive separate webhooks).</td>
        <td>Information about the saved payment method is passed in the <code>payment_account</code> custom object.</td>
    </tr>
    <tr>
        <td>Show info about transactions via saved payment methods.</td>
        <td><p>Information is passed in the following custom parameters of the webhook:</p><ul><li><code>saved_payment_method</code>:<ul><li><code>0</code> — the saved payment method was not used</li><li><code>1</code> —  the payment method was saved when making the current payment</li><li><code>2</code> — the previously saved payment method is used</li></ul></li><li><code>payment_type</code>:<ul><li><code>1</code> — one-time payment</li><li><code>2</code> — recurring payment</li></ul></li></ul></td>
    </tr>
    <tr>
        <td>Add <code>order</code> object to webhook (displayed only if you registered in Publisher Account on or before January 22, 2025 and receive separate webhooks).</td>
        <td>Information about the order is passed in the <code>order</code> object of the <a href="/webhooks/operation/payment/">Payment</a> webhook.</td>
    </tr>
    <tr>
        <td>Send only necessary user parameters without sensitive data.</td>
        <td><p>Only the following information about the user is passed in the webhook:</p><ul><li>ID</li><li>country</li></ul></td>
    </tr>
    <tr>
        <td>Send custom parameters.</td>
        <td>Information about <a href="/api/pay-station/operation/create-token/">custom token parameters</a> is passed in the webhook.</td>
    </tr>
    <tr>
        <td>Show card BIN and suffix.</td>
        <td><p>The following information about the bank card number is passed in the webhook:</p><ul><li>the first 6 digits in the <code>card_bin</code> parameter</li><li>the last 4 digits in the <code>card_suffix</code></li></ul></td>
    </tr>
    <tr>
        <td>Show card brand.</td>
        <td>The brand of the card used for making the payment. For example, Mastercard or Visa.</td>
    </tr>
    <tr>
        <td>Show info about the refund reason.</td>
        <td>Detailed information about refund reasons.</td>
    </tr>
    <tr>
        <td>Show country WHC and user acquisition fees.</td>
        <td>The <code>payment_details.​country_wht</code> and <code>payment_details.​user_acquisition_fee</code> objects will be passed in the webhook. This toggle is turned on by default.</td>
    </tr>
    <tr>
        <td>Send 3DS info.</td>
        <td>The <code>cards</code> object containing data on 3-D Secure verification will be passed in the webhook.</td>
    </tr>
  </tbody>
</table>

![Advanced settings](https://cdn.xsolla.net/developers/current/images/api_docs/webhooks/advanced-settings.png)

# Test webhooks in Publisher Account {% #test-webhooks-in-publisher-account %}

Testing webhooks helps to ensure the correct setup of the project both on your side and on Xsolla side.

If webhooks are <a href="/webhooks/overview/#section/Set-up-webhooks-in-Publisher-Account">set up</a> successfully, a webhooks testing section is displayed below the webhooks setup section.

![Webhooks testing section](https://cdn.xsolla.net/developers/current/images/api_docs/webhooks/testing-section.svg)

The testing section in Publisher Account varies depending on the webhook receiving option.

If you registered in Publisher Account after January 22, 2025, you receive combined webhooks:

<table>
  <thead>
    <tr>
        <th>Tab name for webhook testing</th>
        <th>Webhook name and type</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td><b>Payments and store</b></td>
        <td>User validation &gt; <a href="/webhooks/operation/user-validation/">User validation</a> (<code>user_validation</code>)</td>
    </tr>
    <tr>
        <td></td>
        <td>Game services &gt; Combined webhooks &gt; <a href="/webhooks/operation/successful-order-payment">Successful payment for order</a> (<code>order_paid</code>)</td>
    </tr>
    <tr>
        <td></td>
        <td>Game services &gt; Combined webhooks &gt; <a href="/webhooks/operation/order-cancellation">Order cancellation</a> (<code>order_canceled</code>)</td>
    </tr>
    <tr>
        <td><b>Subscriptions</b></td>
        <td>User validation &gt; <a href="/webhooks/operation/user-validation/">User validation</a> (<code>user_validation</code>)</td>
    </tr>
    <tr>
        <td></td>
        <td>Payments &gt; <a href="/webhooks/operation/payment">Payment</a> (<code>payment</code>)</td>
    </tr>
  </tbody>
</table>


If you registered in Publisher Account on or before January 22, 2025, you receive separate webhooks:

<table>
  <thead>
    <tr>
        <th>Tab name for webhook testing</th>
        <th>Webhook name and type</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td><b>Store</b></td>
        <td>Game services &gt; Separate webhooks &gt; <a href="/webhooks/operation/successful-order-payment-separate">Successful payment for order</a> (<code>order_paid</code>)</td>
    </tr>
    <tr>
        <td></td>
        <td>Game services &gt; Separate webhooks &gt; <a href="/webhooks/operation/order-cancellation-separate">Order cancellation</a> (<code>order_canceled</code>)</td>
    </tr>
    <tr>
        <td><b>Payments</b></td>
        <td>User validation &gt; <a href="/webhooks/operation/user-validation/">User validation</a> (<code>user_validation</code>)</td>
    </tr>
    <tr>
        <td></td>
        <td>Payments &gt; <a href="/webhooks/operation/payment">Payment</a> (<code>payment</code>)</td>
    </tr>
    <tr>
        <td><b>Subscriptions</b></td>
        <td>User validation &gt; <a href="/webhooks/operation/user-validation/">User validation</a> (<code>user_validation</code>)</td>
    </tr>
    <tr>
        <td></td>
        <td>Payments &gt; <a href="/webhooks/operation/payment">Payment</a> (<code>payment</code>)</td>
    </tr>
  </tbody>
</table>

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>If a warning that the test has not passed appears in the testing section, check the webhook response settings in your <a href="/webhooks/overview/#section/Webhook-listener">webhook listener</a>. The reasons for the errors in testing are indicated in the test results.</p>
  <p><b>Example:</b></p>
  <p>You use the specialized site <a href="https://webhook.site/#!/">webhook.site</a> for testing.</p>
  <p>An error is displayed in the <b>Testing response to invalid signature</b> section.</p>
  <p>This happens because Xsolla sends a webhook with an incorrect signature and expects your handler to respond with a <code>4xx</code> HTTP code specifying the <code>INVALID_SIGNATURE</code> error code.</p>
  <p><a href="https://webhook.site/#!/">webhook.site</a> sends a <code>200</code> HTTP code in response to all webhooks, including a webhook with an incorrect signature. The expected <code>4xx</code> HTTP code cannot be obtained, so an error is displayed in the test result.</p>
</div>

The process of testing for the scenario with combined webhooks is described below.

## Payments and Store {% #payments-and-store %}

In the <b>Payments and Store</b> tab, you can test the following webhooks:
- <a href="/webhooks/operation/user-validation/">User validation</a> (`user_validation`)
- <a href="/webhooks/operation/successful-order-payment">Successful payment for order</a> (`order_paid`)
- <a href="/webhooks/operation/order-cancellation">Order cancellation</a> (`order_canceled`)

To test webhooks:
1. In the webhooks testing section, go to the <b>Payments and Store</b> tab.
2. In the drop-down list, select the item type. If you haven’t set up this item type in Publisher Account yet, click the button to configure it. After creating the item, return to the webhook testing section and proceed to the next step.
3. Fill in the necessary fields:
    * **User ID** — when testing, you can use any combination of letters and digits.
    * Enter any value in the **Xsolla order ID** field.
    * **Xsolla invoice ID** — transaction ID on Xsolla side. When testing, you can use any numeric value.
    * **Invoice ID** — transaction ID on your game’s side. When testing, you can use any combination of letters and digits. It is not a required parameter for a successful payment, but you can pass it to link the transaction ID on your side to the transaction ID on Xsolla side.
    * **Amount** — payment amount. When testing, you can use any numeric value.
    * **Currency** — select a currency from the drop-down list.
    * Select the items’ SKU from the drop-down list and indicate the amount. You can choose multiple items of the same type by clicking **+** and adding them in a new line.
4. Click **Test webhooks**.

<a href="/webhooks/operation/user-validation/">User validation</a>, <a href="/webhooks/operation/successful-order-payment">Successful payment for order</a> and <a href="/webhooks/operation/order-cancellation">Order cancellation</a> webhooks with the specified data are sent to the provided URL. The results of testing each webhook type are displayed below the <b>Test webhooks</b> button.

If the <b>Use public user ID</b> box is checked in the <a href="https://publisher.xsolla.com/0/projects/0/edit/advanced">Project settings > Integration settings</a> section, the <a href="/webhooks/user-validation/user-search">User search</a> webhook will also be sent to your webhook server URL and the testing result will be displayed.

For each webhook, you need to configure processing both scenarios: a successful one and the one with an error.

![Payments testing section](https://cdn.xsolla.net/developers/current/images/api_docs/webhooks/testing-results.svg)

## Subscriptions {% #test-webhooks-subscriptions %}

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>To test webhooks, you should have at least one <a href="/sell-subscriptions/integration-guide/set-up-plan/">subscription plan created</a> in Publisher Account in the <a href="https://publisher.xsolla.com/0/projects/0/subscriptions/plans">Items catalog &gt; Subscriptions</a> section.</p>
</div>

In the <b>Subscriptions</b> tab, you can test the following webhooks:
- <a href="/webhooks/operation/user-validation/">User validation</a> (`user_validation`)
- <a href="/webhooks/operation/payment">Payment</a> (`payment`)

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>You can find detailed information about testing other subscription management scenarios in the <a href="/sell-subscriptions/integration-guide/set-up-plan/#guides_subscriptions_set_up_plan_testing_purchase">integration guide</a>.</p>
</div>

To test webhooks:

1. In the testing section, go to the **Subscriptions** tab.
2. Fill in the necessary fields:
    * **User ID** — when testing, you can use any combination of letters and digits.
    * **Xsolla invoice ID** — transaction ID on Xsolla side. When testing, you can use any numeric value.
    * **Public user ID** — ID known to a user, e.g., an email or nickname. This field is displayed if you checked the **Use public user ID** box in your project in the [Project settings > Integration settings](https://publisher.xsolla.com/0/projects/0/edit/advanced) section.
    * **Amount** — payment amount. When testing, you can use any numeric value.
    * **Currency** — select a currency from the drop-down list.
    * **Plan ID** — a subscription plan. Choose a plan from the drop-down list.
    * **Subscription product** — choose a product from the drop-down list (optional). The list is displayed if [products](/sell-subscriptions/integration-guide/get-started/#guides_subscriptions_glossary_product) are set up in your project.
    * **Invoice ID** — transaction ID on your game’s side. When testing, you can use any combination of letters and digits. It is not a required parameter for a successful payment, but you can pass it to link the transaction ID on your side to the transaction ID on Xsolla side.
    * **Trial period**. To test the [purchase of a subscription without a trial period](/sell-subscriptions/integration-guide/get-subscription-information/#guides_subscriptions_get_subscription_set_up_webhooks_sandbox) or to test the [renewal of a subscription](/sell-subscriptions/integration-guide/get-subscription-information/#guides_subscriptions_get_subscription_set_up_webhooks_test_renewal), specify the value `0`.
3. Click **Test**.

In the specified URL, you will receive webhooks with filled in data. Testing results of each webhook, for both a successful scenario and a scenario with an error, are displayed under the <b>Test</b> button.

# Webhook listener {% #webhook-listener %}

Webhook listener is program code that allows receiving incoming webhooks at a specified URL address, <a href="/webhooks/overview/#section/Webhook-listener/Generation-of-signature">generating a signature</a>, and <a href="/webhooks/overview/#section/Webhook-listener/Sending-responses-to-webhook">sending a response</a> to the Xsolla webhook server.

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>You can use the <a href="https://developers.xsolla.com/sdk/php/">Pay Station PHP SDK library</a>, which contains ready-made classes for processing webhooks.</p>
</div>

<!-- IMPORTANT! Changing the list of IP addresses should be coordinated with the administrators. Request for Director of Infrastructure and IT approval in the ticket for changing the IP address list. -->

On the your application side, implement the reception of webhooks from the following IP addresses:
- `185.30.20.0/24`
- `185.30.21.0/24`
- `185.30.22.0/24`
- `185.30.23.0/24`
- `34.102.38.178`
- `34.94.43.207`
- `35.236.73.234`
- `34.94.69.44`
- `34.102.22.197`

If you integrated <a href="/doc/login/">Login</a> product, additionally add processing webhooks from the following IP addresses:

- `34.94.0.85`
- `34.94.14.95`
- `34.94.25.33`
- `34.94.115.185`
- `34.94.154.26`
- `34.94.173.132`
- `34.102.48.30`
- `35.235.99.248`
- `35.236.32.131`
- `35.236.35.100`
- `35.236.117.164`

Limitations:
- There should not be multiple successful transactions with the same ID in your application's database.
- If the webhook listener received a webhook with an ID that already exists in the database, you need to return the result of the previous processing of this transaction. It is not recommended to credit the user with a duplicate purchase and create duplicate records in the database.

## Generation of signature {% #generation-of-signature %}

To ensure secure data transmission, you must verify that the webhook was actually sent from the Xsolla server and hasn't been tampered with during transit. To do this, generate your own signature based on the request body payload and compare it with the signature provided in the `authorization` header of the incoming request. If the signatures match, the webhook is authentic and safe to process.

Verification steps:

1. Retrieve the signature from the `authorization` header of the incoming webhook request. The header format is `Signature <signature_value>`.
2. Retrieve the webhook request body in JSON format. <div class="notice"><p><strong>Notice</strong></p><p>Use the JSON payload exactly as received. Do not parse or re-encode the payload, as this will alter the formatting and cause signature verification to fail.</p></div><p></p>

3. Generate your own signature for comparison:
   <ol type="a">
   <li>Concatenate the JSON payload with your project's secret key by appending the key to the end of the string.</li>
   <li>Apply the SHA-1 cryptographic hash function to the resulting string. The result will be a lowercase hexadecimal string.</li>
   </ol>
4. Compare your generated signature with the one from the `authorization` header. If they match, the webhook is authentic.

Below you can find signature generation implementation examples for the following languages: C#, C++, Go, PHP, and Node.js.

### Example of a webhook (HTTP): {% #example-of-a-webhook-http %}

```http
POST /your_uri HTTP/1.1
host: your.host
accept: application/json
content-type: application/json
content-length: 165
authorization: Signature 52eac2713985e212351610d008e7e14fae46f902
{
  "notification_type":"user_validation",
  "user":{
      "ip":"127.0.0.1",
      "phone":"18777976552",
      "email":"email@example.com",
      "id":1234567,
      "name":"Xsolla User",
      "country":"US"
  }
}
```

### Example of a webhook (curl): {% #example-of-a-webhook-curl %}

```bash
curl -v 'https://your.hostname/your/uri' \
-X POST \
-H 'authorization: Signature 52eac2713985e212351610d008e7e14fae46f902' \
-d '{
  "notification_type":
    "user_validation",
    "user":
      {
        "ip": "127.0.0.1",
        "phone": "18777976552",
        "email": "email@example.com",
        "id": 1234567,
        "name": "Xsolla User",
        "country": "US"
      }
    }'
```

### C# example of implementing signature generation (general sample): {% #csharp-signature-generation-general-sample %}

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>This code sample is compatible with .NET Framework 4.0 and later, as well as with .NET Core and other modern .NET versions. Signature verification uses constant-time comparison via the <code>ConstantTimeEquals</code> method to help prevent timing attacks.</p>
</div>

```csharp
using System;
using System.Security.Cryptography;
using System.Text;
public static class XsollaWebhookSignature
{
    public static string ComputeSha1(string jsonBody, string secretKey)
    {
        // Concatenation of the JSON from the request body and the project's secret key
        string dataToSign = jsonBody + secretKey;
        using (SHA1 sha1 = SHA1.Create())
        {
            byte[] hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
            // Convert hash bytes to lowercase hexadecimal string
            var hexString = new StringBuilder(hashBytes.Length * 2);
            foreach (byte b in hashBytes)
            {
                hexString.Append(b.ToString("x2"));
            }
            return hexString.ToString();
        }
    }
    public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
    {
        string computedSignature = ComputeSha1(jsonBody, secretKey);
        string receivedSignatureLower = receivedSignature.ToLower();
        // Use constant-time comparison to prevent timing attacks
        return ConstantTimeEquals(computedSignature, receivedSignatureLower);
    }
    private static bool ConstantTimeEquals(string a, string b)
    {
        if (a.Length != b.Length)
        {
            return false;
        }
        int result = 0;
        for (int i = 0; i < a.Length; i++)
        {
            result |= a[i] ^ b[i];
        }
        return result == 0;
    }
}
```

### C# example of implementing signature generation (.NET 5.0 and later): {% #csharp-signature-generation-net-5-0-and-later %}

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>To use the <code>Convert.ToHexString</code> method, you need .NET 5.0 and later.<p></p>If you have .NET 7.0 and later, you can also use the <code>CryptographicOperations.FixedTimeEquals</code> method instead of <code>ConstantTimeEquals</code>.</p>
</div>

```csharp
// For .NET 5.0 and later, you can use the more concise Convert.ToHexString method:
using System;
using System.Security.Cryptography;
using System.Text;
public static class XsollaWebhookSignature
{
    public static string ComputeSha1(string jsonBody, string secretKey)
    {
        string dataToSign = jsonBody + secretKey;
        using var sha1 = SHA1.Create();
        byte[] hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
        return Convert.ToHexString(hashBytes).ToLower();
    }
    public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
    {
        string computedSignature = ComputeSha1(jsonBody, secretKey);
        string receivedSignatureLower = receivedSignature.ToLower();
        // Use constant-time comparison to prevent timing attacks
        return ConstantTimeEquals(computedSignature, receivedSignatureLower);
    }
    private static bool ConstantTimeEquals(string a, string b)
    {
        if (a.Length != b.Length)
        {
            return false;
        }
        int result = 0;
        for (int i = 0; i < a.Length; i++)
        {
            result |= a[i] ^ b[i];
        }
        return result == 0;
    }
}
```

### C# example of implementing signature generation (.NET 7.0 and later): {% #csharp-signature-generation-net-7-0-and-later %}

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>If you have .NET 7.0 and later, you can use the <code>CryptographicOperations.FixedTimeEquals</code> method.</p>
</div>

```csharp
// For .NET 7.0+, you can use the built-in CryptographicOperations.FixedTimeEquals:
using System.Security.Cryptography;
public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
{
    string computedSignature = ComputeSha1(jsonBody, secretKey);
    byte[] computedBytes = Encoding.UTF8.GetBytes(computedSignature);
    byte[] receivedBytes = Encoding.UTF8.GetBytes(receivedSignature.ToLower());
    return CryptographicOperations.FixedTimeEquals(computedBytes, receivedBytes);
}
```

### C++ example of implementing signature generation: {% #cpp-signature-generation %}

```c++
#include <string>
#include <sstream>
#include <iomanip>
#include <openssl/sha.h>
class XsollaWebhookSignature {
public:
    static std::string computeSha1(const std::string& jsonBody, const std::string& secretKey) {
        // Concatenation of the JSON from the request body and the project's secret key
        std::string dataToSign = jsonBody + secretKey;
        unsigned char digest[SHA_DIGEST_LENGTH];
        // Create SHA1 hash
        SHA1(reinterpret_cast<const unsigned char*>(dataToSign.c_str()),
             dataToSign.length(), digest);
        // Convert to lowercase hexadecimal string
        std::ostringstream hexStream;
        hexStream << std::hex << std::setfill('0');
        for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) {
            hexStream << std::setw(2) << static_cast<unsigned int>(digest[i]);
        }
        return hexStream.str();
    }
    static bool verifySignature(const std::string& jsonBody, const std::string& secretKey, const std::string& receivedSignature) {
        std::string computedSignature = computeSha1(jsonBody, secretKey);
        // Timing-safe comparison
        if (computedSignature.length() != receivedSignature.length()) {
            return false;
        }
        volatile unsigned char result = 0;
        for (size_t i = 0; i < computedSignature.length(); ++i) {
            result |= (computedSignature[i] ^ receivedSignature[i]);
        }
        return result == 0;
    }
};
```

### Go example of implementing signature generation: {% #go-signature-generation %}

```go
package main
import (
	"crypto/sha1"
    "crypto/subtle"
	"encoding/hex"
	"strings"
)
type XsollaWebhookSignature struct{}
func (x *XsollaWebhookSignature) ComputeSha1(jsonBody, secretKey string) string {
	// Concatenation of the JSON from the request body and the project's secret key
	dataToSign := jsonBody + secretKey
	// Create SHA1 hash
	h := sha1.New()
	h.Write([]byte(dataToSign))
	signature := h.Sum(nil)
	// Convert to lowercase hexadecimal string
	return strings.ToLower(hex.EncodeToString(signature))
}
func (x *XsollaWebhookSignature) VerifySignature(jsonBody, secretKey, receivedSignature string) bool {
	computedSignature := x.ComputeSha1(jsonBody, secretKey)
	receivedSignatureLower := strings.ToLower(receivedSignature)
	// Use constant time comparison to prevent timing attacks
	return subtle.ConstantTimeCompare([]byte(computedSignature), []byte(receivedSignatureLower)) == 1
}
```

### PHP example of implementing signature generation: {% #php-signature-generation %}

```php
<?php
class XsollaWebhookSignature
{
    /**
     * Compute SHA1 signature from webhook JSON body and secret key
     *
     * @param string $jsonBody The raw JSON body from webhook
     * @param string $secretKey The project's secret key
     * @return string The lowercase SHA1 signature
     */
    public static function computeSha1(string $jsonBody, string $secretKey): string
    {
        // Concatenation of the JSON from the request body and the project's secret key
        $dataToSign = $jsonBody . $secretKey;
        // Generate SHA1 signature
        $signature = sha1($dataToSign);
        return strtolower($signature);
    }
    /**
     * Verify webhook signature using timing-safe comparison
     *
     * @param string $jsonBody The raw JSON body from webhook
     * @param string $secretKey The project's secret key  
     * @param string $receivedSignature The signature from authorization header
     * @return bool True if signature is valid, false otherwise
     */
    public static function verifySignature(string $jsonBody, string $secretKey, string $receivedSignature): bool
    {
        $computedSignature = self::computeSha1($jsonBody, $secretKey);
        // Use hash_equals for timing-safe comparison
        return hash_equals($computedSignature, strtolower($receivedSignature));
    }
}
?>
```

### Node.js example of implementing signature generation: {% #nodejs-signature-generation %}

```js
const crypto = require('crypto');
class XsollaWebhookSignature {
    // IMPORTANT: jsonBody must be the raw JSON string exactly as received from Xsolla
    static computeSha1(jsonBody, secretKey) {
        // Concatenation of the JSON from the request body and the project's secret key
        const dataToSign = jsonBody + secretKey;
        // Create SHA1 hash
        const hash = crypto.createHash('sha1');
        hash.update(dataToSign, 'utf8');
        // Convert to lowercase hexadecimal string
        return hash.digest('hex').toLowerCase();
    }
    static verifySignature(jsonBody, secretKey, receivedSignature) {
        const computedSignature = this.computeSha1(jsonBody, secretKey);
        const cleanReceivedSignature = receivedSignature.toLowerCase();
        // Check if signatures have the same length before using timingSafeEqual
        if (computedSignature.length !== cleanReceivedSignature.length) {
            return false;
        }
        try {
            return crypto.timingSafeEqual(
                Buffer.from(computedSignature, 'hex'),
                Buffer.from(cleanReceivedSignature, 'hex')
            );
        } catch (error) {
            // Return false if there's any error (e.g., invalid hex characters)
            return false;
        }
    }
}
```

## Sending responses to webhook {% #sending-responses-to-webhook %}

To confirm receipt of the webhook, your server must return:
* `200`, `201`, or `204` HTTP code in case of a successful response.
* `400` HTTP code with <a href="/webhooks/overview/#section/Errors">description of the problem</a> if the specified user was not found or an invalid signature was passed.
Your webhook handler may also return a `5xx` HTTP code in case of temporary issues on your server.

If the Xsolla server did not receive a response to <a href="/webhooks/operation/successful-order-payment">Successful payment for order</a> and <a href="/webhooks/operation/order-cancellation">Order cancellation</a> webhooks or received a response with a `5xx` code, the webhooks are resent according to the following schedule:
* 2 attempts with a 5-minute interval
* 7 attempts with a 15-minute interval
* 10 attempts with a 60-minute interval

Maximum of 20 attempts to send webhooks are made within 12 hours from the first attempt.

The retry logic for the <a href="/webhooks/operation/payment">Payment</a> and <a href="/webhooks/operation/refund">Refund</a> webhooks is described on the respective webhook page.

<div lang="en" class="notice">
  <p><strong>Notice</strong></p>
  <p>The payment will still be refunded to the user if all of the following conditions are met:<ul><li>The refund was initiated by Xsolla.</li><li>In response to a webhook, a <code>4xx</code> status code was returned, or no response was received after all retry attempts, or a <code>5xx</code> status code was returned.</li></ul></p>
</div>

If the Xsolla server did not receive a response to the <a href="/webhooks/operation/user-validation/">User validation</a> webhook or received a response with a code of `400` or `5xx`, the <a href="/webhooks/operation/user-validation/">User validation</a> webhook is not resent.
In this case, the user sees an error and the <a href="/webhooks/operation/payment">Payment</a> and <a href="/webhooks/operation/successful-order-payment">Successful payment for order</a> webhooks are not sent.

# Errors {% #errors %}

Error codes for HTTP code 400:

<table>
  <thead>
    <tr>
        <th>Code</th>
        <th>Message</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td>INVALID_USER</td>
        <td>Invalid user</td>
    </tr>
    <tr>
        <td>INVALID_PARAMETER</td>
        <td>Invalid parameter</td>
    </tr>
    <tr>
        <td>INVALID_SIGNATURE</td>
        <td>Invalid signature</td>
    </tr>
    <tr>
        <td>INCORRECT_AMOUNT</td>
        <td>Incorrect amount</td>
    </tr>
    <tr>
        <td>INCORRECT_INVOICE</td>
        <td>Incorrect invoice</td>
    </tr>
  </tbody>
</table>

```
HTTP/1.1 400 Bad Request
{
    "error":{
        "code":"INVALID_USER",
        "message":"Invalid user"
    }
}
```

# Best practices {% #best-practices %}

## Security {% #security %}

Follow these guidelines:

* Use HTTPS only, with a valid certificate.
* Always verify the signature against the raw request body — don’t parse or re-encode the data.
* Don’t pass sensitive data in URLs and avoid exposing technical details in error messages.
* Exempt the webhook endpoint from [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) middleware — incoming requests from Xsolla don’t include a CSRF token and will be rejected without this setting.
* Allowlist [Xsolla IP addresses](/webhooks/section/webhook-listener).


## Webhook handler architecture {% #webhook-handler-architecture %}

Follow these guidelines:

1. Accept the `POST` request with the body and headers as-is, **without modification**.
2. [Verify the webhook signature](/webhooks/section/webhook-listener/generation-of-signature) and return the appropriate status code:
    * `4xx` — if the signatures don’t match;
    * `2xx` — in success cases. We recommend returning `204 No Content` **before** executing the main business logic. `200 OK` is also acceptable.
3. Pass the payload to an async job or queue for further processing.
4. Implement [idempotency](https://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning). You must ensure your system can handle [receiving the same webhook more than once](/webhooks/section/webhook-listener/sending-responses-to-webhook).

**Flow example:**

```http
HTTP POST /webhooks/xsolla
  read raw_body, headers
  if !verify_signature(raw_body, headers['authorization']):
     return 400 {"error":{"code":"INVALID_SIGNATURE","message":"Invalid signature"}}
  enqueue(raw_body)
  return 204  # or 200
```

## Idempotency and duplicates {% #idempotency-and-duplicates %}

Follow these guidelines:

* Use the transaction ID and/or [external ID](/dev-resources/faq/payments/#faq_payments_q_new_transaction_external_id), order ID as idempotency keys.
* Store processed IDs and return the previous result if a duplicate is received.
* Avoid item regranting, duplicate database entries, and double charges.
* Keep in mind that with sequential delivery, a failure on an earlier event blocks the processing of all subsequent ones.

## System resilience {% #system-resilience %}

Follow these guidelines:

* Use queues and async processing for resource-intensive operations such as third-party API calls, billing, and item granting.
* Set timeouts on the webhook handler (1–3 s). For transient failures, rely on the [Xsolla retry mechanism](/webhooks/section/webhook-listener/sending-responses-to-webhook).
* Don’t implement retries in the webhook handler — redelivery is handled by Xsolla.
* Log webhook delivery timestamps and processing statuses; set up alerts for spikes in `5xx` errors and redeliveries.
* Propagate correlation IDs from the webhook into your logs and monitoring system (APM).
* Set up error logging and monitoring. For non-recoverable failures, move jobs to a dead-letter queue (DLQ). Develop a secure tool for replaying events that is protected by an idempotency mechanism.

## Implementation examples {% #implementation-examples %}

**Success purchase — item granted on first attempt:**

![Purchase](https://cdn.xsolla.net/developers/current/images/api_docs/webhook-schemes/purchase-v2.svg)

**Duplicate delivery (partner timeout on first attempt):**

![Timeout](https://cdn.xsolla.net/developers/current/images/api_docs/webhook-schemes/timeout-v2.svg)

**Refund:**

![Refund](https://cdn.xsolla.net/developers/current/images/api_docs/webhook-schemes/refund-v2.svg)

**Partner outage**:

![Partner outage](https://cdn.xsolla.net/developers/current/images/api_docs/webhook-schemes/server-error.svg)

# FAQs {% #faqs %}

## Do I need to use HTTPS for a webhook protocol? {% #do-i-need-to-use-https-for-a-webhook-protocol %}

Yes.

## Can I receive payment webhooks at several URLs? {% #can-i-receive-payment-webhooks-at-several-urls %}

No. Payment webhooks use the Server-to-Server protocol and are sent to a single URL specified in the [project settings](/webhooks/section/set-up-webhooks-in-publisher-account). If you would like to receive notifications in your game, website, or mobile application, set up sending webhooks on your server to pass data between Xsolla and your game. You can also test webhooks from the developer console.

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>If you are testing the integration locally, `POST` requests from Xsolla don’t reach URLs like <code>http://localhost:3000/my-webhook-endpoint</code>. Use services such as <a href="https://ngrok.com/">Ngrok</a> that allow you to create a tunnel for external access, enabling you to receive requests from Xsolla locally. E.g., you can read more about this in the <a href="https://ngrok.com/docs/guides/share-localhost/webhooks#test-webhooks-locally">ngrok documentation</a>.</p>
</div>

## Why was Xsolla notification not sent to the webhook URL? {% #why-was-xsolla-notification-not-sent-to-the-webhook-url %}

Make sure that your webhook server supports the `POST` and `GET` types of HTTP requests.

## How do I prevent duplicate transaction IDs during processing? {% #how-do-i-prevent-duplicate-transaction-ids-during-processing %}

Use the external ID — this is the transaction ID in your game, assigned to the order in your system. On the Xsolla side, the external ID is linked to the transaction ID, which allows Xsolla to prevent duplicate payments for the same transaction. For configuration details, Refer to our [documentation](/dev-resources/faq/payments/#faq_payments_q_new_transaction_external_id) for detailed information about configuration.

## Are there any best practices for working with webhooks? {% #are-there-any-best-practices-for-working-with-webhooks %}

We recommend:

* Returning `204` or `200` immediately after signature verification.
* Verifying the webhook signature against the raw request body, without modification.
* Implementing idempotency for all operations.
* Logging all events and setting up error monitoring.
* Avoiding sensitive data in URLs and not exposing technical details in error messages.

Refer to the [Best practices](/webhooks/section/best-practices) section for detailed information.

# Webhook integration checklist {% #webhook-integration-checklist %}

For webhooks to work correctly, make sure the following in place before going live:

* HTTPS is used.
* Webhook [signature verification](/webhooks/section/webhook-listener/generation-of-signature) is implemented against the raw request body, without modification.
* A `204/200` response is returned as soon as the signature is confirmed.
* Idempotency is implemented for all operations.
* Error logging and monitoring are configured.
* Sensitive data is not passed in URLs, and technical details are not exposed in error messages.
* Webhook retries are supported in accordance with [Xsolla retry logic](/webhooks/section/webhook-listener/sending-responses-to-webhook).
* The entire integration is documented.

# Webhooks list {% #webhooks-list %}

<div lang="en" class="note">
  <p><strong>Note</strong></p>
  <p>The notification type is sent in the <code>notification_type</code> parameter.</p>
</div>

<table>
  <thead>
    <tr>
        <th>Webhook</th>
        <th>Notification type</th>
        <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
        <td><a href="/webhooks/operation/user-validation/">User validation</a></td>
        <td><code>user_validation</code></td>
        <td>Sent to check if a user exists in the game.</td>
    </tr>
    <tr>
        <td><a href="/webhooks/operation/user-search/">User search</a></td>
        <td><code>user_search</code></td>
        <td>Sent to get user info based on public user ID.</td>
    </tr>
    <tr>
        <td><a href="/webhooks/operation/payment/">Payment</a></td>
        <td><code>payment</code></td>
        <td>Sent when a user completes a payment.</td>
    </tr>
    <tr>
        <td><a href="/webhooks/operation/refund/">Refund</a></td>
        <td><code>refund</code></td>
        <td>Sent when a payment must be canceled for any reason.</td>
    </tr>
    <tr>
        <td><a href="/webhooks/operation/partial-refund/">Partial refund</a></td>
        <td><code>partial_refund</code></td>
        <td>Sent when a payment must be partially canceled for any reason.</td>
    </tr>
    <tr>
        <td><a href="/webhooks/operation/payment-declined/">Declined payment</a></td>
        <td><code>ps_declined</code></td>
        <td>Sent when a payment is declined by payment system.</td>
    </tr>
    <tr>
        <td><a href="https://developers.xsolla.com/webhooks/operation/afs-rejected-transaction/">AFS rejected transaction</a></td>
        <td><code>afs_reject</code></td>
        <td>Sent when a transaction is declined during an AFS check.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/afs-rejected-blocklist/">AFS updated blocklist</a></td>
      <td><code>afs_black_list</code></td>
      <td>Sent when the AFS blocklist is updated.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/created-subscription/">Created subscription</a></td>
      <td><code>create_subscription</code></td>
      <td>Sent when a user creates a subscription.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/updated-subscription/">Updated subscription</a></td>
      <td><code>update_subscription</code></td>
      <td>Sent when a subscription is renewed or changed.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/canceled-subscription/">Canceled subscription</a></td>
      <td><code>cancel_subscription</code></td>
      <td>Sent when a subscription is canceled.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/nonrenewing-subscription/">Nonrenewing subscription</a></td>
      <td><code>non_renewal_subscription</code></td>
      <td>Sent when status is set to nonrenewing.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/add-payment-account/">Add payment account</a></td>
      <td><code>payment_account_add</code></td>
      <td>Sent when a user adds or saves a payment account.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/remove-payment-account/">Remove payment account</a></td>
      <td><code>payment_account_remove</code></td>
      <td>Sent when a user removes the payment account from saved accounts.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/user-validation-in-webshop">User validation in Web Shop</a></td>
      <td><code>-</code></td>
      <td>Sent from a Web Shop site to check if a user exists in the game.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/personalized-partner-catalog">Catalog personalization on partner’s side</a></td>
      <td><code>partner_side_catalog</code></td>
      <td>Sent when a user interacts with the store.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/successful-order-payment">Successful payment for order</a></td>
      <td><code>order_paid</code></td>
      <td>Sent when an order is paid.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/order-cancellation">Order cancellation</a></td>
      <td><code>order_canceled</code></td>
      <td>Sent when an order is canceled.</td>
    </tr>
    <tr>
      <td><a href="https://developers.xsolla.com/webhooks/operation/dispute">Dispute</a></td>
      <td><code>dispute</code></td>
      <td>Sent when a new dispute is opened.</td>
    </tr>
  </tbody>
</table>


Version: 1.0

## Servers

```
https://api.xsolla.com/merchant/v2
```

## Download OpenAPI description

[Webhooks](https://xsolla.redocly.app/_bundle/webhooks/index.yaml)

## User validation

### User validation

 - [POST user-validation](https://xsolla.redocly.app/webhooks/user-validation/user-validation.md): Xsolla sends a webhook with the user_validation type to the webhook URL to verify that a user is registered in the game. The request is sent multiple times as part of the payment process:

* when a user chooses a payment method in the payment UI
* when a user enters data in the payment form, e.g., bank card data or the ZIP code when paying via PayPal
* when a user clicks Pay now to proceed with payment
* when payment process is completed and the transaction status changes to done

The request is sent when paying with any payment methods.

When you save the webhook URL in Publisher Account, you can give permissions to receive detailed information in webhooks. To do that, set the necessary toggles to active in Publisher Account in the Project settings &gt; Webhooks &gt; Advanced settings section.


  Note
  If you registered in Publisher Account on or before January 22, 2025, you can find the toggles in the Project settings &gt; Webhooks &gt; Testing &gt; Payments &gt; Advanced settings section.



  
    
        Toggle
        Description
    
  
  
    
        Send only necessary user parameters without sensitive data
        Only the following information about the user is passed in the webhook:IDcountry
    
    
        Send custom parameters
        Information about custom token parameters is passed in the webhook.

### User search

 - [POST user-search](https://xsolla.redocly.app/webhooks/user-validation/user-search.md): Public User ID is a parameter that uniquely identifies the user and is known to them, unlike User ID (Public User ID can be email, screen name, etc). Xsolla sends a webhook with the user_search type when a purchase is made outside the game store (e.g., via cash kiosks).

### User validation in Web Shop

 - [POST user-validation-in-webshop](https://xsolla.redocly.app/webhooks/user-validation/user-validation-in-webshop.md): Xsolla sends a webhook from a Web Shop site to check if a user exists in the game. The webhook is sent from the following IP address: 34.102.38.178.
Note
Webhook is used only for user validation in Web Shop. Refer to these instructions for more information about configuring webhooks in Site Builder.

## Payments

### Payment

 - [POST payment](https://xsolla.redocly.app/webhooks/payments/payment.md): When a user completes a payment,  Xsolla sends payment details in a webhook with the payment type to the webhook URL.

The expected response codes are described in the Responses section, but you can use other response codes as well:


    
    
        Response code
        Description
    
    
    
    
        200, 201, 204
        A successful response.
    
    
        4xx
        An error occurred. For example, if the specified user was not found or an invalid signature was passed.
    
    
        5xx
        A temporary server error. When this response is received,  Xsolla will automatically retry sending the webhook, gradually increasing the interval between attempts until your listener confirms receiving. The maximum number of retries is 12 retry attempts over a 48-hour period.
    
    


When you save the webhook URL in Publisher Account, you can also set up receiving additional information in webhooks.


  Note
  If you registered in Publisher Account on or before January 22, 2025, you can find the toggles in your project in the Settings &gt; Webhooks &gt; Testing &gt; Payments &gt; Advanced settings section.



  
    
        Toggle
        Description
    
  
  
    
        Show info about the saved payment account
        Information about the saved payment method is passed in the payment_account custom object.
    
    
        Show info about transactions via saved payment methods
        Information is passed in the following custom parameters of the webhook:saved_payment_method:0 — the saved payment method was not used1 —  the payment method was saved when making the current payment2 — the previously saved payment method is usedpayment_type:1 — one-time payment2 — recurring payment
    
    
        Add order object to webhook
        Information about the order is passed in the order object of the Payment webhook.
    
    
        Send only necessary user parameters without sensitive data
        Only the following information about the user is passed in the webhook:IDcountry
    
    
        Show card BIN and suffix
        The following information about the bank card number is passed in the webhook:the first 6 digits in the card_bin parameterthe last 4 digits in the card_suffix
    
    
        Show card brand
        The brand of the card used for making the payment. For example, Mastercard or Visa.
    
    
        Show country WHC and user acquisition fees.
        The payment_details.​country_wht and payment_details.​user_acquisition_fee objects will be passed in the webhook. This toggle is turned on by default.
    
    
        Send 3DS info.
        The cards object containing data on 3-D Secure verification will be passed in the webhook.
    
  



  Notice
  The set of fields sent in a webhook depends on:the advanced settings configured in Publisher Accountthe custom settings configured on the Xsolla sideIf you have any questions, contact your Customer Success Manager or email to csm@xsolla.com.

### Refund

 - [POST refund](https://xsolla.redocly.app/webhooks/payments/refund.md): When a payment is canceled, Xsolla sends details of the canceled transaction in a webhook with the refund type to the webhook URL.

The webhook retry mechanism depends on who initiated the refund:
* If the refund was initiated on your side, the webhook isn’t resent. The payment is refunded to the user regardless of the response to a webhook.
* If the refund was initiated by a third party — e.g., a payment system or Xsolla Customer Support team — and in response to a webhook, a 5xx status code was returned, the webhook is resent at increasing intervals. The maximum number of retries is 12 within 48 hours from the first attempt.

For detailed information about the refund process, refer to the instructions.


  Notice
  The payment will still be refunded to the user if all of the following conditions are met:The refund was initiated by Xsolla.In response to a webhook, a 4xx status code was returned, or no response was received after all retry attempts, or a 5xx status code was returned.


When you save the webhook URL in Publisher Account, you can also set up receiving additional information in webhooks.


  Note
  If you registered in Publisher Account on or before January 22, 2025, you can find the toggles in your project in the Settings &gt; Webhooks &gt; Testing &gt; Payments &gt; Advanced settings section.



  
    
        Toggle
        Description
    
  
  
    
        Show info about transactions via saved payment methods
        Information is passed in the following custom parameters of the webhook:saved_payment_method:0 — the saved payment method was not used1 —  the payment method was saved when making the current payment2 — the previously saved payment method is usedpayment_type:1 — one-time payment2 — recurring payment
    
    
        Show info about the refund reason.
        Detailed information about refund reasons.
    
  


Refund codes:


    
    
        Code
        Reason
        Description
    
    
    
    
        1
        Cancellation by the user request / the game request
        Cancellation initiated from Publisher Account.
    
    
        2
        Chargeback
        Transaction chargeback requested.
    
    
        3
        Integration error
        Issues in integration between Xsolla and the game.Recommendation: Do not add the user to blocklist.
    
    
        4
        Potential fraud – AFS reject
        Transaction rejected because the Xsolla Anti-fraud system detected potential fraud.
    
    
        5
        Test payment
        Test transaction followed by cancellation.Recommendation: Do not add the user to blocklist.
    
    
        6
        User invoice expired
        Invoice overdue (used for postpaid model).
    
    
        7
        Fraud notification from PS
        Payment rejected because the payment system detected potential fraud.Recommendation: Add the user to blocklist.
    
    
        8
        Cancellation by the PS request
        Cancellation requested by payment system.Recommendation: Do not add the user to blocklist.
    
    
        9
        Cancellation by the user request
        The user was not satisfied with the game or the purchase for any reason.Recommendation: Do not add the user to blocklist.
    
    
        10
        Cancellation by the game request
        Cancellation requested by the game.Recommendation: Do not add the user to blocklist.
    
    
        11
        Account holder called to report fraud
        The account owner states that they didn’t make the transaction.Recommendation: Add the user to blocklist.
    
    
        12
        Potential fraud – friendly fraud
        Legitimate cardholder has disputed their transaction.
    
    
        13
        Duplicate
        Duplicate transaction for the same invoice.
    
    
        21
        Potential fraud – BIN attack
        Cards stolen from one or multiple BINs in a batch. A key indicator is a burst of attempts sharing a BIN range over a short window, often with enumerated card numbers.
    
    
        22
        Potential fraud – monetization fraud
        Stolen card used to buy tradable items for the purpose of resale.
    
    
        23
        Potential fraud – low-scale card fraud
        Cards stolen from one or multiple BINs. Not as widespread and coordinated as the BIN attack (refund code 21).
    
    
        24
        Potential fraud – regional price abuse
        Regional pricing or key resale abuse. Users exploited regional prices — typically via location or payment-method misrepresentation — to acquire items cheaply for resale in higher-priced markets.
    
    
        25
        Potential fraud – partner or PS exploit
        Credential theft and account takeover — abuse of a partner-side or payment-system-side account or integration rather than direct card abuse.
    
    
        26
        Potential fraud – not definable
        Confirmed fraud but there is not enough evidence to determine the exact attack type.
    
    
        27
        Fraud notification from PS – linked transactions
        The transaction itself was not specified in the payment system fraud report, but it is connected, e.g., via a shared card or device, to transactions that were refunded on a fraud-related basis.

### Partial refund

 - [POST partial-refund](https://xsolla.redocly.app/webhooks/payments/partial-refund.md): When a partial refund is made, Xsolla sends details of the canceled transaction in a webhook with the partial_refund type to the webhook URL. Learn more about the partial refund process in these instructions.

When you save the webhook URL in Publisher Account, you can give permissions to receive detailed information in webhooks. To do that, set the following toggle to active in Publisher Account in the Project settings &gt; Webhooks &gt; Advanced settings section.


  Note
  If you registered in Publisher Account on or before January 22, 2025, you can find the toggles in the Project settings &gt; Webhooks &gt; Testing &gt; Payments &gt; Advanced settings section.



  
    
        Toggle
        Description
    
  
  
    
        Show info about transactions via saved payment methods
        Information is passed in the following custom parameters of the webhook:saved_payment_method:0 — the saved payment method was not used1 —  the payment method was saved when making the current payment2 — the previously saved payment method is usedpayment_type:1 — one-time payment2 — recurring payment
    
  


Refund codes:


    
    
        Code
        Reason
        Description
    
    
    
    
        1
        Cancellation by the user request / the game request
        Cancellation initiated from Publisher Account.
    
    
        3
        Integration error
        Issues in integration between Xsolla and the game.Recommendation: Do not add the user to blocklist.
    
    
        5
        Test payment
        Test transaction followed by cancellation.Recommendation: Do not add the user to blocklist.
    
    
        7
        Fraud notification from PS
        Payment rejected because the payment system detected potential fraud.Recommendation: Add the user to blocklist.
    
    
        9
        Cancellation by the user request
        The user was not satisfied with the game or the purchase for any reason.Recommendation: Do not add the user to blocklist.
    
    
        10
        Cancellation by the game request
        Cancellation requested by the game.Recommendation: Do not add the user to blocklist.

### Declined payment

 - [POST payment-declined](https://xsolla.redocly.app/webhooks/payments/payment-declined.md): If a transaction is declined by a payment system, Xsolla sends the transaction details in a webhook of the ps_declined type to your configured webhook URL.
The webhook is sent during the authorization or payment processing stage.
In this case, the payment\ order_paid webhook is not sent.

Typical reasons for payment system declines:

* Card authorization failed (for example, the payment system could not complete the authorization process due to a technical error or no response from the bank) or was declined (for example, the bank responded but refused the transaction due to insufficient funds or invalid card details).
* 3-D Secure verification failed, was not completed, or the user confirmation timed out.
* The processor or acquiring bank is temporarily unavailable or returns a hard decline due to an irreversible error, such as a closed account or an invalid card number. Retrying without addressing the underlying issue will not result in a successful transaction.

Should not be confused with:

* Anti-fraud rejections, which are reported via the afs_reject webhook.
* Refunds and partial refunds after a successful payment, which are reported via the refund and partial_refund webhooks.


  Note
  To receive the ps_declined webhook, contact your Customer Success Manager or email csm@xsolla.com.

### Add payment account

 - [POST add-payment-account](https://xsolla.redocly.app/webhooks/payments/add-payment-account.md): Xsolla sends a webhook with the payment_account_add type to the webhook URL whenever a user adds a payment account or saves a payment account when purchasing something inside the game. To receive this webhook, contact your Customer Success Manager or email csm@xsolla.com.

### Remove payment account

 - [POST remove-payment-account](https://xsolla.redocly.app/webhooks/payments/remove-payment-account.md): When a user removes the payment account from saved accounts, Xsolla sends a webhook with the payment_account_remove type to the webhook URL. To receive this webhook, contact your Customer Success Manager or email csm@xsolla.com.

## Combined webhooks

### Successful payment for order (with payment and transaction details)

 - [POST successful-order-payment](https://xsolla.redocly.app/webhooks/combined-webhooks/successful-order-payment.md): Xsolla sends the order_paid webhook to the specified URL when the user successfully pays for the order.

The order_paid webhook contains information about the purchased items, payment data and transaction details.

The order_paid webhook is not sent if the payment is not successful, for example:
* the payment form was opened, but the user did not pay for the order
* the payment form was opened, but there were errors during the payment

It is recommended that the processing time of the order_paid  webhook  is less than 3 seconds.


  Notice
  The set of fields sent in a webhook depends on the following settings:the ones you configured in Publisher Account in the Project settings &gt; Webhooks &gt; Advanced settings sectionthe ones configured on the Xsolla sideIf you have any questions, contact your Customer Success Manager or email to csm@xsolla.com.


The expected answers are described in the Responses section.
You can use other response codes. Depending on the response code and the connection of the automatic payment refund functionality, the webhook processing logic on Xsolla’s side is as follows:


    
    
        Response code
        Automatic payment refund is disabled (by default)
        Automatic payment refund is enabled
    
    
    
    
        400, 401, 402, 403, 404, 409, 422, 415
        No actions
        Automatic refund to the user
    
    
        200, 201, 204
        No actions
        No actions
    
    
        Different code or no response to webhook
        Multiple webhooks are sent within a specified time interval: 2 attempts with a 5-minute interval, 7 attempts with a 15-minute interval, 10 attempts with a 60-minute interval.
        Multiple webhooks are sent within a specified time interval: 2 attempts with a 5-minute interval, 7 attempts with a 15-minute interval, 10 attempts with a 60-minute interval. If all webhooks are sent but a successful response is not received, an automatic refund is issued to the user.
    
    


To connect the automatic refund functionality, contact your Customer Success Managers or email to csm@xsolla.com.

### Order cancellation (with payment and transaction details)

 - [POST order-cancellation](https://xsolla.redocly.app/webhooks/combined-webhooks/order-cancellation.md): Xsolla sends the order_canceled webhook to the specified URL when the payment is canceled by the user, partner, or automatically. The webhook contains information about returned items, payment data and details of the canceled order.

The webhook is not sent if the payment is not successful, for example:
* the payment UI was opened but the user did not pay for the order
* the payment UI was opened but there were errors during the payment

The recommended webhook processing time is within 3 seconds.

## Separate webhooks

### Successful payment for order (without payment and transaction details)

 - [POST successful-order-payment-separate](https://xsolla.redocly.app/webhooks/separate-webhooks/successful-order-payment-separate.md): Xsolla sends the order_paid webhook to the specified URL when the following conditions are fulfilled:
1. The user successfully paid for the order.
2. Xsolla received a response about the successful processing of payment webhook.

The order_paid webhook contains information about the purchased items and transaction details.

The order_paid webhook is not sent if:
* The payment was not successful, for example:
  * the payment form was opened, but the user did not pay for the order
  * the payment form was opened, but there were errors during the payment
* The response about the successful processing of the payment webhook has not been received.

It is recommended that the processing time of the order_paid  webhook  is less than 3 seconds.

The expected answers are described in the Responses section.
You can use other response codes. Depending on the response code and the connection of the automatic payment refund functionality, the webhook processing logic on Xsolla’s side is as follows:


    
    
        Response code
        Automatic payment refund is disabled (by default)
        Automatic payment refund is enabled
    
    
    
    
        400, 401, 402, 403, 404, 409, 422, 415
        No actions
        Automatic refund to the user
    
    
        200, 201, 204
        No actions
        No actions
    
    
        Different code or no response to webhook
        Multiple webhooks are sent within a specified time interval: 2 attempts with a 5-minute interval, 7 attempts with a 15-minute interval, 10 attempts with a 60-minute interval.
        Multiple webhooks are sent within a specified time interval: 2 attempts with a 5-minute interval, 7 attempts with a 15-minute interval, 10 attempts with a 60-minute interval. If all webhooks are sent but a successful response is not received, an automatic refund is issued to the user.
    
    


To connect the automatic refund functionality, contact your Customer Success Managers or email to csm@xsolla.com.

### Order cancellation (without payment and transaction details)

 - [POST order-cancellation-separate](https://xsolla.redocly.app/webhooks/separate-webhooks/order-cancellation-separate.md): Xsolla sends the order_canceled webhook to the specified URL when the payment was canceled by the user, partner, or automatically. The webhook contains information about returned items and details of the canceled order.

The webhook is not sent if the payment was not successful, for example:
* the payment UI was opened but the user did not pay for the order
* the payment UI was opened but there were errors during the payment

The recommended webhook processing time is within 3 seconds.

## Personalization webhook

### Catalog personalization on partner side

 - [POST personalized-partner-catalog](https://xsolla.redocly.app/webhooks/personalization/personalized-partner-catalog.md): Xsolla will send a partner_side_catalog webhook that contains the user and project parameters to the webhook URL when a user interacts with the store.

Return a list of item_id or item SKU that are available to the user in response. In this case, you can also include information that a particular user can buy a certain product a specified number of times. This feature allows you to control the number and type of products that the user can add to the cart and buy.


  Notice
  When processing the webhook, consider the following limitations:The webhook must be processed in under 3 seconds. If processing takes longer, the get virtual items list, create payment token, and create order API calls return an error.The webhook response size mustn’t exceed 64 KB. Responses exceeding this limit are not processed — the user sees an empty catalog and can’t purchase any items. To change the maximum response size, contact your Customer Success Manager or email to csm@xsolla.com.

## Anti-fraud

### Anti-fraud system rejected transaction

 - [POST afs-rejected-transaction](https://xsolla.redocly.app/webhooks/anti-fraud/afs-rejected-transaction.md): When a transaction is declined during an Anti-fraud system check, Xsolla sends transaction details in the webhook with the afs_reject type to the webhook URL. To receive this webhook, contact your Customer Success Manager or email csm@xsolla.com.

When you save the webhook URL in Publisher Account, you can give permissions to receive detailed information in webhooks. To do that, set the following toggle to active in Publisher Account in the Project settings &gt; Webhooks &gt; Advanced settings section.


  Note
  If you registered in Publisher Account on or before January 22, 2025, you can find the toggles in the Project settings &gt; Webhooks &gt; Testing &gt; Payments &gt; Advanced settings section.



  
    
        Toggle
        Description
    
  
  
    
        Show info about transactions via saved payment methods
        Information is passed in the following custom parameters of the webhook:saved_payment_method:0 — the saved payment method was not used1 —  the payment method was saved when making the current payment2 — the previously saved payment method is usedpayment_type:1 — one-time payment2 — recurring payment

### Anti-fraud blocklist update

 - [POST afs-rejected-blocklist](https://xsolla.redocly.app/webhooks/anti-fraud/afs-rejected-blocklist.md): When the Anti-fraud system blocklist is updated (add or remove a parameter), Xsolla sends a webhook with the afs_black_list type to the webhook URL. The parameter addition is performed automatically on the Xsolla side or on request. Parameter removal is possible only on request. To receive this webhook, contact your Customer Success Manager or email csm@xsolla.com.

### Dispute

 - [POST dispute](https://xsolla.redocly.app/webhooks/anti-fraud/dispute.md): When a new dispute is opened or a dispute changes its status, Xsolla sends a webhook with the dispute type to the webhook URL. To receive this webhook, contact your Customer Success Manager or email csm@xsolla.com.

## Subscriptions

### Created subscription

 - [POST created-subscription](https://xsolla.redocly.app/webhooks/subscriptions/created-subscription.md): When a user creates a subscription, Xsolla sends a webhook with the create_subscription type to the webhook URL.

### Updated subscription

 - [POST updated-subscription](https://xsolla.redocly.app/webhooks/subscriptions/updated-subscription.md): If some parameters in the subscription (plan_id, date_next_charge) were changed, and in the case of every subscription renewal, Xsolla sends a webhook with the update_subscription type to the webhook URL.

### Canceled subscription

 - [POST canceled-subscription](https://xsolla.redocly.app/webhooks/subscriptions/canceled-subscription.md): When a subscription is canceled, Xsolla sends a webhook with the cancel_subscription type to the webhook URL.

### Nonrenewing subscription

 - [POST nonrenewing-subscription](https://xsolla.redocly.app/webhooks/subscriptions/nonrenewing-subscription.md): When a subscription status is set to nonrenewing, Xsolla sends a webhook with the non_renewal_subscription type to the webhook URL. To receive this webhook, contact your Customer Success Manager or email csm@xsolla.com.

