# Sandbox test scenarios

**The server-side Merchant API checks to pass in Sandbox before you go live.**

Every check on this page is an API call your backend will make in production. This is a usage checklist for the [Merchant API](/docs/api/merchant): run each call with your Sandbox API key against the [Sandbox endpoints](/docs/guides/merchant/test-and-go-live/environments), and treat a passing check as proof that the operation works end-to-end.

:::note
These checks cover the server-side only. The client-side parts of your integration have their own checks, which live in each integration guide and differ by implementation - run both.
:::

Run the checks once your Sandbox [checkout flows](/docs/guides/merchant/test-and-go-live/testing/test-flows) work, as the last testing step before you go live. When the checks you need pass, your integration can run the operations your business depends on - move on to [Go live](/docs/guides/merchant/test-and-go-live/go-live) to switch to Production and use your integration in full, with real money and real customer data.

## How it works

Every check follows the same pattern: make the calls with your Sandbox credentials, then verify the result through the API response and in your [Sandbox Merchant dashboard](https://sandbox-business.revolut.com/merchant).

- All requests go to the [Sandbox endpoints](/docs/guides/merchant/test-and-go-live/environments) with your Sandbox API key in the `Authorization` header, and carry the `Revolut-Api-Version` header.
- To pay for an order, open its `checkout_url` (or run your integrated widget) and pay the way your customers will - see [Test cards](/docs/guides/merchant/test-and-go-live/testing/test-cards), [3DS simulator](/docs/guides/merchant/test-and-go-live/testing/3ds-simulator), and [Test payment flows](/docs/guides/merchant/test-and-go-live/testing/test-flows).
- The examples use a £5.00 order (`amount: 500`) in `GBP`.

:::warning [Amount-based Sandbox flows]
Some Sandbox scenarios are triggered by the order amount: specific Revolut Pay account-to-account and Google Pay amounts simulate declines and other outcomes - see [Test payment flows](/docs/guides/merchant/test-and-go-live/testing/test-flows) for the amount-based scenarios. 

The checks on this page verify the default successful behaviour, so pick amounts outside those ranges - the £5.00 (`amount: 500`) used in the examples is a safe choice.
:::

### Before you begin

Before you start, make sure you have:

- [ ] A Sandbox account and API key - see [Set up test environment](/docs/guides/merchant/test-and-go-live/set-up-test-environment).
- [ ] Your backend running against the Sandbox endpoints - see [Environments](/docs/guides/merchant/test-and-go-live/environments).
- [ ] A payment method you can exercise in checkout - see [Test cards](/docs/guides/merchant/test-and-go-live/testing/test-cards) and [Test payment flows](/docs/guides/merchant/test-and-go-live/testing/test-flows).

---

## Scenario checks

Each check is independent: run the ones that match the operations your business performs, and skip the rest - if you don't manage refunds through the API, skip the refund checks.

:::info
For the full contract behind each call, see the [Merchant API](/docs/api/merchant) reference.
:::

### Order management

Every payment your business takes lives on an order - the core object of the Merchant API. These checks prove your backend can create orders, get them paid, and control what happens next: capturing authorised funds, or cancelling orders that won't be fulfilled.

#### Create and pay for order

The baseline: prove your backend can create an order and see it through to a completed payment.

::::::details [Run this check]

1. [Create order](/docs/api/merchant#create-order) with minimal required parameters:

   - ![Request]

     ```http [Example request]
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2, 7}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "automatic",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

2. Open the order's `checkout_url` and pay for the order with your Sandbox payment method.
3. [Retrieve the order](/docs/api/merchant#retrieve-order) by its `id` and check its state:

   - ![Request]

     ```http [Example request]
     GET /api/orders/{order_id}
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {3}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "completed",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "automatic",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

:::tip [Expected results]
- [ ] The create call returns `201` with the order in `state: pending`.
- [ ] After payment, the retrieved order's `state` is `completed`.
- [ ] The transaction shows as **Completed** in your [Sandbox Merchant dashboard](https://sandbox-business.revolut.com/merchant).
:::

::::::

#### Capture an order later

Authorise now, capture when you're ready to fulfil - proves your backend handles the deferred-capture lifecycle.

::::::details [Run this check]

1. [Create order](/docs/api/merchant#create-order) with `capture_mode` set to `manual`:

   - ![Request]

     ```http [Example request] {10}
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "manual"
     }
     ```

   - ![Response]

     ```json [Example response] {2, 7}
      {
        "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
        "state": "pending",
        "amount": 500,
        "currency": "GBP",
        "capture_mode": "manual",
        "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
        ...
      }
      ```

2. Open the order's `checkout_url` and pay for the order with your Sandbox payment method, then [retrieve the order](/docs/api/merchant#retrieve-order) - the order ends up `authorised`, not `completed`:

   - ![Request]

     ```http [Example request]
     GET /api/orders/{order_id}
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {2, 3}
      {
        "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
        "state": "authorised",
        "amount": 500,
        "currency": "GBP",
        "capture_mode": "manual",
        "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
        ...
      }
      ```

3. [Capture the order](/docs/api/merchant#capture-order) for the authorised amount:

   - ![Request]

     ```http [Example request]
     POST /api/orders/{order_id}/capture
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500
     }
     ```

   - ![Response]

     ```json [Example response] {3}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "completed",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "manual",
       "payments": [
         {
           "state": "captured",
           "amount": 500,
           ...
         }
       ],
       ...
     }
     ```

:::tip [Expected results]
- [ ] After payment, the order's `state` is `authorised`.
- [ ] The capture call returns the order with `state: completed` and the payment `captured`.
- [ ] The transaction shows as **Completed** in your [Sandbox Merchant dashboard](https://sandbox-business.revolut.com/merchant).
:::

:::note
You can also capture from the dashboard: in your [Sandbox Merchant dashboard](https://sandbox-business.revolut.com/merchant), select the uncaptured transaction and click **Capture**.
:::

::::::

#### Cancel an unpaid order

Proves you can void an order the customer never paid - abandoned checkouts, stock issues, changed minds.

::::::details [Run this check]

1. [Create order](/docs/api/merchant#create-order) with minimal required parameters:

   - ![Request]

     ```http [Example request]
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

2. Do not pay for the order.
3. [Cancel the order](/docs/api/merchant#cancel-order) using the order's `id`:

   - ![Request]

     ```http [Example request]
     POST /api/orders/{order_id}/cancel
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {3}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "cancelled",
       "amount": 500,
       "currency": "GBP",
       ...
     }
     ```

:::tip [Expected results]
- [ ] The cancel call returns the order with `state: cancelled`.
- [ ] [Retrieving the order](/docs/api/merchant#retrieve-order) confirms the `cancelled` state.
:::

::::::

#### Cancel a paid, uncaptured order

Proves you can release an authorised payment you won't capture - without waiting for the authorisation to expire.

::::::details [Run this check]

1. [Create order](/docs/api/merchant#create-order) with `capture_mode` set to `manual`:

   - ![Request]

     ```http [Example request] {10}
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "manual"
     }
     ```

   - ![Response]

     ```json [Example response] {2, 6, 7}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "manual",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

2. Open the order's `checkout_url` and pay for the order with your Sandbox payment method, then [retrieve the order](/docs/api/merchant#retrieve-order) - the order ends up `authorised`, not `completed`:

   - ![Request]

     ```http [Example request]
     GET /api/orders/{order_id}
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {2,3}
      {
        "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
        "state": "authorised",
        "amount": 500,
        "currency": "GBP",
        "capture_mode": "manual",
        "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
        ...
      }
      ```

3. [Cancel the order](/docs/api/merchant#cancel-order) using the order's `id`:

   - ![Request]

     ```http [Example request]
     POST /api/orders/{order_id}/cancel
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {3}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "cancelled",
       "amount": 500,
       "currency": "GBP",
       ...
     }
     ```

:::tip [Expected results]
- [ ] The cancel call returns the order with `state: cancelled`.
- [ ] The transaction shows as **Cancelled** in your [Sandbox Merchant dashboard](https://sandbox-business.revolut.com/merchant).
:::

::::::

#### Create an order with customer and shipping details

Proves the order carries the customer and delivery data your fulfilment stack needs.

::::::details [Run this check]

1. [Create customer](/docs/api/merchant#create-customer):

   - ![Request]

     ```http [Example request]
     POST /api/customers
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "full_name": "Example Customer",
       "email": "example.customer@example.com",
       "phone": "+441234567890"
     }
     ```

   - ![Response]

     ```json [Example response] {2}
     {
       "id": "6c7c97a8-cfc1-4cf3-8b38-26a74fdf1fae",
       "full_name": "Example Customer",
       "email": "example.customer@example.com",
       "phone": "+441234567890",
       ...
     }
     ```

2. [Create order](/docs/api/merchant#create-order) with the customer and shipping details:

   - ![Request]

     ```http [Example request] {10-20}
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP",
       "customer": {
         "id": "{customer_id}"
       },
       "shipping": {
         "address": {
           "street_line_1": "1 Main Street",
           "city": "London",
           "country_code": "GB",
           "postcode": "E14 5AB"
         }
       }
     }
     ```

   - ![Response]

     ```json [Example response] {8-21}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "automatic",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       "customer": {
         "id": "6c7c97a8-cfc1-4cf3-8b38-26a74fdf1fae",
         "email": "example.customer@example.com",
         "phone": "+441234567890",
         "full_name": "Example Customer"
       },
       "shipping": {
         "address": {
           "street_line_1": "1 Main Street",
           "city": "London",
           "country_code": "GB",
           "postcode": "E14 5AB"
         }
       },
       ...
     }
     ```

:::tip [Expected results]
- [ ] The order response contains the `customer` object with the details that live on the customer record.
- [ ] The order response contains the `shipping` object with the address you sent.
- [ ] [Retrieving the order](/docs/api/merchant#retrieve-order) confirms the `customer` and `shipping` details are stored.
:::

::::::

### Refunds

Refunds are your after-sales operations - money back when a customer returns an item, or goodwill when something went wrong. If your business issues refunds through the API, these checks prove the full range: one total refund, partial refunds, and refunding to the last penny in consecutive steps.

#### Refund an order in full

Proves the full refund path: money back to the customer, tracked as its own order.

::::::details [Run this check]

1. [Create order](/docs/api/merchant#create-order) with minimal required parameters:

   - ![Request]

     ```http [Example request]
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

2. Open the order's `checkout_url` and pay for the order with your Sandbox payment method - [Retrieve the order](/docs/api/merchant#retrieve-order) by its `id` and check its state:

   - ![Request]

     ```http [Example request]
     GET /api/orders/{order_id}
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {2, 3}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "completed",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "automatic",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

3. [Refund the order](/docs/api/merchant#refund-order) for the full amount:

   - ![Request]

     ```http [Example request] {8}
     POST /api/orders/{order_id}/refund
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {3, 4}
     {
       "id": "6852e9a6-5cf0-ac65-8182-6a9c251011ce",
       "type": "refund",
       "state": "processing",
       "amount": 500,
       "currency": "GBP",
       "related_order_id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       ...
     }
     ```

:::tip [Expected results]
- [ ] The refund call returns a new order with `type: refund` and `state: processing`.
- [ ] [Retrieving the refund order](/docs/api/merchant#retrieve-order) by its `id` shows `state: completed`.
- [ ] The refund transaction shows as **Completed** in your [Sandbox Merchant dashboard](https://sandbox-business.revolut.com/merchant).
:::

::::::

#### Refund part of an order

Proves partial refunds - returns, discounts, goodwill - with the rest of the order untouched.

::::::details [Run this check]

1. [Create order](/docs/api/merchant#create-order) with minimal required parameters:

   - ![Request]

     ```http [Example request]
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

2. Open the order's `checkout_url` and pay for the order with your Sandbox payment method - [Retrieve the order](/docs/api/merchant#retrieve-order) by its `id` and check its state:

   - ![Request]

     ```http [Example request]
     GET /api/orders/{order_id}
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {2, 3}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "completed",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "automatic",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

3. [Refund the order](/docs/api/merchant#refund-order) for a partial amount - £2.00 (`amount: 200`):

   - ![Request]

     ```http [Example request] {8}
     POST /api/orders/{order_id}/refund
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 200,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2-4}
     {
       "id": "6852e9a6-5cf0-ac65-8182-6a9c251011ce",
       "type": "refund",
       "state": "processing",
       "amount": 200,
       "currency": "GBP",
       "related_order_id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       ...
     }
     ```

:::tip [Expected results]
- [ ] The refund call returns a new order with `type: refund` and `state: processing`.
- [ ] [Retrieving the refund order](/docs/api/merchant#retrieve-order) by its `id` shows `state: completed`.
- [ ] [Retrieving the original order](/docs/api/merchant#retrieve-order) shows `refunded_amount: 200`.
:::

::::::

#### Make multiple partial refunds

Proves your refund handling scales past a single partial refund.

::::::details [Run this check]

1. [Create order](/docs/api/merchant#create-order) with minimal required parameters:

   - ![Request]

     ```http [Example request]
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

2. Open the order's `checkout_url` and pay for the order with your Sandbox payment method - [Retrieve the order](/docs/api/merchant#retrieve-order) by its `id` and check its state:

   - ![Request]

     ```http [Example request]
     GET /api/orders/{order_id}
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {2, 3}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "completed",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "automatic",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

3. [Refund the order](/docs/api/merchant#refund-order) for £1.00 (`amount: 100`):

   - ![Request]

     ```http [Example request] {8}
     POST /api/orders/{order_id}/refund
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 100,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2-4}
     {
       "id": "6852e9a6-5cf0-ac65-8182-6a9c251011ce",
       "type": "refund",
       "state": "processing",
       "amount": 100,
       "currency": "GBP",
       "related_order_id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       ...
     }
     ```

4. Refund the order again for £2.00 (`amount: 200`).

:::tip [Expected results]
- [ ] Each refund call returns its own order with `type: refund`.
- [ ] [Retrieving the refund orders](/docs/api/merchant#retrieve-order) shows `state: completed` for each.
- [ ] [Retrieving the original order](/docs/api/merchant#retrieve-order) shows `refunded_amount: 300`.
:::

::::::

#### Fully refund an order through consecutive partial refunds

Proves refunding to the last penny in several steps - and that your integration handles the over-refund error.

::::::details [Run this check]

1. [Create order](/docs/api/merchant#create-order) with minimal required parameters:

   - ![Request]

     ```http [Example request]
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

2. Open the order's `checkout_url` and pay for the order with your Sandbox payment method - [Retrieve the order](/docs/api/merchant#retrieve-order) by its `id` and check its state:

   - ![Request]

     ```http [Example request]
     GET /api/orders/{order_id}
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     ```

   - ![Response]

     ```json [Example response] {2, 3}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "completed",
       "amount": 500,
       "currency": "GBP",
       "capture_mode": "automatic",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

3. [Refund the order](/docs/api/merchant#refund-order) for the first partial amount - £1.00 (`amount: 100`):

   - ![Request]

     ```http [Example request] {8}
     POST /api/orders/{order_id}/refund
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 100,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2-4}
     {
       "id": "6852e9a6-5cf0-ac65-8182-6a9c251011ce",
       "type": "refund",
       "state": "processing",
       "amount": 100,
       "currency": "GBP",
       "related_order_id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       ...
     }
     ```

4. Send further partial refunds until the full amount is refunded - for example, another £1.00 (`amount: 100`), then £3.00 (`amount: 300`).
5. Send one more refund request for any amount.

:::tip [Expected results]
- [ ] Each refund call returns its own order with `type: refund`.
- [ ] All refund orders reach `state: completed`.
- [ ] The final refund request - sent after the order is fully refunded - returns an error.
:::

::::::

### Webhooks

Payments complete asynchronously: your customer pays on their device, and the result reaches your backend after the request-response cycle is over. Webhooks are how your backend stays in sync with what actually happened - these checks prove you receive and act on the events in your payment flow.

#### Set up and listen to webhooks

Proves your backend learns about payments without polling - the events arrive at your URL.

::::::details [Run this check]

1. [Create a webhook](/docs/api/merchant#create-webhook) to listen to events in your payment flow:

   - ![Request]

     ```http [Example request] {9-12}
     POST /api/webhooks
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "url": "https://example.com/webhooks",
       "events": [
         "ORDER_AUTHORISED",
         "ORDER_COMPLETED"
       ]
     }
     ```

   - ![Response]

     ```json [Example response]
     {
       "id": "c6b981f4-53b3-47d5-9b24-4f87af1160eb",
       "url": "https://example.com/webhooks",
       "events": [
         "ORDER_AUTHORISED",
         "ORDER_COMPLETED"
       ],
       "signing_secret": "wsk_4jETWMz1g1b37gCONjNp84t2KSSIT7dK"
     }
     ```

2. [Create order](/docs/api/merchant#create-order) with minimal required parameters:

   - ![Request]

     ```http [Example request]
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

3. Pay for the order via its `checkout_url` and watch your endpoint. Each subscribed event arrives as a POST request to your `url`:

   ```json [Webhook event]
{
      "event": "ORDER_COMPLETED",
      "order_id": "6516e61c-d279-a454-a837-bc52ce55ed49"
    }
   ```

:::tip [Expected results]
- [ ] Your backend receives each event you subscribed to - for example, `ORDER_COMPLETED` for the paid order.
- [ ] The event's `order_id` matches the order you created.
:::

:::note
Respond to each delivery with any `200-399` status code (`204` recommended). If a delivery fails or times out, Revolut retries it 3 more times, 10 minutes apart.
:::

::::::

#### Allowlist webhook IPs

Proves your firewall lets Revolut's webhook deliveries through.

::::::details [Run this check]

1. If your server blocks incoming traffic, allowlist the [webhook IP addresses for your environment](/docs/guides/merchant/test-and-go-live/environments#webhooks).
2. With a webhook live - for example, from [Set up and listen to webhooks](#set-up-and-listen-to-webhooks) - [create order](/docs/api/merchant#create-order) with minimal required parameters:

   - ![Request]

     ```http [Example request]
     POST /api/orders
     Host: https://sandbox-merchant.revolut.com
     Authorization: Bearer sk_abcdef12347890_...
     Revolut-Api-Version: 2026-08-17
     Content-Type: application/json

     {
       "amount": 500,
       "currency": "GBP"
     }
     ```

   - ![Response]

     ```json [Example response] {2}
     {
       "id": "6516e61c-d279-a454-a837-bc52ce55ed49",
       "state": "pending",
       "amount": 500,
       "currency": "GBP",
       "checkout_url": "https://sandbox-checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
       ...
     }
     ```

3. Pay for the order via its `checkout_url` and confirm the events still arrive at your endpoint.

:::tip [Expected results]
- [ ] Your server receives the webhook events with the IP addresses allowlisted.
:::

::::::

---

## What's next

All the checks you need pass? Your backend can run the operations your business depends on - **time to take it to Production!**

- [:Rocket: Go live](/docs/guides/merchant/test-and-go-live/go-live 'Switch to Production and verify your first live payment')