# 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 the subscription right away - the creation response can still show `pending`, so retrieve the subscription to confirm. 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 unless overridden at creation. The subscription echoes the effective `trial_duration` back: the override, or the plan's default. 

The trial adds a cycle of its own: cycle 1 spans the trial period - `start_date` to `trial_end_date` - and is flagged `trial: true`. Nothing is billed during the trial; the trial cycle's order collects the first payment when the trial ends. From the next cycle on, the subscribed variation's phases set the cycle duration and the price.

:::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 activates right away, and you can skip [step 3](#3-collect-payment-method). The creation response can still show `pending`: activation follows within moments, so retrieve the subscription to confirm it's `active`.

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,12,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:47:00.036001Z",
    "current_cycle_id": "d418b1c3-bd97-4763-a18e-ef7aa9d3e529",
    "trial_duration": "P30D",
    "trial_end_date": "2026-02-25T09:47: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` |
  | `start_date` | When the subscription activated - the moment the customer saved their payment method in [step 3](#3-collect-payment-method), not the creation time - and the trial cycle's start |
  | `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 - `start_date` plus the subscription's `trial_duration` |

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` on the trial cycle, the dedicated cycle the trial creates, and `false` on every cycle after. 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-25T09:47:00.036001Z",
        "end_date": "2026-03-25T09:47: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:47:00.036001Z",
        "end_date": "2026-02-25T09:47: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` on the trial cycle - the dedicated cycle the trial creates, spanning `start_date` to `trial_end_date` - and `false` on every cycle after |

Read the pair in order: cycle 1 - `trial: true`, finished - is the trial cycle, holding the order that collected the first £19.00 when the trial ended; cycle 2 - `trial: false`, current - carries the ongoing charge. The trial cycle ends exactly at `trial_end_date`, and the next cycle starts then, at the variation's price - the first payment lands at the boundary between the two.

#### 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-25T09:47:00.036001Z",
    "end_date": "2026-03-25T09:47: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. RESOLVED 2026-09-18 by sandbox evidence (user-run captures: P1D trial on a
   P1Y variation, cycle list, subscription retrieval): the trial adds a
   dedicated cycle of its own. Cycle 1 spans start_date to trial_end_date (the
   trial duration, not the variation's cycle_duration), is flagged trial: true,
   carries no plan_variation_phase_id (phases govern from cycle 2), and its
   order collects the first payment at trial end. start_date reflects
   activation, not creation; the pending creation response omits start_date
   and trial_end_date (confirmed - the walkthrough mirrors this). SUPERSEDES
   the earlier 'no added cycle' model. Still open: the shape when
   trial_duration is longer than the cycle duration (one long trial cycle vs
   multiple trial: true cycles) - not taught until verified.

2. Taught but unobserved: the trial cycle's order collecting the first payment
   at trial end. The sandbox capture predates trial end (cycle active,
   order_id present); the model is consistent with the API and the page -
   confirm on a run-out trial when convenient.

3. Spec examples encode the superseded cycle model - Res-Subscription-Cycles-List.yaml
   (trial cycle spanning the full cycle_duration) and Res-Subscription-Active.yaml
   (trial_end_date inside cycle 1) contradict the sandbox behaviour. Also:
   Subscription-Creation.yaml properties omit payment_method_id while the
   request examples send it. Reported to the API team as PTTD-905; the page's
   examples deliberately diverge from the spec examples until the spec side is
   updated. Related: creation with a saved payment_method_id attached still
   returns pending - activation follows within moments; the page teaches
   retrieve-to-confirm (PTTD-905 asks whether a creation response can ever
   return active synchronously).

4. Trial + phases combine (trial runs before phase 1, first collected payment
   on the intro variation is the discounted one) - SPEC-DOCUMENTED:
   api_subscription-plans.yaml L26 and api_subscription-plans_{subscription_plan_id}.yaml
   L19 both state 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.

5. Setup-order composition for trial subscriptions (step 3.1, amount-0
   authorise-only model) - still UNVERIFIED: confirm with the API team that
   the first payment is charged by the trial cycle's order at trial_end_date,
   not by the setup order carrying a deferred first-cycle charge. Also tracked
   in PTTD-905.

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

7. 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')