# Get started with the Subscriptions API

**Create a plan, subscribe a customer, and collect the first recurring payment - the flow every subscription integration builds on.**

Every subscription integration follows the same core flow, whatever the pricing model.

This guide walks you through the flow once - the scenario guides vary the plan configuration for fixed-rate, per-seat, usage-based, and trial pricing.

## How it works

The integration flow breaks down into the following steps:

1. **Create a subscription plan** - define the pricing: one or more variations (e.g. monthly and yearly), each with phases that set the billing cycle and amount.
2. **Create a subscription** - attach a customer to a plan variation. The subscription starts in `pending`, and Revolut creates a setup order for the first payment.
3. **Collect the first payment** - redirect the customer to the hosted checkout page, or embed a payment widget in your site. The customer pays, and Revolut saves their payment method.
4. **The subscription activates** - Revolut charges the saved payment method automatically on each billing cycle, and retries failed payments.
5. **Monitor and manage** - retrieve subscriptions and billing cycles, and receive webhook events when subscription states change.

### Plans, variations, and phases

Pricing details live on the plan in three nested levels. 

A **plan** is the product you sell - "Premium plan" - and it carries one or more **variations**: pricing options such as monthly and yearly billing. 

Each variation contains one or more **phases** that run in sequence - a phase sets one price (`amount`, in minor units) for billing cycles of a given length (`cycle_duration`). Single-phase variations charge the same price indefinitely; multi-phase variations change price over time, which is how introductory pricing and trials work.

```mermaid
flowchart TD
    subgraph plan["Premium plan"]
        subgraph monthly ["Monthly variation"]
            phase1["Phase 1 - £9.90/month<br>first 3 cycles"]
            phase2["Phase 2 - £19.00/month<br>ongoing"]
        end
        subgraph yearly ["Yearly variation"]
            phase3["Phase 1 - £190.00/year<br>ongoing"]
        end
    end
    phase1 -->|"after 3 cycles"| phase2
```

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

    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"
    }
```

### Before you begin

Before you start integrating, make sure you have the following:

- [ ] An active **Revolut Business account with a Merchant account** - see [Get started with the Merchant API](/docs/guides/merchant/get-started).
- [ ] A **sandbox account with API keys** - see [Set up a sandbox account](/docs/guides/merchant/test-and-go-live/set-up-sandbox).
- [ ] An **existing customer** - the customer must already exist in the API before you create a subscription. 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 your first subscription

The following steps build on each other: each API call returns the IDs the next step needs, so work through them in order and save every response.

### 1. Create a subscription plan

You start here once you have a recurring service to sell - software access, a membership, a hosted product, anything customers pay for on an ongoing basis. Say that service is your **Pro plan**, billed at £99.00 a month.

The plan you create consumes these business details: the name your customers recognise, the monthly billing cadence, and the price. One variation with one phase is enough.

:::info
To understand how plans, variations, and phases relate, see [Plans, variations, and phases](#plans-variations-and-phases).
:::

Call [Create a subscription plan](/docs/api/merchant#create-subscription-plan) to define a plan with the respective details:

- ![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": "Pro plan",
    "variations": [
      {
        "phases": [
          {
            "ordinal": 1,
            "cycle_duration": "P1M",
            "amount": 9900,
            "currency": "GBP"
          }
        ]
      }
    ]
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `name` | The plan name - what your customers subscribe to |
  | `variations` | Pricing options for the plan, e.g., monthly and yearly |
  | `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` |
  | `cycle_count` | Number of cycles the phase runs for - omit to run indefinitely |
  | `amount` | Price per billing cycle, in minor units - `9900` is £99.00 |
  | `currency` | Billing currency, as an [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) code |

- ![Response]
  The response returns the plan with the provided details and system-generated IDs. Save the variation `id` - you need it to create the subscription in step 2. Save the plan `id` as well: it identifies the plan when you retrieve it later, e.g., to list its variations before a plan change.

  ```json [Response example] {2,9}
  {
    "id": "f757b068-f287-43c8-8d05-9c073fecbe73",
    "name": "Pro plan",
    "state": "active",
    "created_at": "2026-01-26T08:59:09.433527Z",
    "updated_at": "2026-01-26T08:59:09.433527Z",
    "variations": [
      {
        "id": "f4e0a171-4f4e-484b-b0a2-22085059af65",
        "phases": [
          {
            "id": "23319d04-4b23-4ae7-ba54-82112c752683",
            "ordinal": 1,
            "cycle_duration": "P1M",
            "amount": 9900,
            "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 ID - save it, you'll use it in [step 2](#2-create-a-subscription) to create the subscription |

### 2. Create a subscription

When a customer wants to subscribe to the **Pro plan**, you create a subscription. The subscription connects the customer - and their consent to use their payment details for recurring charges - to one variation of the plan, e.g., the variation for monthly billing. You identify the variation with the `id` you saved after creating the plan. 

:::warning
The customer must already exist in the API. 
:::

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]
  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: 0f7c9a1e-3f2a-4b8e-9d1c-7a2e5b8d3f10

  {
    "plan_variation_id": "f4e0a171-4f4e-484b-b0a2-22085059af65",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "external_reference": "cus_8f3a91",
    "setup_order_redirect_url": "https://example.com/subscription/complete"
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `plan_variation_id` | The variation the customer subscribes to - the variation `id` you saved from [step 1](#1-create-a-subscription-plan) |
  | `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` to collect the first payment in the next step.

  ```json [Response example] {11}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "external_reference": "cus_8f3a91",
    "state": "pending",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "plan_id": "f757b068-f287-43c8-8d05-9c073fecbe73",
    "plan_variation_id": "f4e0a171-4f4e-484b-b0a2-22085059af65",
    "payment_method_type": "automatic",
    "created_at": "2026-01-26T09:15:00.036001Z",
    "updated_at": "2026-01-26T09:15:00.036001Z",
    "setup_order_id": "a50e8400-e29b-41d4-a716-446655440005",
    "current_cycle_id": "a31627fb-b037-4566-8d7b-f380c1f44653"
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `id` | The subscription ID - identifies the subscription in retrieve operations and webhook events |
  | `state` | `pending` - the subscription becomes `active` once the customer completes the first payment |
  | `setup_order_id` | The setup order collecting the first payment - save it, step 3 retrieves the order with it |

### 3. Collect the first payment

In the previous step, 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 - £99.00 for the Pro plan - and saves the customer's payment method for the recurring cycles that follow. 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-create-a-subscription) 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-create-a-subscription) |

- ![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": "a50e8400-e29b-41d4-a716-446655440005",
    "token": "0adc0e3c-ab44-4f33-bcc0-534ded7354ce",
    "state": "pending",
    "created_at": "2026-01-26T09:15:00.036001Z",
    "updated_at": "2026-01-26T09:15:00.036001Z",
    "amount": 9900,
    "currency": "GBP",
    "checkout_url": "https://checkout.revolut.com/payment-link/0adc0e3c-ab44-4f33-bcc0-534ded7354ce"
  }
  ```

  | Parameter | Description |
  |-----------|-------------|
  | `token` | The public token for initialising a payment widget |
  | `state` | `pending` - the order completes once the customer pays the 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-create-a-subscription), 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-the-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-create-a-subscription) 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-create-a-subscription) |

- ![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}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "external_reference": "cus_8f3a91",
    "state": "active",
    "customer_id": "650e8400-e29b-41d4-a716-446655440001",
    "plan_id": "f757b068-f287-43c8-8d05-9c073fecbe73",
    "plan_variation_id": "f4e0a171-4f4e-484b-b0a2-22085059af65",
    "payment_method_type": "automatic",
    "payment_method_id": "6689e244-8af7-4ada-9448-a91f02d4f192",
    "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": "950e8400-e29b-41d4-a716-446655440004"
  }
  ```

  | 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` |

Going forward, Revolut charges the saved payment method automatically on each billing cycle. If a renewal payment fails, the subscription moves to `overdue` and Revolut retries the payment - see [Failed payments and retries](/docs/guides/merchant/billing-subscriptions/subscription-lifecycle#failed-payments-and-retries).

:::info[Trial plans]
If the plan includes a `trial_duration`, the subscription still starts in `pending` - but it activates as soon as the customer provides a payment method, and Revolut collects the first payment when the trial ends. 

See [Build a subscription with trials and introductory pricing](/docs/guides/merchant/billing-subscriptions/api/trials).
:::

:::tip
**You've built your first subscription!** The plan exists, the customer is subscribed, the first payment is collected, and the subscription is `active`. With the universal flow complete, you're ready to build a specific pricing model in a scenario guide.
:::

---

## Implementation checklist

Confirm your integration handles the universal flow before moving on to a scenario guide. 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 and saved the returned variation `id`
- [ ] Created a subscription for an existing customer - the response contains `state: "pending"` and a `setup_order_id`
- [ ] Collected the first payment via the setup order - hosted checkout or payment widget
- [ ] Retrieved the subscription and confirmed `state: "active"`
- [ ] Handled failed payments - a failed renewal moves the subscription to `overdue`, and Revolut retries automatically

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)

Sandbox verification needed before master:

1. renewal timing - cycles run on real durations; confirm with the API team whether Sandbox accepts
   short cycle durations (e.g. P1D) so merchants can observe a renewal and the overdue flow
   (related: event-timing TODO on webhooks.md).

2. Failed first payment - confirm the observable Sandbox behaviour when the setup-order payment
   fails with an error test card (does the subscription stay `pending`?); consider a dedicated
   checklist item.

3. Webhook events - step 4 notes there's no activation event; confirm which subscription webhook
   events merchants should expect during this flow, then consider adding a webhook check item.
-->

<!--
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-customer, retrieve-an-order, retrieve-a-subscription).

2. Lifecycle management operations are 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')
- [:Voucher: Build a subscription with trials](/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')