# Build trials and introductory pricing

**Let customers try before they pay - or start them on a discounted introductory price that steps up to the regular rate.**

A trial gives customers the product for free for a stretch of time - the first payment lands only when the trial ends. Introductory pricing gives them a discounted start - a promotional first cycle or two at a lower price, stepping up to the regular rate automatically. The Subscriptions API supports both, and they combine: a customer can try your service for free with a trial period, then pass through a promotional phase, then settle into the regular price.

In this guide, you'll sell a **Premium plan** - £19.00 a month with a 14-day free trial as the plan's default. One variation charges the regular price throughout; a second starts new customers on a discounted £9.90 first month. The guide signs up a new customer - no payment method on file yet - with a 30-day promotional trial in place of the plan's default, and collects their payment method through the same setup-order flow every subscription uses.

## How it works

This guide walks you through the full flow: all API calls run between your backend and the Merchant API, and only one part - [step 3](#3-collect-payment-method), collecting the payment method - happens on the customer's device.

1. **Create the plan** - the Premium plan carries a 14-day free trial, and one variation starts new customers on a discounted first month.
2. **Subscribe the customer** - the trial starts with the subscription: the customer has no saved payment method, so it starts `pending` with the trial running; attaching a payment method that's already on file instead activates it immediately. You can also override or skip the trial per customer.
3. **Collect the payment method** - through the setup order, same as in other subscription flows: the trial buys time, and the subscription activates the moment the method is saved - nothing is collected until the trial ends.
4. **Bill regularly** - nothing is billed during the trial; the first payment lands when it ends, and every cycle after bills automatically.

The trial's timeline is shaped by two optional settings - offer a free trial, introductory pricing, or both:

| Mechanism | Set on | Bills during | Ends when |
| --------- | ------ | ------------ | --------- |
| Free trial | The plan - `trial_duration` - overridable per subscription | Nothing | The trial ends and the first payment is collected |
| Introductory pricing | A variation - sequential phases | The phase's discounted `amount` | The phase's `cycle_count` completes and the next phase's price applies |

```mermaid
flowchart TD
    subgraph plan ["Premium plan with 14-day trial"]
        subgraph variation1 ["Standard variation"]
            phase1["Phase 1 - £19.00/month, ongoing"]
        end
        subgraph variation2 ["Intro-pricing variation"]
            phase2["Phase 1 - £9.90 x 1 cycle"]
            phase3["Phase 2 - £19.00/month, ongoing"]
        end
    end
    phase2 --> phase3
```

The Premium plan carries its 14-day free trial alongside the variations customers subscribe to - `trial_duration` is a plan-level attribute, one setting that applies to every subscription within that plan. On the subscription, the trial doesn't add a cycle of its own: cycles keep their standard duration and count, and a cycle that starts inside the trial period - before the subscription's `trial_end_date` - is simply flagged `trial: true`. Nothing is billed until the trial ends; the subscribed variation's phases set the price from the following cycle on.

:::tip[Collect the payment method early]
The trial delays the first payment, not the payment method collection.

Collect payment details during sign-up - the subscription activates as soon as it's on file, and the first payment then waits for the trial to end without the customer needing to visit again.
:::

### Before you begin

- [ ] You've completed **[Get started with the Subscriptions API](/docs/guides/merchant/billing-subscriptions/api/get-started)** - it introduces the universal subscription flow this guide builds on
- [ ] Familiarity with the **core subscription concepts** - see [Subscription plans](/docs/guides/merchant/billing-subscriptions/subscription-plans) and [Subscription lifecycle](/docs/guides/merchant/billing-subscriptions/subscription-lifecycle)
- [ ] A **customer** to subscribe - the walkthrough signs up a new one with no saved payment method; see [Get started with the Subscriptions API](/docs/guides/merchant/billing-subscriptions/api/get-started) for creating customers

---

## Implement subscription with trials

The steps below follow the Premium plan narrative: the plan carries the trial default, a new customer subscribes to the Standard variation with a 30-day promotional override, and the subscription starts `pending` - with the trial already running - until their payment method lands in [step 3](#3-collect-payment-method).

### 1. Create plan with trial duration

Trials and introductory pricing are set at different levels of the plan. `trial_duration` lives on the plan itself - a free period that applies to every subscription unless overridden. Introductory pricing lives on a variation - sequential **phases**, each holding a price for a number of cycles. One plan can carry both.

:::info
For the plan, variation, and phase hierarchy these fields sit in, see [Get started with the Subscriptions API](/docs/guides/merchant/billing-subscriptions/api/get-started).
:::

Call [Create a subscription plan](/docs/api/merchant#create-subscription-plan) to turn your trial terms and pricing steps into a subscribable plan:

- ![Request]
  ```http [Request example] {9,22-39}
  POST /api/subscription-plans HTTP/1.1
  Content-Type: application/json
  Authorization: Bearer sk_abcdef12347890_...
  Revolut-Api-Version: 2026-08-17
  Host: merchant.revolut.com

  {
    "name": "Premium",
    "trial_duration": "P14D",
    "variations": [
      {
        "name": "Standard",
        "phases": [
          {
            "ordinal": 1,
            "cycle_duration": "P1M",
            "amount": 1900,
            "currency": "GBP"
          }
        ]
      },
      {
        "name": "Intro pricing",
        "phases": [
          {
            "ordinal": 1,
            "cycle_duration": "P1M",
            "cycle_count": 1,
            "amount": 990,
            "currency": "GBP"
          },
          {
            "ordinal": 2,
            "cycle_duration": "P1M",
            "amount": 1900,
            "currency": "GBP"
          }
        ]
      }
    ]
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `name` | Plan name shown in the Revolut Business dashboard |
  | `trial_duration` | Free trial before the first payment - `P14D` sets 14 days as the plan's default, applying to every subscription unless overridden at creation; days only |
  | `variations` | Pricing paths customers subscribe to - one charges the regular price throughout, the other runs the introductory sequence |
  | `phases` | Sequential price steps on a variation, executed in `ordinal` order |
  | `ordinal` | Position of the phase in the sequence |
  | `cycle_duration` | Length of each billing cycle in the phase - `P1M` for monthly |
  | `cycle_count` | Cycles the phase runs before moving to the next - omit on the final phase to continue indefinitely |
  | `amount` | Price per cycle in minor units - `1900` is £19.00 |
  | `currency` | ISO 4217 currency code |

- ![Response]
  The plan is created - `active`, with the trial default and both variations echoed back.

  ```json [Response example] {4,10}
  {
    "id": "fd084f51-5426-4b8c-868f-8e8f1ca3255b",
    "name": "Premium",
    "trial_duration": "P14D",
    "state": "active",
    "created_at": "2026-01-26T08:59:09.433527Z",
    "updated_at": "2026-01-26T08:59:09.433527Z",
    "variations": [
      {
        "id": "31003a04-e0ca-4513-a1fb-64a6c37198ee",
        "name": "Standard",
        "phases": [
          {
            "id": "270f5be8-3d1f-47c5-98e0-2dde2d218502",
            "ordinal": 1,
            "cycle_duration": "P1M",
            "amount": 1900,
            "currency": "GBP"
          }
        ]
      },
      {
        "id": "dc27fea7-268c-4ae8-a657-95fe7bbd535f",
        "name": "Intro pricing",
        "phases": [
          {
            "id": "c30aff62-c13d-49a1-9986-69410da48d50",
            "ordinal": 1,
            "cycle_duration": "P1M",
            "cycle_count": 1,
            "amount": 990,
            "currency": "GBP"
          },
          {
            "id": "a9f3c2c9-d27b-4cac-8706-db7791116864",
            "ordinal": 2,
            "cycle_duration": "P1M",
            "amount": 1900,
            "currency": "GBP"
          }
        ]
      }
    ]
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `id` | Plan ID - save it to manage the plan and subscribe customers |
  | `trial_duration` | Echoed plan-level trial default |
  | `state` | `active` as soon as the plan is created |
  | `variations[].id` | Variation IDs - the walkthrough subscribes to Standard |
  | `phases[].id` | Phase IDs - the intro-pricing variation carries two |

Phases run in `ordinal` order. `cycle_count` bounds a phase: the intro-pricing variation's phase 1 runs a single £9.90 cycle, then phase 2 takes over at £19.00 a month, indefinitely - omit `cycle_count` on a final phase and it simply never ends. When a bounded phase completes with no successor, the subscription automatically stops - that's how you shape a fixed-length plan.

The trial runs before any phase: on the intro-pricing variation, the 14-day trial bills nothing, then the £9.90 phase 1 cycle starts - the first payment that variation ever collects is the discounted one.

### 2. Subscribe customer

Subscribing connects the customer to one variation, and the plan's trial applies by default. The walkthrough's customer has no saved payment method, so the subscription starts `pending` - the trial already running - until [step 3](#3-collect-payment-method) delivers one. The other trial-specific move happens on this same call: overriding the trial length.

| `trial_duration` on the request | Behaviour |
| ------------------------------- | --------- |
| Omitted | The plan's default applies - 14 days here |
| Same value as the plan default | Explicit restatement of the default |
| Different value | Overrides the plan default for this subscription only - the walkthrough's `P30D` promotional trial |
| `"P0D"` | Skips the trial - regular billing starts immediately |

Call [Create a subscription](/docs/api/merchant#create-subscription) to start the customer's trial - set the 30-day promotional trial with `trial_duration`:

- ![Request]
  ```http [Request example] {9,11}
  POST /api/subscriptions HTTP/1.1
  Content-Type: application/json
  Authorization: Bearer sk_abcdef12347890_...
  Idempotency-Key: cd391ee6-eb5f-4124-98e1-13b76d79fa3b
  Revolut-Api-Version: 2026-08-17
  Host: merchant.revolut.com

  {
    "plan_variation_id": "31003a04-e0ca-4513-a1fb-64a6c37198ee",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "trial_duration": "P30D",
    "external_reference": "promo_a3e71c",
    "setup_order_redirect_url": "https://example.com/subscription/complete"
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `plan_variation_id` | ID of the variation the customer subscribes to - the Standard variation created in step 1: this customer's promotion is the 30-day trial itself, and the intro-pricing variation takes its turn in [Change plan](#change-plan) |
  | `customer_id` | ID of the customer subscribing - no saved payment method needed yet |
  | `trial_duration` | Overrides the plan's 14-day default - `P30D` gives this customer a 30-day promotional trial; `"P0D"` skips the trial; omitted, the plan default applies |
  | `external_reference` | Your identifier for the subscription, useful for reconciliation |
  | `setup_order_redirect_url` | Optional: where the customer lands after completing checkout in [step 3](#3-collect-payment-method) |

- ![Response]
  The subscription is created - `pending`, with the trial running. Save the `setup_order_id`: [step 3](#3-collect-payment-method) retrieves the order with it to collect the payment method.

  ```json [Response example] {4,11,12,13}
  {
    "id": "a3a42fdb-ea02-4d9b-b806-c00785924c23",
    "external_reference": "promo_a3e71c",
    "state": "pending",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "plan_id": "fd084f51-5426-4b8c-868f-8e8f1ca3255b",
    "plan_variation_id": "31003a04-e0ca-4513-a1fb-64a6c37198ee",
    "payment_method_type": "automatic",
    "created_at": "2026-01-26T09:15:00.036001Z",
    "updated_at": "2026-01-26T09:15:00.036001Z",
    "current_cycle_id": "d418b1c3-bd97-4763-a18e-ef7aa9d3e529",
    "trial_duration": "P30D",
    "setup_order_id": "a645915f-de23-4596-96b8-1b8c37893aa2"
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `id` | Subscription ID - save it for every call that follows |
  | `state` | `pending` - the subscription activates the moment a payment method is saved in [step 3](#3-collect-payment-method) |
  | `current_cycle_id` | ID of the trial cycle - the trial is already running - retrieved under [Operate](#retrieve-billing-cycles) |
  | `trial_duration` | The override applied to this subscription - `P30D` |
  | `setup_order_id` | The setup order collecting the payment method - save it, [step 3](#3-collect-payment-method) retrieves the order with it |

To start a customer on regular billing with no trial at all, send the same call with `"trial_duration": "P0D"` - the trial is skipped and billing begins immediately.

:::tip[Returning customer shortcut]
If the customer already has a payment method on file, attach its `payment_method_id` on this request - the subscription skips `pending` and activates immediately, and you can skip [step 3](#3-collect-payment-method).

The trial still applies either way: the first payment waits for it to end.
:::

### 3. Collect payment method

In the previous step, you created the subscription. It is in `pending` state, and becomes `active` once the customer provides a payment method. That happens through a **setup order** - an order that exists to start a subscription.

Revolut creates the setup order in the background when you create the subscription. For a trial subscription it saves the customer's payment method and collects no charge: nothing is billed during the trial, and the first £19.00 lands when the trial ends, charged by the trial cycle's order under [Operate](#retrieve-billing-cycles). You already saved its `setup_order_id`.

#### 3.1 Retrieve the setup order

Retrieve the setup order with [Retrieve an order](/docs/api/merchant#retrieve-order), passing the `setup_order_id` you saved in [step 2](#2-subscribe-customer) as the `order_id`:

- ![Request]
  ```http [Request example]
  GET /api/orders/{order_id} HTTP/1.1
  Host: merchant.revolut.com
  Authorization: Bearer sk_abcdef12347890_...
  Revolut-Api-Version: 2026-08-17
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `order_id` | The ID of the setup order you saved in [step 2](#2-subscribe-customer) |

- ![Response]
  The response returns the setup order. The fields that unlock the checkout approaches below are - `token` for embedding a payment widget on your site and `checkout_url` for Revolut's Hosted Checkout Page.

  ```json [Response example] {3,7,9}
  {
    "id": "a645915f-de23-4596-96b8-1b8c37893aa2",
    "token": "45c68d64-d17a-455a-8910-6121c23f0bc6",
    "state": "pending",
    "created_at": "2026-01-26T09:15:00.036001Z",
    "updated_at": "2026-01-26T09:15:00.036001Z",
    "amount": 0,
    "currency": "GBP",
    "checkout_url": "https://checkout.revolut.com/payment-link/45c68d64-d17a-455a-8910-6121c23f0bc6"
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `token` | The public token for initialising a payment widget |
  | `amount` | `0` - the setup order collects no charge: it exists to authorise and save the payment method, and the first payment waits for the trial to end |
  | `checkout_url` | The link to Revolut's Hosted Checkout Page |

Like the calls in the previous steps, this is a server-side operation - it happens between your backend and the Merchant API.

#### 3.2 Build your payment acceptance solution

Collecting the payment method reaches beyond your backend: the customer acts in their browser or mobile app, so this part of the flow has client-side work alongside your server. The goal is to hand the customer a way to authorise and save their payment method. Revolut supports two approaches, and both do this for you:

- [:CodeRepository: Payment widget](# "Embed the payment flow in your site: you build the customer experience, and the customer never leaves your page")
- [:Browser: Hosted Checkout Page](# "Redirect to a payment page Revolut hosts for you: no payment UI to build, and Revolut handles the payment experience")

Choose the approach that fits your integration:

- ![Payment widget]
  Keep the customer on your site with an embedded payment widget or a card-not-present method:

  1. Build your payment acceptance solution on your frontend with the widget or payment method of your choice, initialising it with the `token` from the response.
  1. Configure it to save the customer's payment method for merchant-initiated recurring transactions.
  1. The customer completes authorisation without leaving your site, and Revolut saves their payment method - the subscription activates on the spot, and the first payment still waits for the trial to end.

- ![Hosted Checkout Page]
  Redirect the customer to Revolut's Hosted Checkout Page:

  1. Redirect the customer to the `checkout_url` from the response.
  1. The customer completes authorisation on the hosted page, and Revolut saves their payment method - the subscription activates, and the first payment still waits for the trial to end.
  1. If you set `setup_order_redirect_url` in [step 2](#2-subscribe-customer), the customer is redirected there after authorisation; otherwise they see Revolut's default completion screen.

:::info
This step assumes you're familiar with a standard payment method integration, see [Introduction to online payments](/docs/guides/merchant/accept-payments/online-payments/introduction).
:::

:::warning
A `pending` subscription that never receives a payment method is cancelled without ever going live - the trial doesn't extend that window. See [Subscription lifecycle](/docs/guides/merchant/billing-subscriptions/subscription-lifecycle#subscription-trials).
:::

### 4. Verify subscription state

When the customer completes authorisation in [step 3](#3-collect-payment-method), the saved payment method activates the subscription. Confirm it's live and the trial is running by calling [Retrieve a subscription](/docs/api/merchant#retrieve-subscription), passing the subscription `id` you saved in [step 2](#2-subscribe-customer) as the `subscription_id`:

- ![Request]
  ```http [Request example]
  GET /api/subscriptions/{subscription_id} HTTP/1.1
  Authorization: Bearer sk_abcdef12347890_...
  Revolut-Api-Version: 2026-08-17
  Host: merchant.revolut.com
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `subscription_id` | The ID of the subscription you saved in [step 2](#2-subscribe-customer) |

- ![Response]
  The subscription is `active` with the trial running - the method saved in [step 3](#3-collect-payment-method) is on file, `current_cycle_id` is still the trial cycle, and nothing has been collected yet.

  ```json [Response example] {4,13,15}
  {
    "id": "a3a42fdb-ea02-4d9b-b806-c00785924c23",
    "external_reference": "promo_a3e71c",
    "state": "active",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "plan_id": "fd084f51-5426-4b8c-868f-8e8f1ca3255b",
    "plan_variation_id": "31003a04-e0ca-4513-a1fb-64a6c37198ee",
    "payment_method_type": "automatic",
    "payment_method_id": "7cfb1e2b-14a3-422f-ad49-5590b39feab9",
    "created_at": "2026-01-26T09:15:00.036001Z",
    "updated_at": "2026-01-26T09:47:00.036001Z",
    "start_date": "2026-01-26T09:15:00.036001Z",
    "current_cycle_id": "d418b1c3-bd97-4763-a18e-ef7aa9d3e529",
    "trial_duration": "P30D",
    "trial_end_date": "2026-02-25T09:15:00.036001Z"
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `state` | `active` - the subscription is live and the trial is running |
  | `payment_method_id` | The method saved in [step 3](#3-collect-payment-method) - Revolut charges it automatically: nothing during the trial, the first payment at `trial_end_date` |
  | `current_cycle_id` | ID of the trial cycle, retrieved under [Operate](#retrieve-billing-cycles) |
  | `trial_end_date` | The day the first payment is collected from the saved payment method |

The subscription is live: `active` with the trial running to `trial_end_date`, and no payment collected yet.

:::tip
**You've completed the trial subscription flow!** The Premium plan is live with its two variations, the customer's payment method is saved, and their trial is running to its end date.

Next, operate the subscription: retrieve the billing cycles as the trial turns into regular billing, change the customer's plan when they need different pricing, and cancel the subscription when they leave.

From here the timeline runs itself - we collect the first payment from the saved method at trial end, bill every cycle after, and retry failed payments automatically, see [Failed payments and retries](/docs/guides/merchant/billing-subscriptions/subscription-lifecycle#failed-payments-and-retries).
:::

---

## Operate subscription with trials

The trial runs on our side - no payment is collected until `trial_end_date`, and billing is automatic afterwards. What stays yours: retrieving the cycles to see the trial turn into regular billing - and running entitlement checks against them - moving the customer to a different variation, and cancelling when they leave.

### Retrieve billing cycles

Every cycle carries a `trial` flag - `true` while the cycle sits inside the trial period, before `trial_end_date`. The trial cycle bills nothing during the trial; its order collects the first payment when the trial ends. Retrieve the cycles to watch that transition:

```mermaid
flowchart TD
    subgraph subscription ["Subscription a3a42fdb - active"]
        subgraph cycle1 ["Cycle 1 - d418b1c3 trial cycle, finished"]
            order1["Order 2454992d <br>collected the first £19.00 when the trial ended"]
        end
        subgraph cycle2 ["Cycle 2 - 06259b38, current, active"]
            order2["Order f0fd59a3 <br>charges £19.00"]
        end
    end
```

#### Retrieve cycle list

Retrieve the cycles with [Retrieve a subscription cycle list](/docs/api/merchant#retrieve-subscription-cycle-list), passing the subscription `id` you saved in [step 2](#2-subscribe-customer) as the `subscription_id` - the trial cycle sits beside the current one:

- ![Request]
  ```http [Request example]
  GET /api/subscriptions/{subscription_id}/cycles HTTP/1.1
  Authorization: Bearer sk_abcdef12347890_...
  Revolut-Api-Version: 2026-08-17
  Host: merchant.revolut.com
  ```

- ![Response]
  Cycle 2 is current; cycle 1 - the trial cycle - is finished.

  ```json [Response example] {15,25,26}
  {
    "next_page_token": "be9f9ba1-7f2d-4c63-9d0a-f889468eac45",
    "cycles": [
      {
        "id": "06259b38-d335-429c-8ae3-54f4557e8666",
        "subscription_id": "a3a42fdb-ea02-4d9b-b806-c00785924c23",
        "plan_variation_id": "31003a04-e0ca-4513-a1fb-64a6c37198ee",
        "plan_variation_phase_id": "270f5be8-3d1f-47c5-98e0-2dde2d218502",
        "number": 2,
        "previous_cycle_id": "d418b1c3-bd97-4763-a18e-ef7aa9d3e529",
        "state": "active",
        "start_date": "2026-02-26T09:15:00.036001Z",
        "end_date": "2026-03-26T09:15:00.036001Z",
        "order_id": "f0fd59a3-7f42-42ec-a7e0-11fdf3919c5e",
        "trial": false
      },
      {
        "id": "d418b1c3-bd97-4763-a18e-ef7aa9d3e529",
        "subscription_id": "a3a42fdb-ea02-4d9b-b806-c00785924c23",
        "plan_variation_id": "31003a04-e0ca-4513-a1fb-64a6c37198ee",
        "number": 1,
        "state": "finished",
        "start_date": "2026-01-26T09:15:00.036001Z",
        "end_date": "2026-02-26T09:15:00.036001Z",
        "order_id": "2454992d-26ef-42ae-9987-a578944d3eed",
        "trial": true
      }
    ]
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `cycles[].number` | Cycle position in the subscription - the trial is cycle 1 |
  | `cycles[].state` | `active` while the cycle is current, `finished` after it completes |
  | `cycles[].order_id` | The order that charged the cycle - cycle 1's order collected the first payment when the trial ended |
  | `cycles[].trial` | `true` while the cycle sits inside the trial period, before `trial_end_date` - the trial cycle bills nothing during the trial |

Read the pair in order: cycle 1 - `trial: true`, finished - holds the order that collected the first £19.00 when the trial ended; cycle 2 - `trial: false`, current - carries the ongoing charge. A trial can end inside its cycle: `trial_end_date` says when the first payment is collected, while the cycle still spans its full `cycle_duration` - here the trial ends a day before cycle 1 closes.

#### Run entitlement check

Grant access while the subscription is `active` and its current cycle is too. The walkthrough customer is past the trial now - retrieve their current cycle with [Retrieve a subscription cycle](/docs/api/merchant#retrieve-subscription-cycle), passing its `id` - the `current_cycle_id` from the subscription response - as the `cycle_id`, and check the state:

- ![Request]
  ```http [Request example]
  GET /api/subscriptions/{subscription_id}/cycles/{cycle_id} HTTP/1.1
  Authorization: Bearer sk_abcdef12347890_...
  Revolut-Api-Version: 2026-08-17
  Host: merchant.revolut.com
  ```

- ![Response]
  The cycle is `active` - access continues.

  ```json [Response example] {8}
  {
    "id": "06259b38-d335-429c-8ae3-54f4557e8666",
    "subscription_id": "a3a42fdb-ea02-4d9b-b806-c00785924c23",
    "plan_variation_id": "31003a04-e0ca-4513-a1fb-64a6c37198ee",
    "plan_variation_phase_id": "270f5be8-3d1f-47c5-98e0-2dde2d218502",
    "number": 2,
    "previous_cycle_id": "d418b1c3-bd97-4763-a18e-ef7aa9d3e529",
    "state": "active",
    "start_date": "2026-02-26T09:15:00.036001Z",
    "end_date": "2026-03-26T09:15:00.036001Z",
    "order_id": "f0fd59a3-7f42-42ec-a7e0-11fdf3919c5e",
    "trial": false
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `state` | `active` - grant access; `finished` or `cancelled` - end it |
  | `end_date` | The access window the charge covers - if you let customers finish what they paid for, stop here |

The check works unchanged during a trial: the current cycle is then the trial cycle - `trial: true`, nothing collected yet - and it still reads `active`, so access continues through the trial without a special case.

### Change plan

When a customer outgrows the current pricing or you owe them a win-back, move them to another variation with [Change a subscription plan](/docs/api/merchant#change-subscription-plan), passing the subscription `id` you saved in [step 2](#2-subscribe-customer) as the `subscription_id`. The walkthrough customer moves to the intro-pricing variation - its £9.90 phase 1 doubles as the promotional month - scheduled to start at the end of the current cycle:

- ![Request]
  ```http [Request example]
  POST /api/subscriptions/{subscription_id}/change-plan HTTP/1.1
  Content-Type: application/json
  Authorization: Bearer sk_abcdef12347890_...
  Revolut-Api-Version: 2026-08-17
  Host: merchant.revolut.com

  {
    "plan_variation_id": "dc27fea7-268c-4ae8-a657-95fe7bbd535f",
    "scheduled": "at_cycle_end"
  }
  ```

  | Parameter | Description |
  | ----------- | ----------- |
  | `plan_variation_id` | ID of the variation the customer moves to - the intro-pricing variation created in step 1 |
  | `scheduled` | When the change takes effect - `at_cycle_end` only: the current cycle completes at its current price and the new variation starts with the next cycle |

- ![Response]
  The change is scheduled - it takes effect with the next cycle.

  ```http [Response example]
  HTTP/1.1 204 No Content
  ```

Plan changes are scheduled, never immediate - requesting one returns `400 immediate_not_supported`. Three rules govern the move:

- **Trials don't repeat** - if the target variation carries a trial period, it's skipped: trials only apply when a subscription is first created.
- **Multi-phase targets start from a phase** - when the target variation has multiple phases, set `plan_variation_phase_id` to start from a specific one; omitted, the change starts from the first phase. The walkthrough starts at the £9.90 phase 1 deliberately - point at phase 2 to skip the discount.
- **The current cycle completes normally** - the new price applies from the next cycle, so nothing is charged twice or refunded mid-cycle.

### Cancel subscription

When the customer leaves, cancel with [Cancel a subscription](/docs/api/merchant#cancel-subscription), passing the subscription `id` you saved in [step 2](#2-subscribe-customer) as the `subscription_id`:

- ![Request]
  ```http [Request example]
  POST /api/subscriptions/{subscription_id}/cancel HTTP/1.1
  Authorization: Bearer sk_abcdef12347890_...
  Revolut-Api-Version: 2026-08-17
  Host: merchant.revolut.com
  ```

- ![Response]
  The subscription is marked `cancelled` - no further cycles are created.

  ```http [Response example]
  HTTP/1.1 204 No Content
  ```

The subscription moves to `cancelled` - a final state: it can't be reactivated, so if the customer returns, create a new subscription for them. A `SUBSCRIPTION_CANCELLED` webhook event is sent whether the cancellation came from you or the customer - see [Subscription states](/docs/guides/merchant/billing-subscriptions/subscription-plans#subscription-states) and [Track subscriptions with webhooks](/docs/guides/merchant/billing-subscriptions/api/webhooks).

Cancelling during the trial costs the customer nothing - no payment has been collected yet, and none will be: Revolut stops billing and cancels any pending orders, so the first payment due at `trial_end_date` is never taken.

If you [run the entitlement check](#run-entitlement-check), this is where it stops granting access: end access immediately, or - if you let customers finish what they paid for - stop at the current cycle's `end_date`. Cancelling stops future charges only - it doesn't refund completed cycles.

---

## Implementation checklist

Confirm your trials integration works end to end. Run the checks in the Sandbox environment first - set the base URL of your API calls to `sandbox-merchant.revolut.com` - then repeat them in production before going live:

- [ ] Created a plan with a `trial_duration` default and saved both variation `id`s - the one the customer subscribes to, and the multi-phase one for plan changes
- [ ] Subscribed a customer without a saved payment method - `pending` with the trial running, `trial_duration` and `setup_order_id` on the response
- [ ] Collected the payment method through the setup order - the order carries `amount: 0`, and retrieving the subscription confirms `active` with the first payment still waiting for `trial_end_date`
- [ ] Subscribed a returning customer by attaching `payment_method_id` at creation - `active` immediately, no setup order needed
- [ ] Overrode the trial on another subscription - omitted so the plan default applies, a different value next, then `"P0D"` to skip it entirely
- [ ] Retrieved the cycle list - the trial cycle shows `trial: true`, and its order collected the first payment when the trial ended
- [ ] Ran the entitlement check against the current cycle - and confirmed it works unchanged during the trial
- [ ] Scheduled a plan change to a multi-phase variation - `at_cycle_end` only, `plan_variation_phase_id` targets the right phase, and the trial doesn't repeat on the change
- [ ] Cancelled a test subscription during its trial - `204` response, the first payment due at `trial_end_date` is never taken, no new cycles created, `SUBSCRIPTION_CANCELLED` event received

For verifying the payment solution itself - widget behaviour, test cards, webhook receipt for the order - use the implementation checklist in the payment method guide you followed.

<!--
TODO (PTTD-824)

1. Trial-vs-cycle timing: with a trial shorter than the cycle, trial_end_date (subscription field)
   lands inside cycle 1 - the official examples show the trial cycle spanning the full
   cycle_duration with trial: true (Res-Subscription-Cycles-List.yaml) and trial_end_date 14 days
   after start on a P1M cycle (Res-Subscription-Active.yaml). The walkthrough uses a P30D override
   so trial end nearly coincides with cycle 1 end - the visible 1-day gap in the example dates is
   intentional, and the cycle-list prose teaches the official model (first payment at
   trial_end_date, cycle spans its full cycle_duration). Verify with the API team: is the first
   payment collected at trial_end_date or at cycle end, and is cycle 1's order_id that first-payment
   order? Cycle-model status: `trial: true` semantics and `trial_end_date` (= `start_date` +
   `trial_duration`) are now SPEC-DOCUMENTED (Subscription-Cycle-Trial.yaml: a cycle within the
   trial period, before `trial_end_date`; Subscription-Trial-End-Date.yaml); How it works teaches
   the user-ruled model - the trial adds no cycle, cycles keep standard duration/count, cycles
   starting before `trial_end_date` are flagged `trial: true`, phases set the price from the
   following cycle. Still inferred from the official example shape only: cycle 1 carries no
   `plan_variation_phase_id` (phases govern from cycle 2). OPEN QUESTION: the schema description
   implies a trial LONGER than the cycle duration (e.g. P60D on P1M) flags MULTIPLE cycles `trial:
   true` - the page's examples all fit within one cycle; confirm the multi-cycle trial shape if
   worth teaching.

2. Spec discrepancy: Subscription-Creation.yaml's properties omit payment_method_id, but both
   official trial request examples send it (Req-Subscription-With-Trial.yaml,
   Req-Subscription-
   Skip-Trial.yaml) and the response schema carries it - report to the API team. Activation-on-
   attach semantics follow the lifecycle page's resolved model (trial subscriptions are created
   pending and activate when a payment method is provided - immediately when attached at creation).

3. Trial + phases combine (trial runs before phase 1, first collected payment on the intro variation
   is the discounted one) - NOW SPEC-DOCUMENTED: api_subscription-plans.yaml L26 and
   api_subscription-plans_{subscription_plan_id}.yaml L19 both state that if a trial_duration is
   defined, billing phases begin immediately after the trial ends. Remaining: get-started.md (~line
   37) loosely says multi-phase variations are how 'introductory pricing and trials work' - clarify
   that cross-page wording with the TW team.

4. Setup-order composition for trial subscriptions now SHOWN in step 3.1 with the amount-0
   authorise-only model: the setup order saves the payment method and collects nothing; the first
   £19.00 is charged by the trial cycle's order at trial_end_date - consistent with the cycle list,
   where cycle 1's order_id 2454992d differs from the setup order a645915f. UNVERIFIED - confirm
   with the API team; alternative model: the setup order carries the first-cycle charge deferred to
   trial end, in which case cycle 1's order_id would be the setup order id and 3.1 plus the cycle-
   list example need unifying. Also confirm: (a) whether a pending trial subscription response omits
   start_date and trial_end_date - the walkthrough mirrors Res-Subscription-Setup-Order.yaml, which
   omits both, and materialises them on activation in step 4; (b) whether start_date reflects
   creation (09:15, as shown - keeps trial_end_date 2026-02-25T09:15 consistent with the cycle list)
   or activation (get-started's non-trial flow shows start_date = updated_at = activation time).

5. The pending->cancelled window: the lifecycle page says 'within the set time period' without a
   value - step 3's warning mirrors that wording; add the concrete window if the API team confirms
   it.

6. Plan-change deep dive deferred to the upcoming manage/ category - add cross-links here when those
   pages land.
-->

---

## What's next

- [:Repayment: Build a fixed-rate subscription](/docs/guides/merchant/billing-subscriptions/api/fixed 'Charge a fixed recurring amount - the simplest subscription flow')
- [:PlaneSeat: Build a per-seat subscription](/docs/guides/merchant/billing-subscriptions/api/per-seat 'Bill per seat, with a stable or changing seat count')
- [:LimitHigh: Build a usage-based subscription](/docs/guides/merchant/billing-subscriptions/api/usage-based 'Meter usage, report it via the API, and settle charges at cycle end')
- [:Webhook: Track subscriptions with webhooks](/docs/guides/merchant/billing-subscriptions/api/webhooks 'Receive real-time events when subscription states change')