> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.solvimon.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.solvimon.com/_mcp/server.

# Plan changes in a pricing plan group

Move a subscription from one plan to another in the same pricing plan group in a single call, with the timing decided by the group rather than by the caller.

---

## Why this matters

An upgrade from Starter to Pro is one commercial decision. As a billing operation it is several: end the running schedule on the right date, open a new one on the target plan, keep the currency and billing period, and get the pro-ration right. Doing that by hand means the same sequence of calls every time. The date it lands on is then whatever the caller passed, rather than what the plan family says it should be.

A [pricing plan group](/platform-guides/products-and-pricing/pricing-plans) already holds that policy: which plans belong together, in what order, and when a move between them takes effect. [`change-plan`](https://docs.solvimon.com/api-docs/configuration-api/pricing-plan-subscriptions/post-pricing-plan-subscriptions-by-resource-id-change-plan) executes it. An upgrade becomes one request, and the timing rules live with the plans instead of in your integration.

## How it works

A group carries an ordered list of member plans and three transition policies:

| Field                   | What it decides                                                                                                                                                                                                 |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pricing_plans[].order` | The position of a plan within the group. It is what makes one move an upgrade and the opposite a downgrade                                                                                                      |
| `upgrade_type`          | When a move to a higher-ordered plan takes effect                                                                                                                                                               |
| `downgrade_type`        | When a move to a lower-ordered plan takes effect                                                                                                                                                                |
| `cancellation_type`     | Declared on the group for cancelling a member plan. This action does not read it; [cancelling a subscription](/platform-guides/customers-and-billing/subscriptions/subscription-lifecycle) is its own operation |
| `status`                | A move is only accepted while the group is `ACTIVE`                                                                                                                                                             |

The move itself is a new [schedule](/platform-guides/customers-and-billing/subscriptions/subscription-schedules) on the same subscription, pointing at the target plan. The schedule that was running is closed at the moment the new one starts, so the subscription still has exactly one schedule in effect.

```mermaid
flowchart LR
    A["Current schedule<br />Starter, order 1"] -->|POST change-plan| B["New schedule<br />Pro, order 2"]
    A --> C["Closed at the new<br />schedule's start"]
```

Direction is inferred, never passed. A target with a higher `order` than the current plan is an upgrade and follows `upgrade_type`; a lower one is a downgrade and follows `downgrade_type`. That policy then resolves the date:

| Policy                | Start of the new schedule                                        | `start_at` on the request |
| --------------------- | ---------------------------------------------------------------- | ------------------------- |
| `IMMEDIATE`           | Now, or the `start_at` you send                                  | Allowed                   |
| `IMMEDIATE_PRO_RATA`  | Now, or the `start_at` you send                                  | Allowed                   |
| `NEXT_BILLING_PERIOD` | The subscription's next invoice date, in the account's time zone | Rejected                  |
| `NOT_ALLOWED`         | The transition is refused                                        | Rejected                  |

`IMMEDIATE` and `IMMEDIATE_PRO_RATA` resolve to the same start moment. What follows from that start is the subscription's own [pro-ration behaviour](/platform-guides/customers-and-billing/subscriptions/billing-cycles-proration): whether the closed period is charged in full or pro-rated. The two policies describe that behaviour rather than change it.

## Change the plan

Send the target plan. Everything else is either inferred or carried over:

**`Upgrade a subscription to another plan in its group`**

```bash Upgrade a subscription to another plan in its group
curl -X POST https://test.api.solvimon.com/v1/pricing-plan-subscriptions/ppsu_jwDeeN0tYSY3F7BkeN1v/change-plan \
  -H "X-API-KEY: <apiKey>" \
  -H "Content-Type: application/json" \
  -d '{
    "pricing_plan_id": "ppla_QwDeeN0vcYJaBLAc0C29"
  }'
```

**`Response`**

```json Response
{
  "object_type": "PRICING_PLAN_SCHEDULE",
  "id": "ppsc_hwDeeN0vcYJaBLAc0C1W",
  "pricing_plan_subscription_id": "ppsu_jwDeeN0tYSY3F7BkeN1v",
  "pricing_plan_version_id": "ppve_2PnBx7VdtRgLmE4WcQJ8K",
  "status": "ACTIVE",
  "start_at": "2026-10-01T00:00:00Z",
  "billing_period": { "type": "MONTH", "value": 1 },
  "pricing_currency": "EUR"
}
```

| Field             | Required | Description                                                                                                                              |
| ----------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `pricing_plan_id` | Yes      | The plan to move to. A member of the same group as the subscription's current plan                                                       |
| `start_at`        | No       | Only on an `IMMEDIATE` or `IMMEDIATE_PRO_RATA` policy. Defaults to now, and cannot be in the past                                        |
| `billing_period`  | No       | Change the billing period along with the plan. Must be one of the target version's billing period settings. Absent keeps the current one |

The response is the new schedule, returned with `201 Created`. See [Change the pricing plan of a subscription](https://docs.solvimon.com/api-docs/configuration-api/pricing-plan-subscriptions/post-pricing-plan-subscriptions-by-resource-id-change-plan) in the API reference. The call needs both `PRICING_PLAN_SUBSCRIPTION.UPDATE` and `PRICING_PLAN_SCHEDULE.CREATE`, since it updates a subscription by creating a schedule on it.

### What the new schedule takes with it

| Carried over                                                                                                                        | Not carried over  |
| ----------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| The pricing currency, from the current schedule or the subscription, when the target version has currency settings                  | Override pricings |
| The billing period, from the request, the current schedule or the subscription, when the target version has billing period settings | Commitments       |
| The invoice date realignment setting of the schedule it replaces                                                                    | Discounts         |
|                                                                                                                                     | Seat values       |

Anything negotiated onto the schedule being replaced is customer-specific pricing on a plan the customer is leaving. It is not copied onto the plan they are moving to. Configure it again on the new schedule if it still applies.

A target plan that is a [rate card](/platform-guides/products-and-pricing/rate-cards) works the same way. The version applicable at the new schedule's start is resolved, and the schedule keeps following the rate card rather than being pinned to that version.

## Change only the billing period

A plan sold in several billing periods, monthly and yearly against the same pricing, is moved between them by sending the plan the subscription is already on together with a different `billing_period`:

**`Move a subscription from monthly to yearly billing`**

```bash Move a subscription from monthly to yearly billing
curl -X POST https://test.api.solvimon.com/v1/pricing-plan-subscriptions/ppsu_jwDeeN0tYSY3F7BkeN1v/change-plan \
  -H "X-API-KEY: <apiKey>" \
  -H "Content-Type: application/json" \
  -d '{
    "pricing_plan_id": "ppla_hwDeeN0vcYJaBLAc0C1W",
    "billing_period": { "type": "YEAR", "value": 1 }
  }'
```

There is no `order` difference to read the direction from here, so it comes from the length of the period instead. A longer billing period is an upgrade, a shorter one a downgrade. The group's policy for that direction then decides the timing as usual. Two periods of the same length, `MONTH/12` against `YEAR/1`, carry no direction and are rejected.

## Show the group in the customer portal

A self-service upgrade screen has to know which plans it may offer. That is exactly the group's member list, and the portal exposes it for the subscription the session is scoped to:

**`Read the group behind a subscription`**

```bash Read the group behind a subscription
curl https://test.api.solvimon.com/v1/portal/pricing-plan-subscriptions/ppsu_jwDeeN0tYSY3F7BkeN1v/pricing-plan-group \
  -H "Authorization: Bearer <portalAccessToken>"
```

The response is the group itself. It carries the members with their `order`, plus the `upgrade_type`, `downgrade_type` and `cancellation_type`. Those tell the screen which moves are possible, and when each would take effect.

> **Note**
>
> The portal endpoint is read-only. Performing the change is a platform-side call, so the customer's action reaches `change-plan` through your backend, not from the browser. For the changes a customer can make to their own subscription directly, see [Self-serve plan changes](/platform-guides/customers-and-billing/self-serve-plan-changes).

## What is rejected

| Rejected                                                      | Field             | Why                                                                                                             |
| ------------------------------------------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------- |
| The subscription is not `ACTIVE`                              | `resource_id`     | There is no running schedule to replace                                                                         |
| A later schedule already exists on the subscription           | `resource_id`     | The change truncates the last schedule, and truncating one that has a successor would leave a gap or an overlap |
| The current plan is in no group, or the group is not `ACTIVE` | `pricing_plan_id` | There is no policy to apply                                                                                     |
| The target plan is not a member of that group                 | `pricing_plan_id` | A move outside the group is a migration, not a plan change                                                      |
| The same plan with no `billing_period`                        | `pricing_plan_id` | Nothing would change                                                                                            |
| The direction's policy is `NOT_ALLOWED`                       | `pricing_plan_id` | The group forbids that move                                                                                     |
| `start_at` on a `NEXT_BILLING_PERIOD` policy                  | `start_at`        | The date comes from the invoice schedule, not from the caller                                                   |

## Via Desk

You manage the group in Desk under **Pricing → Plans**, on the **Plan groups** tab. There you set its member plans and their order, the timing of upgrades, downgrades and cancellations, and its status. Desk has no action yet that moves a subscription between plans in a group. An agent making the same move edits the subscription's schedules directly, which the group's policies do not bind. The policies exist to keep an automated or self-service change on the terms the plan family was sold on.

## Edge cases

* **The move is not a migration.** [Migrating a schedule](/platform-guides/customers-and-billing/subscriptions/subscription-schedules) moves it to a different version of the plan it is already on. `change-plan` moves the subscription to a different plan. That is why it builds a new schedule instead of remapping the existing one.
* **`start_at` cannot be in the past.** The subscription also has to be active at that moment, so a date before its start is rejected.
* **Only billing subscriptions.** A quote subscription is rejected: agreed terms change through a new quote version, not through this action.
* **The group is resolved from the current plan, not from the request.** If the subscription's plan was removed from its group, the call fails. It does not fall back to the target's group.