# Build a fixed-rate subscription model

**Charge the customer the same amount on every billing cycle - the simplest pricing model.**

A fixed-rate subscription bills a flat price at a fixed cadence: £29.00 a month, £290.00 a year, and so on. The price never changes while the subscription runs, so once the customer is subscribed, your work is done - Revolut charges the saved payment method on every cycle and retries failed payments automatically.

This is the baseline scenario: every other pricing model - per-seat, usage-based, trials - is a variation on the same flow with a different plan configuration.

In this guide, you sell a **Standard plan** - £29.00 a month, with a yearly variation at £290.00 for customers who commit for a full year.

The example demonstrates how to model your own product or service palette as a subscription plan. One plan represents the service you offer, and each **variation** is one way a customer can buy it: the monthly option bills £29.00 every month, while the yearly option bills £290.00 once a year - a discount for the longer commitment.

Map your own catalogue the same way: every purchasing option for the same offering - a different cadence, commitment length, or price - becomes a variation, and each customer subscribes to exactly one of them.

:::tip[Itemised pricing]
If the product bundles distinct services, you can break the flat price into per-component items - see [Itemised flat pricing](#itemised-flat-pricing).
:::

## How it works

This guide walks the full flow: all API calls run between your backend and the Merchant API, and only [step 3](#3-collect-first-payment) - collecting the first payment - reaches the customer's browser.

1. **Create a plan with a fixed price** - each variation is a single phase that sets the price and cycle length. Offer monthly and yearly options as separate variations. Optionally, break the price into itemised flat components.
2. **Subscribe the customer** - create the subscription, which starts in `pending` state until the first payment is collected.
3. **Collect the first payment** - retrieve the setup order, hand the customer a payment widget or Revolut's Hosted Checkout Page, and confirm the subscription is `active` - Revolut bills automatically from there.
4. **Operate the subscription** - retrieve the billing cycles as they accrue, and cancel the subscription when the customer leaves.

The plan you'll build in this guide looks like this:

```mermaid
flowchart TD
    subgraph plan ["Standard plan"]
        subgraph monthly ["Monthly variation"]
            phase1["Phase 1 - £29.00/month<br>ongoing"]
        end
        subgraph yearly ["Yearly variation"]
            phase2["Phase 1 - £290.00/year<br>ongoing"]
        end
    end
```

### Before you begin

Before you start, make sure you have the following:

- [ ] 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
- [ ] An **existing customer** - see [Create a customer](/docs/api/merchant#create-customer)
- [ ] 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)

---

## Implement fixed-rate subscription

The steps below follow the Standard plan narrative: you create the plan with its two variations, subscribe a customer, collect the first payment, and confirm the subscription is `active`.

### 1. Create plan with fixed price

Your Standard plan offers two billing options: £29.00 a month, or £290.00 a year for customers who commit to the full 12 months. Each variation is a single phase - the phase's `amount` is the price charged on every cycle of `cycle_duration` - and each customer subscribes to exactly one of them.

The plan you create consumes these business details: the name your customers recognise, the monthly and yearly billing cadences, and the two prices - the yearly price works as a discount for the longer commitment.

Call [Create a subscription plan](/docs/api/merchant#create-subscription-plan), turning these business details into a plan your customers can subscribe to:

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

  {
    "name": "Standard plan",
    "variations": [
      {
        "phases": [
          {
            "ordinal": 1,
            "cycle_duration": "P1M",
            "amount": 2900,
            "currency": "GBP"
          }
        ]
      },
      {
        "phases": [
          {
            "ordinal": 1,
            "cycle_duration": "P1Y",
            "amount": 29000,
            "currency": "GBP"
          }
        ]
      }
    ]
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `name` | The plan name - what your customers subscribe to |
  | `variations` | Pricing options for the plan - here, monthly and yearly billing |
  | `phases` | Sequential pricing stages within a variation, executed in `ordinal` order |
  | `ordinal` | Execution order of the phase, starting at `1` |
  | `cycle_duration` | Length of the billing cycle, as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) duration, e.g., `P1M` or `P1Y` |
  | `cycle_count` | Number of cycles the phase runs for - omit to run indefinitely |
  | `amount` | Price per billing cycle, in minor units - `2900` is £29.00, `29000` is £290.00 |
  | `currency` | Billing currency, as an [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) code |

- ![Response]
  The response returns the plan with system-generated IDs. Save the `id` of the variation the customer wants - here, the monthly variation - you use it to create the subscription in [step 2](#2-subscribe-customer).

  ```json [Response example] {9}
  {
    "id": "d83629ba-db28-4b98-a789-30159dc83dfb",
    "name": "Standard plan",
    "state": "active",
    "created_at": "2026-01-26T08:59:09.433527Z",
    "updated_at": "2026-01-26T08:59:09.433527Z",
    "variations": [
      {
        "id": "5dfb572c-d2d4-4522-8626-ed6ea2d2711f",
        "phases": [
          {
            "id": "c806d409-c3c9-422c-b57a-3a780650e28f",
            "ordinal": 1,
            "cycle_duration": "P1M",
            "amount": 2900,
            "currency": "GBP"
          }
        ]
      },
      {
        "id": "017fb93d-6306-45e0-b068-c8999ba8b40f",
        "phases": [
          {
            "id": "2d60789f-e6fb-4644-9db8-decb414b3064",
            "ordinal": 1,
            "cycle_duration": "P1Y",
            "amount": 29000,
            "currency": "GBP"
          }
        ]
      }
    ]
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `id` | The plan ID - the plan's identifier in the API |
  | `state` | `active` - the plan is ready to accept subscriptions |
  | `variations[].id` | The variation IDs - save the one the customer subscribes to; you'll use it in [step 2](#2-subscribe-customer) |

:::tip[Limited subscriptions]
To run the subscription for a fixed number of cycles - e.g., a 12-month commitment that ends automatically - set `cycle_count` on the phase. When the last cycle completes, the subscription moves to `finished` and no further charges are made.
:::

#### Itemised flat pricing [!details]

Itemised flat pricing is an optional extension of the standard fixed-rate model. Say your Standard plan bundles two services: the platform licence and a priority-support add-on.

Some customers want to know exactly what they're paying for - so instead of one opaque £29.00 charge, you bill each component separately under the same subscription: the platform licence at £19.00 a month, priority support at £10.00.

To do this, add `subscription_items` with `type: flat` to the phase - each flat item charges its `amount` multiplied by its `quantity` on every cycle. The phase-level `amount` and `currency` stay on the phase.

With the items, the plan configuration looks like this:

```mermaid
flowchart TD
    subgraph plan ["Standard plan"]
        subgraph monthly ["Monthly variation"]
            subgraph phase1 ["Phase 1 - £29.00/month ongoing"]
                subgraph items ["Subscription items"]
                    item1["Platform licence<br>flat item - £19.00"]
                    item2["Priority support<br>flat item - £10.00"]
                end
            end
        end
        subgraph yearly ["Yearly variation"]
            phase2["Phase 1 - £290.00/year ongoing"]
        end
    end
```

In terms of the API's fields and types - as the create response returns them - the same structure looks like this:

```mermaid
erDiagram
    plan ||--|{ variation : variations
    variation ||--|{ phase : phases
    phase ||--o{ subscription_item : subscription_items

    plan {
        id uuid PK
        name string "the plan name"
        state string "active when created"
        variations array
    }
    variation {
        id uuid PK "save it - the customer subscribes to one"
        phases array
    }
    phase {
        id uuid PK
        ordinal integer "execution order, starting at 1"
        cycle_duration string "ISO 8601 duration, e.g. P1M"
        cycle_count integer "optional - omit to run indefinitely"
        amount integer "price per cycle, minor units"
        currency string "ISO 4217 code"
        subscription_items array
    }
    subscription_item {
        id uuid PK
        type string "flat for a fixed per-cycle charge"
        name string "item name, e.g. Platform licence"
        unit string "what the item bills"
        quantity integer "units billed per cycle"
        amount integer "price per unit, minor units"
        currency string "ISO 4217 code"
    }
```

This is the [Create a subscription plan](/docs/api/merchant#create-subscription-plan) call from [step 1](#1-create-plan-with-fixed-price), with the monthly variation's phase itemised:

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

  {
    "name": "Standard plan",
    "variations": [
      {
        "phases": [
          {
            "ordinal": 1,
            "cycle_duration": "P1M",
            "amount": 2900,
            "currency": "GBP",
            "subscription_items": [
              {
                "type": "flat",
                "name": "Platform licence",
                "unit": "subscription",
                "quantity": 1,
                "amount": 1900,
                "currency": "GBP"
              },
              {
                "type": "flat",
                "name": "Priority support",
                "unit": "subscription",
                "quantity": 1,
                "amount": 1000,
                "currency": "GBP"
              }
            ]
          }
        ]
      },
      {
        "phases": [
          {
            "ordinal": 1,
            "cycle_duration": "P1Y",
            "amount": 29000,
            "currency": "GBP"
          }
        ]
      }
    ]
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `type` | Item type - `flat` for a fixed per-cycle charge |
  | `name` | The item name, e.g., `Platform licence` |
  | `amount` | Price per unit, in minor units - `1900` is £19.00 |
  | `currency` | Item currency, as an [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) code |
  | `unit` | What the item bills, e.g., `subscription`, `licence` |
  | `quantity` | Units billed per cycle - each cycle charges `quantity * amount` |

- ![Response]
  The response returns the same plan as [step 1](#1-create-plan-with-fixed-price) - each phase now echoes its `subscription_items`, and every item gets a system-generated `id`.

  ```json [Response example]
  {
    "id": "d83629ba-db28-4b98-a789-30159dc83dfb",
    "name": "Standard plan",
    "state": "active",
    "created_at": "2026-01-26T08:59:09.433527Z",
    "updated_at": "2026-01-26T08:59:09.433527Z",
    "variations": [
      {
        "id": "5dfb572c-d2d4-4522-8626-ed6ea2d2711f",
        "phases": [
          {
            "id": "c806d409-c3c9-422c-b57a-3a780650e28f",
            "ordinal": 1,
            "cycle_duration": "P1M",
            "amount": 2900,
            "currency": "GBP",
            "subscription_items": [
              {
                "id": "1ffb2404-6e31-425a-b548-1b1108f9f324",
                "type": "flat",
                "name": "Platform licence",
                "unit": "subscription",
                "quantity": 1,
                "amount": 1900,
                "currency": "GBP"
              },
              {
                "id": "8b308dcd-fcef-47da-897f-f746277de713",
                "type": "flat",
                "name": "Priority support",
                "unit": "subscription",
                "quantity": 1,
                "amount": 1000,
                "currency": "GBP"
              }
            ]
          }
        ]
      },
      {
        "id": "017fb93d-6306-45e0-b068-c8999ba8b40f",
        "phases": [
          {
            "id": "2d60789f-e6fb-4644-9db8-decb414b3064",
            "ordinal": 1,
            "cycle_duration": "P1Y",
            "amount": 29000,
            "currency": "GBP"
          }
        ]
      }
    ]
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `subscription_items` | The phase's flat items, echoed back as sent |
  | `subscription_items[].id` | The system-generated item identifier |

<!--
TODO (PTTD-824)

Spec verification - Subscription-Plan-Phase-Creation.yaml requires phase amount/currency even when
subscription_items is present, but the additive-vs-total relationship between the phase amount and
item amounts is undocumented. The example implies the items sum to the phase amount (1900 + 1000 =
2900). Ask the API team/PO; if additive, rework this subsection's framing.
-->

### 2. Subscribe customer

When a customer wants to subscribe to your **Standard plan**, you create a subscription. The subscription connects the customer - and their consent to use their payment details for recurring charges - to the monthly variation you chose in [step 1](#1-create-plan-with-fixed-price).

Subscription creation is the same for every pricing model - the pricing lives entirely in the plan you built. Once created, the subscription starts in `pending` state - it becomes `active` once the customer completes the first payment.

Call [Create a subscription](/docs/api/merchant#create-subscription) with an idempotency key, so you can safely retry the request without creating duplicate subscriptions:

- ![Request]
  ```http [Request example] {9}
  POST /api/subscriptions HTTP/1.1
  Host: merchant.revolut.com
  Authorization: Bearer sk_abcdef12347890_...
  Revolut-Api-Version: 2026-08-17
  Content-Type: application/json
  Idempotency-Key: 4f1a9c2b-8e3d-4a67-9b5f-2c7d8e1f4a6b

  {
    "plan_variation_id": "5dfb572c-d2d4-4522-8626-ed6ea2d2711f",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "external_reference": "std_8f3a91",
    "setup_order_redirect_url": "https://example.com/subscription/complete"
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `plan_variation_id` | The variation the customer subscribes to - the monthly variation `id` you saved in [step 1](#1-create-plan-with-fixed-price) |
  | `customer_id` | The customer to bill |
  | `external_reference` | Optional: your own identifier for the subscription, e.g., the customer's ID in your system - returned in responses and echoed in webhook events |
  | `setup_order_redirect_url` | Optional: where the customer lands after completing payment on the hosted checkout page |

- ![Response]
  The subscription is created in `pending` state. Save the `setup_order_id` - [step 3](#3-collect-first-payment) collects the first payment with it - and the subscription `id` - [step 4](#4-verify-subscription-state) confirms activation with it, and the [Operate section](#operate-fixed-rate-subscription) uses it for the billing cycles and cancellation.

  ```json [Response example] {2,11}
  {
    "id": "11883317-3922-4921-949d-4f00aed579ad",
    "external_reference": "std_8f3a91",
    "state": "pending",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "plan_id": "d83629ba-db28-4b98-a789-30159dc83dfb",
    "plan_variation_id": "5dfb572c-d2d4-4522-8626-ed6ea2d2711f",
    "payment_method_type": "automatic",
    "created_at": "2026-01-26T09:15:00.036001Z",
    "updated_at": "2026-01-26T09:15:00.036001Z",
    "setup_order_id": "5c5d4c09-cfde-44ff-afb7-6b7b7ae62f63",
    "current_cycle_id": "031f6f77-0468-4f74-88c5-fa8782253711"
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `id` | The subscription ID - used to retrieve the billing cycles and cancel the subscription |
  | `state` | `pending` - the subscription becomes `active` once the customer completes the first payment |
  | `setup_order_id` | The setup order collecting the first payment - [step 3](#3-collect-first-payment) retrieves the order with it |
  | `current_cycle_id` | The cycle currently billing the subscription - retrieve it for entitlement checks in [Retrieve billing cycles](#retrieve-billing-cycles) |

### 3. Collect first payment

In [step 2](#2-subscribe-customer) you created the subscription. It is in `pending` state, and becomes `active` once the customer completes the first payment. That payment is collected 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: it takes the first charge - £29.00 for the Standard plan - and saves the customer's payment method for the recurring cycles that follow. You already saved its `setup_order_id`.

#### 3.1 Retrieve 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,9}
  {
    "id": "5c5d4c09-cfde-44ff-afb7-6b7b7ae62f63",
    "token": "fd974cfb-5e6f-4748-bcbc-3e023953fe8e",
    "state": "pending",
    "created_at": "2026-01-26T09:15:00.036001Z",
    "updated_at": "2026-01-26T09:15:00.036001Z",
    "amount": 2900,
    "currency": "GBP",
    "checkout_url": "https://checkout.revolut.com/payment-link/fd974cfb-5e6f-4748-bcbc-3e023953fe8e"
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `token` | The public token for initialising a payment widget |
  | `state` | `pending` - the order completes once the customer pays the £29.00 first charge |
  | `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 reaches beyond your backend: the customer pays 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 pay the first charge 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 payment without leaving your site, and Revolut saves their payment method.

- ![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 payment on the hosted page, and Revolut saves their payment method.
  1. If you set `setup_order_redirect_url` in [step 2](#2-subscribe-customer), the customer is redirected there after payment; 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).
:::

### 4. Verify subscription state

When the customer completes the first payment in [step 3](#3-collect-first-payment), the subscription becomes `active`. There's no webhook event for activation, so retrieve the subscription to confirm it's live.

Check the subscription details with [Retrieve a subscription](/docs/api/merchant#retrieve-subscription), passing the subscription `id` from [step 2](#2-subscribe-customer) as the `subscription_id`:

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

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

- ![Response]
  When the first payment succeeds, the subscription moves to `active` with a saved `payment_method_id` and a `start_date`.

  ```json [Response example] {4,9,12,13}
  {
    "id": "11883317-3922-4921-949d-4f00aed579ad",
    "external_reference": "std_8f3a91",
    "state": "active",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "plan_id": "d83629ba-db28-4b98-a789-30159dc83dfb",
    "plan_variation_id": "5dfb572c-d2d4-4522-8626-ed6ea2d2711f",
    "payment_method_type": "automatic",
    "payment_method_id": "efae529d-906b-4520-83e6-1924fa353d67",
    "created_at": "2026-01-26T09:15:00.036001Z",
    "updated_at": "2026-01-26T09:20:00.036001Z",
    "start_date": "2026-01-26T09:20:00.036001Z",
    "current_cycle_id": "031f6f77-0468-4f74-88c5-fa8782253711"
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `state` | `active` - the subscription is live and charges on each billing cycle |
  | `payment_method_id` | The saved payment method - Revolut charges it automatically on each cycle |
  | `start_date` | When the subscription became `active` |
  | `current_cycle_id` | The cycle currently billing the subscription - [Retrieve billing cycles](#retrieve-billing-cycles) uses it |

Once the subscription is `active`, your fixed-rate subscription is live - Revolut takes over from here: it charges the customer's saved payment method £29.00 (`2900`) a month or £290.00 (`29000`) a year, and retries failed payments automatically - see [Failed payments and retries](/docs/guides/merchant/billing-subscriptions/subscription-lifecycle#failed-payments-and-retries).

:::tip
**You've completed the fixed-rate subscription flow!** The Standard plan is live with its two variations, and Revolut bills the customer automatically from here. Next, operate the subscription: retrieve the billing cycles as they accrue, and cancel it when the customer leaves.
:::

---

## Operate fixed-rate subscription

With the subscription active, Revolut bills the saved payment method automatically. Two operations remain yours while it runs: retrieving the billing cycles - for entitlement checks, billing history, and reconciliation - and cancelling the subscription when the customer leaves.

### Retrieve billing cycles

While the subscription is active, Revolut creates a billing cycle for every billing period - one a month on the monthly variation. Each cycle carries its period, `state`, and the `order_id` of the order that charged it, so a complete billing history builds up as the subscription runs.

The subscription's runtime resources look like this:

```mermaid
flowchart TD
    subgraph subscription ["Subscription 11883317 - state: active"]
        subgraph cycle2 ["Cycle b3688550 - current, state: active"]
            order2["Order d5086d86 - charges £29.00"]
        end
        subgraph cycle1 ["Cycle 031f6f77 - state: finished"]
            order1["Order 5c5d4c09 - charged £29.00"]
        end
    end
```

The examples below cover two common use cases - a billing-history view and an entitlement check - but they're just a starting point. Explore how the same calls can serve your own business cases: the cycle data can power reconciliation, customer-facing billing pages, dunning workflows, and anything else your product needs.

#### Retrieve cycle list

The cycle list gives you the subscription's billing history in one call - every cycle so far, its state, and the order that charged each period. Use it for reconciliation and billing-history views, and to discover the current cycle's `id` if you don't have it saved.

Call [Retrieve a subscription cycle list](/docs/api/merchant#retrieve-subscription-cycle-list), passing the `id` of the subscription you created in [step 2](#2-subscribe-customer) as the `subscription_id`:

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

- ![Response]
  The response lists the subscription's cycles - each carries its `id`, period, `state`, and the `order_id` that charged it.

  ```json [Response example] {10}
  {
    "cycles": [
      {
        "id": "b3688550-2a6a-4921-be2f-1c4388e729c6",
        "subscription_id": "11883317-3922-4921-949d-4f00aed579ad",
        "plan_variation_id": "5dfb572c-d2d4-4522-8626-ed6ea2d2711f",
        "plan_variation_phase_id": "c806d409-c3c9-422c-b57a-3a780650e28f",
        "number": 2,
        "previous_cycle_id": "031f6f77-0468-4f74-88c5-fa8782253711",
        "state": "active",
        "start_date": "2026-02-26T09:20:00.036001Z",
        "end_date": "2026-03-26T09:20:00.036001Z",
        "order_id": "d5086d86-0946-439e-8fac-e3b46ba300ab",
        "trial": false
      },
      {
        "id": "031f6f77-0468-4f74-88c5-fa8782253711",
        "subscription_id": "11883317-3922-4921-949d-4f00aed579ad",
        "plan_variation_id": "5dfb572c-d2d4-4522-8626-ed6ea2d2711f",
        "plan_variation_phase_id": "c806d409-c3c9-422c-b57a-3a780650e28f",
        "number": 1,
        "state": "finished",
        "start_date": "2026-01-26T09:20:00.036001Z",
        "end_date": "2026-02-26T09:20:00.036001Z",
        "order_id": "5c5d4c09-cfde-44ff-afb7-6b7b7ae62f63",
        "trial": false
      }
    ]
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `id` | The cycle's identifier - retrieve a single cycle with it |
  | `number` | Cycle sequence number, starting at `1` for the first cycle |
  | `state` | `active` while the cycle runs, `finished` once complete |
  | `start_date` / `end_date` | The cycle's billing period - `end_date` is when the next cycle starts |
  | `order_id` | The order charging this cycle - use it to reconcile payments |
  | `trial` | Whether the cycle is a trial cycle - always `false` for fixed-rate plans without trials |

#### Run entitlement check

A common pattern is gating platform access on the subscription's state: each time the customer logs in, retrieve the current cycle - its `id` is the `current_cycle_id` from the subscription response - and grant access while its `state` is `active`.

The check runs on every login, so keep it lightweight: retrieve just the current cycle instead of pulling the whole list. Call [Retrieve a subscription cycle](/docs/api/merchant#retrieve-subscription-cycle), passing the current cycle's `id` as the `cycle_id`:

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

- ![Response]
  The response is the cycle object itself - the same shape as the list items above. For the entitlement check, `state` is the field that matters: grant access while it's `active`.

  ```json [Response example] {8}
  {
    "id": "b3688550-2a6a-4921-be2f-1c4388e729c6",
    "subscription_id": "11883317-3922-4921-949d-4f00aed579ad",
    "plan_variation_id": "5dfb572c-d2d4-4522-8626-ed6ea2d2711f",
    "plan_variation_phase_id": "c806d409-c3c9-422c-b57a-3a780650e28f",
    "number": 2,
    "previous_cycle_id": "031f6f77-0468-4f74-88c5-fa8782253711",
    "state": "active",
    "start_date": "2026-02-26T09:20:00.036001Z",
    "end_date": "2026-03-26T09:20:00.036001Z",
    "order_id": "d5086d86-0946-439e-8fac-e3b46ba300ab",
    "trial": false
  }
  ```

### Cancel subscription

When the customer wants to leave, cancel the subscription - Revolut stops billing and cancels any pending orders. You can cancel in any state except `cancelled` or `finished`.

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

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

- ![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).

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 fixed-rate 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 fixed phase `amount` and saved the variation `id` - or added `flat` subscription items for itemised pricing
- [ ] Subscribed a customer, collected the first payment, and confirmed the subscription is `active`
- [ ] Retrieved the cycle list and the current cycle - confirmed each cycle's `number`, `state`, and `order_id`
- [ ] If using `cycle_count` - confirmed the subscription moves to `finished` after the last cycle
- [ ] Cancelled a test subscription - `204` response, 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-08 per PO: anchor format confirmed - articles are stripped from operation-
   summary anchors (e.g. #create-subscription-plan, matching master-page precedent like #retrieve-
   order and #create-webhook). All links updated to the article-stripped form. Historical inventory:
   (create-a-subscription-plan, create-a-subscription, retrieve-a-subscription-cycle-list, cancel-a-
   subscription).

2. Plan changes are deferred to the upcoming manage/ category - add a cross-link to the change-plan
   deep dive here when those pages land.
-->

---

## What's next

- [: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.')
- [:Voucher: Build a subscription with trials and introductory pricing](/docs/guides/merchant/billing-subscriptions/api/trials 'Offer free trials and promotional pricing phases.')
- [:Webhook: Track subscriptions with webhooks](/docs/guides/merchant/billing-subscriptions/api/webhooks 'Receive real-time events when subscription states change.')