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
flatitem with aquantity. Every cycle bills the same amount, and seat changes go through a scheduled plan change. - Dynamic seats - the plan carries a
usageitem withlatestaggregation. 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.
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.
- Create a per-seat plan - model the seat price as items on variations: static seat packs carry a
flatitem with aquantity, and the dynamic option carries ausageitem withlatestaggregation. - Subscribe the customer - create the subscription, which starts in
pendingstate until the first payment is collected. - 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. - 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 seats | Dynamic seats | |
|---|---|---|
| Plan configuration | flat item with quantity: N | usage item with usage_aggregation_method: latest |
| Charge each cycle | Unit amount * quantity | Unit amount * most recently reported count |
| Seat changes | Switch to another variation, scheduled at_cycle_end | Report the new count via the usage API |
| Unreported cycle | N/A - always bills the plan quantity | Charges 0 - reported values don't carry over |
| Best for | Stable team sizes, predictable invoices | Growing teams, monthly seat true-ups |
The Team plan you'll build in this guide looks like this:
Before you begin
Before you start, make sure you have the following:
- You've completed Get started with the Subscriptions API - it introduces the universal subscription flow this guide builds on
- An existing customer - see Create a customer
- Familiarity with the core subscription concepts - see Subscription plans and Subscription lifecycle
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:
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"
}
]
}
]
}
]
}| Parameter | Description |
|---|---|
name | The plan name - what your customers subscribe to |
variations | Purchasing options for the plan - here, two seat packs and the flexible option |
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 duration, e.g., P1M |
amount | Price per billing cycle, in minor units - 7500 is £75.00, 15000 is £150.00 |
currency | Billing currency, as an ISO 4217 code |
subscription_items | The seat price as items on the phase - here, one item per variation |
subscription_items[].type | flat bills a fixed quantity every cycle; usage bills a count you report |
subscription_items[].quantity | Seat count on a flat item - each cycle charges amount * quantity |
subscription_items[].unit | What the item bills - a free-form label, seat here |
subscription_items[].package_size | Units grouped into one billable package - optional, defaults to 1; for seats, leave it at 1 |
subscription_items[].code | Merchant-defined identifier for a usage item - unique within the phase; you supply it when reporting the seat count |
subscription_items[].usage_aggregation_method | How reported counts become the charge - latest uses the most recently reported value at cycle end |
subscription_items[].amount | Price 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:
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"
}| Parameter | Description |
|---|---|
plan_variation_id | The variation the customer subscribes to - the 5-seat variation id you saved in step 1 |
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 |
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:
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 |
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:
Choose the approach that fits your integration:
Keep the customer on your site with an embedded payment widget or a card-not-present method:
- Build your payment acceptance solution on your frontend with the widget or payment method of your choice, initialising it with the
tokenfrom the response. - Configure it to save the customer's payment method for merchant-initiated recurring transactions.
- 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:
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 |
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:
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
}| Parameter | Description |
|---|---|
subscription_id | The ID of the subscription on the dynamic variation |
subscription_item_code | The code you gave the usage item in step 1 - here active_seats |
usage_date | When the count applies - Revolut resolves the billing cycle from this date |
quantity | The current seat count - a gauge, not a delta: report the total count, not the change |
How reported counts become the cycle charge:
| Reporting scenario | What happens |
|---|---|
| Report multiple times in a cycle | The 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 cycle | The item charges 0 - values don't carry over, so if you stop reporting, billing stops |
| Correct a past cycle | Accepted 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 cycle | Accepted 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:
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"
}| Parameter | Description |
|---|---|
plan_variation_id | The new seat pack - the 10-seat variation id you saved in step 1 |
scheduled | When 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:
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:
GET /api/subscriptions/{subscription_id}/cycles HTTP/1.1
Host: merchant.revolut.com
Authorization: Bearer sk_abcdef12347890_...
Revolut-Api-Version: 2026-08-17Run 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:
GET /api/subscriptions/{subscription_id}/cycles/{cycle_id} HTTP/1.1
Host: merchant.revolut.com
Authorization: Bearer sk_abcdef12347890_...
Revolut-Api-Version: 2026-08-17Cancel 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:
POST /api/subscriptions/{subscription_id}/cancel HTTP/1.1
Host: merchant.revolut.com
Authorization: Bearer sk_abcdef12347890_...
Revolut-Api-Version: 2026-08-17The 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 -
flatwithquantityon the static paths,usagewithlatestaggregation on the dynamic path - and saved the variationidthe customer subscribes to - Subscribed a customer, collected the first payment, and confirmed the subscription is
active - Static paths - confirmed each cycle bills
amountxquantity, and a scheduled variation switch moves the customer to the new seat pack at cycle end - Dynamic path - reports always send an
Idempotency-Keyand target the rightsubscription_item_code - Dynamic path - confirmed an unreported cycle charges
0, and corrections land before the cycle'susage_cutoff_date - Cancelled a test subscription -
204response, no new cycles created,SUBSCRIPTION_CANCELLEDevent 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.