Sandbox
Help

Build a per-seat subscription model

Bill a unit price for every seat - with a seat count that's fixed on the plan or reported as it changes.

Per-seat pricing bills a unit price for each user, licence, or device: £15.00 per seat per month, however many seats the customer has. The Merchant API supports two shapes, and the one you pick determines how seat counts are handled for the life of the subscription:

  • Static seats - the seat count is fixed on the plan as a flat item with a quantity. Every cycle bills the same amount, and seat changes go through a scheduled plan change.
  • Dynamic seats - the plan carries a usage item with latest aggregation. You report the current seat count through the usage API whenever it changes, and each cycle bills the count you most recently reported.

In this guide, you sell a Team plan - £15.00 per seat per month, offered three ways: a 5-seat pack for £75.00 a month, a 10-seat pack for £150.00, and a flexible option that bills whatever seat count you report.

The example demonstrates how to model seat-based pricing on a single plan. Each variation is one way to buy the same £15.00 seat: the packs fix the count on a flat item, while the flexible option leaves the count to you and bills the seats you report. Map your own pricing the same way - every seat arrangement becomes a variation, and each customer subscribes to exactly one of them.

Combining pricing models

Items can share a phase - a per-seat item alongside a flat platform fee, for example. For the rules, see Subscription plans.

How it works

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

  1. Create a per-seat plan - model the seat price as items on variations: static seat packs carry a flat item with a quantity, and the dynamic option carries a usage item with latest aggregation.
  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 - report the seat count on the dynamic path, switch seat packs on the static paths, retrieve the billing cycles as they accrue, and cancel the subscription when the customer leaves.

The two seat shapes differ in how seat counts are handled for the life of the subscription:

Static seatsDynamic seats
Plan configurationflat item with quantity: Nusage item with usage_aggregation_method: latest
Charge each cycleUnit amount * quantityUnit amount * most recently reported count
Seat changesSwitch to another variation, scheduled at_cycle_endReport the new count via the usage API
Unreported cycleN/A - always bills the plan quantityCharges 0 - reported values don't carry over
Best forStable team sizes, predictable invoicesGrowing teams, monthly seat true-ups

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

Team plan 5-seat variation - £75.00/month 10-seat variation - £150.00/month Flexible seats - £15.00 per reported seat flat item - quantity 5 x £15.00 flat item - quantity 10 x £15.00 usage item - latest reported count x £15.00

Before you begin

Before you start, make sure you have the following:


Implement per-seat subscription

The steps below follow the Team plan narrative: you create the plan with its three variations, subscribe a customer to the 5-seat pack, collect the first payment, and confirm the subscription is active.

1. Create plan for per-seat pricing

Your Team plan sells the same £15.00 seat in three variations. Each variation is a single phase, and the seat price lives on an item in the phase: the seat packs carry a flat item with the count fixed in quantity, and the flexible variation carries a usage item that bills whatever count you report.

For the plan, variation, and phase hierarchy these items sit in, see Get started with the subscriptions API.

Call Create a subscription plan, turning your seat pricing into a plan your customers can subscribe to:

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": "Team plan",
  "variations": [
    {
      "phases": [
        {
          "ordinal": 1,
          "cycle_duration": "P1M",
          "amount": 7500,
          "currency": "GBP",
          "subscription_items": [
            {
              "type": "flat",
              "name": "Team seats",
              "unit": "seat",
              "quantity": 5,
              "amount": 1500,
              "currency": "GBP"
            }
          ]
        }
      ]
    },
    {
      "phases": [
        {
          "ordinal": 1,
          "cycle_duration": "P1M",
          "amount": 15000,
          "currency": "GBP",
          "subscription_items": [
            {
              "type": "flat",
              "name": "Team seats",
              "unit": "seat",
              "quantity": 10,
              "amount": 1500,
              "currency": "GBP"
            }
          ]
        }
      ]
    },
    {
      "phases": [
        {
          "ordinal": 1,
          "cycle_duration": "P1M",
          "subscription_items": [
            {
              "type": "usage",
              "name": "Active seats",
              "unit": "seat",
              "code": "active_seats",
              "usage_aggregation_method": "latest",
              "amount": 1500,
              "currency": "GBP"
            }
          ]
        }
      ]
    }
  ]
}
ParameterDescription
nameThe plan name - what your customers subscribe to
variationsPurchasing options for the plan - here, two seat packs and the flexible option
phasesSequential pricing stages within a variation, executed in ordinal order
ordinalExecution order of the phase, starting at 1
cycle_durationLength of the billing cycle, as an ISO 8601 duration, e.g., P1M
amountPrice per billing cycle, in minor units - 7500 is £75.00, 15000 is £150.00
currencyBilling currency, as an ISO 4217 code
subscription_itemsThe seat price as items on the phase - here, one item per variation
subscription_items[].typeflat bills a fixed quantity every cycle; usage bills a count you report
subscription_items[].quantitySeat count on a flat item - each cycle charges amount * quantity
subscription_items[].unitWhat the item bills - a free-form label, seat here
subscription_items[].package_sizeUnits grouped into one billable package - optional, defaults to 1; for seats, leave it at 1
subscription_items[].codeMerchant-defined identifier for a usage item - unique within the phase; you supply it when reporting the seat count
subscription_items[].usage_aggregation_methodHow reported counts become the charge - latest uses the most recently reported value at cycle end
subscription_items[].amountPrice per seat in minor units - 1500 is £15.00

2. Subscribe customer

When a customer wants to subscribe to your Team plan, you create a subscription. The subscription connects the customer - and their consent to use their payment details for recurring charges - to the variation they chose: the 5-seat variation in this walkthrough.

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 with an idempotency key, so you can safely retry the request without creating duplicate subscriptions:

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: 916b2ee5-a6bf-441d-9077-e4b9fc93c5ba

{
  "plan_variation_id": "993236c2-fd84-4b1f-b90a-f9691537beb8",
  "customer_id": "650e8400-e29b-41d4-a716-446655440001",
  "external_reference": "team_3f9a2c",
  "setup_order_redirect_url": "https://example.com/subscription/complete"
}
ParameterDescription
plan_variation_idThe variation the customer subscribes to - the 5-seat variation id you saved in step 1
customer_idThe customer to bill
external_referenceOptional: 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_urlOptional: where the customer lands after completing payment on the hosted checkout page
First-cycle charges differ by shape

On the static paths, the first payment covers the first cycle's full seat charge - £75.00 here. On the dynamic path, the first payment is collected before any seat count is reported - the usage item contributes nothing until you report usage, so make sure your first report lands inside the cycle.

3. Collect first payment

In step 2 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 - £75.00 for the 5-seat variation - 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, passing the setup_order_id you saved in step 2 as the order_id:

Request example
GET /api/orders/{order_id} HTTP/1.1
Host: merchant.revolut.com
Authorization: Bearer sk_abcdef12347890_...
Revolut-Api-Version: 2026-08-17
ParameterDescription
order_idThe ID of the setup order you saved in step 2

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:

Payment widget
Embed the payment flow in your site: you build the customer experience, and the customer never leaves your page
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:

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.
  2. Configure it to save the customer's payment method for merchant-initiated recurring transactions.
  3. The customer completes payment without leaving your site, and Revolut saves their payment method.

This step assumes you're familiar with a standard payment method integration, see Introduction to online payments.

4. Verify subscription state

When the customer completes the first payment in step 3, 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, passing the subscription id from step 2 in the request path:

Request example
GET /api/subscriptions/{subscription_id} HTTP/1.1
Host: merchant.revolut.com
Authorization: Bearer sk_abcdef12347890_...
Revolut-Api-Version: 2026-08-17
ParameterDescription
subscription_idThe ID of the subscription you saved in step 2

Once the subscription is active, your per-seat subscription is live, and Revolut takes over from here. We charge the customer's saved payment method the seat charge of the subscribed variation - £75.00 a month on the 5-seat pack. Failed payments are retried automatically - see Failed payments and retries.

You've completed the per-seat subscription flow! The Team plan is live with its three variations, and Revolut bills the customer automatically from here. Next, operate the subscription: report or change the seat count as the team evolves, retrieve the billing cycles as they accrue, and cancel it when the customer leaves.


Operate per-seat subscription

With the subscription active, Revolut bills the saved payment method automatically. What remains yours while it runs depends on the shape the customer chose.

On the dynamic path, you keep the reported seat count current; on the static paths, you move the customer between seat packs. On every path, you also retrieve the billing cycles - for entitlement checks, billing history, and reconciliation - and cancel the subscription when the customer leaves.

Adjust seat count

Seat counts change as teams grow and shrink. How you keep the billed count current depends on the shape the customer subscribed to - report it on the dynamic path, switch seat packs on the static paths.

Report seat count

On the dynamic path, reporting seat count is a recurring operation: whenever the customer's team changes size - seats added, seats removed - report the current count, and Revolut charges the latest value at each cycle's end. The example below follows a subscription on the flexible variation, with the customer's team at 12 seats.

The Idempotency-Key header is required for this endpoint - it prevents retries from creating duplicate usage records.

Call Create a subscription usage, passing the subscription id and the subscription_item_code you configured in step 1, to tell Revolut the seat count to bill at the cycle's end:

Request example
POST /api/subscription-usages HTTP/1.1
Host: merchant.revolut.com
Authorization: Bearer sk_abcdef12347890_...
Revolut-Api-Version: 2026-08-17
Content-Type: application/json
Idempotency-Key: a5e687aa-251e-47e5-b2b0-cd6a773b7097

{
  "subscription_id": "beebf6fb-f887-4bcf-af78-d46c7be5825f",
  "subscription_item_code": "active_seats",
  "usage_date": "2026-02-15T09:30:00Z",
  "quantity": 12
}
ParameterDescription
subscription_idThe ID of the subscription on the dynamic variation
subscription_item_codeThe code you gave the usage item in step 1 - here active_seats
usage_dateWhen the count applies - Revolut resolves the billing cycle from this date
quantityThe current seat count - a gauge, not a delta: report the total count, not the change

How reported counts become the cycle charge:

Reporting scenarioWhat happens
Report multiple times in a cycleThe most recent report at the cycle's cutoff date wins - report 5 seats, then 12, and the cycle bills 12 seats: 12 x £15.00 = £180.00
Report nothing during a cycleThe item charges 0 - values don't carry over, so if you stop reporting, billing stops
Correct a past cycleAccepted until its usage_cutoff_date - 12 hours after end_date by default. Send a new report with a usage_date inside the cycle being corrected
Report ahead for the next cycleAccepted and held in a pending cycle until that cycle starts

Change seat count

On the static paths, the seat count is fixed on the plan's flat item - there's no mid-cycle quantity update. Instead, move the customer to a different seat pack: Change a subscription plan with the new variation's plan_variation_id, scheduled to land at the end of the current cycle. The walkthrough customer grows into the 10-seat variation you created in step 1:

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

{
  "plan_variation_id": "72222cd7-87d5-408b-b604-880a6ac59451",
  "scheduled": "at_cycle_end"
}
ParameterDescription
plan_variation_idThe new seat pack - the 10-seat variation id you saved in step 1
scheduledWhen the change takes effect - at_cycle_end completes the current cycle on the old pack first

The next cycle bills the new pack, with no proration in between: the customer moves from 5 seats (£75.00 a month) to 10 (£150.00 a month) at the cycle boundary. For a team size your plan doesn't model, create a plan with the right quantity first, then switch the subscription to it the same way.

Retrieve billing cycles

While the subscription is active, Revolut creates a billing cycle for every billing period - one a month on the 5-seat 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:

Subscription c33e76eb - state: active Cycle 004c9dd4 - current, state: active Cycle 055f3a58 - state: finished Order 30b9d75b - charges £75.00 Order 22425f3b - charged £75.00

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, passing the id of the subscription you created in step 2 as the subscription_id:

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

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, passing the current cycle's id as the cycle_id:

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

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, passing the id of the subscription you created in step 2 as the subscription_id:

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

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 and Track subscriptions with webhooks.

If you run the 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 per-seat 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 the seat price as an item - flat with quantity on the static paths, usage with latest aggregation on the dynamic path - and saved the variation id the customer subscribes to
  • Subscribed a customer, collected the first payment, and confirmed the subscription is active
  • Static paths - confirmed each cycle bills amount x quantity, and a scheduled variation switch moves the customer to the new seat pack at cycle end
  • Dynamic path - reports always send an Idempotency-Key and target the right subscription_item_code
  • Dynamic path - confirmed an unreported cycle charges 0, and corrections land before the cycle's usage_cutoff_date
  • 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.


What's next

Build a fixed-rate subscription
Charge a fixed recurring amount - the simplest subscription flow
Build a usage-based subscription
Meter usage, report it via the API, and settle charges at cycle end
Build a subscription with trials and introductory pricing
Offer free trials and promotional pricing phases
Track subscriptions with webhooks
Receive real-time events when subscription states change
Rate this page