# Update Subscription

Subscription update checkouts let existing subscribers change their plan — upgrade, downgrade, or modify add-ons ( [https://docs.limio.com/product/self-service/what-are-the-standard-functionality-of-limio-self-service-manage-my-account/how-to-configure-an-update-subscription-flow](https://docs.limio.com/product/self-service/what-are-the-standard-functionality-of-limio-self-service-manage-my-account/how-to-configure-an-update-subscription-flow "mention") ) . They use a different flow from standard acquisition checkouts because the server drives the available next actions (effective dates, proration, removal side-effects).

{% hint style="info" %}
Subscription update checkouts use `order_type: "update_subscription"`. The SDK detects this automatically and routes mutations through the subscription update API.
{% endhint %}

### How it works

1. From a subscription management page, call `initiateCheckout` with `order_type: "update_subscription"` and a `forSubscription` reference.
2. The server creates an update checkout session and returns a `checkoutId`.
3. Redirect the subscriber to the update checkout page with the `checkoutId`.
4. On the offer selection page, use `selectOfferForSubscriptionUpdate` to let the subscriber pick a new plan.
5. The server resolves effective dates, proration, and next actions, then returns the updated basket.

### Starting an update checkout

Use `initiateCheckout` with `order_type: "update_subscription"` and the subscription ID. This creates the server-side update session.

```tsx
import React from "react"
import { useBasket } from "@limio/sdk"

const SubscriptionUpdateButton = ({ subscription, updatePageUrl = "/update" }) => {
  const { initiateCheckout, basketLoading } = useBasket()

  const handleUpdate = async () => {
    const basket = await initiateCheckout({
      order: {
        order_type: "update_subscription",
        forSubscription: {
          id: subscription.id
        }
      }
    })

    const checkoutId = basket.order.checkoutId
    window.location.href = `${updatePageUrl}?basket=${checkoutId}`
  }

  return (
    <button onClick={handleUpdate} disabled={basketLoading}>
      Change plan
    </button>
  )
}
```

{% hint style="info" %}
The `forSubscription.id` tells the server which subscription is being modified. The response includes the `checkoutId` used to track this update session.
{% endhint %}

***

### Selecting a new offer

Once the update checkout session exists, use `selectOfferForSubscriptionUpdate` on the offer selection page. Only one offer can be active at a time — selecting a new offer resets the checkout and re-resolves server-side state.

```typescript
await selectOfferForSubscriptionUpdate(orderItem: Partial<UpdateSubscriptionBasketItem>): Promise<void>
```

**Parameters:**

| Field      | Type           | Description                               |
| ---------- | -------------- | ----------------------------------------- |
| `offer`    | `ElasticOffer` | The offer the subscriber is switching to  |
| `quantity` | `number`       | Quantity (typically `1` for plan changes) |

```tsx
import React from "react"
import { useBasket } from "@limio/sdk"

const UpgradeOption = ({ offer, currentOfferId }) => {
  const { selectOfferForSubscriptionUpdate, clearOrderItems, basketLoading } = useBasket()

  const handleSelect = async () => {
    // Clear existing items first — the server will re-resolve
    // effective dates and side-effects for the new selection
    if (currentOfferId && currentOfferId !== offer.id) {
      clearOrderItems()
    }

    await selectOfferForSubscriptionUpdate({
      offer,
      quantity: 1
    })

    // Redirect to the update checkout page
    const params = new URLSearchParams(window.location.search)
    const checkoutId = params.get("basket")
    const ownerId = params.get("ownerId")
    window.location.assign(`/update?basket=${checkoutId}&ownerId=${ownerId}`)
  }

  return (
    <button onClick={handleSelect} disabled={basketLoading}>
      Select {offer.data.attributes.display_name__limio}
    </button>
  )
}
```

{% hint style="warning" %}
Selecting a new offer drops all existing order items and sends the new selection to the server. The server returns updated next actions, effective dates, and any proration details.
{% endhint %}

***

### Clearing items before re-selection

When the subscriber changes their mind and picks a different offer, call `clearOrderItems()` before `selectOfferForSubscriptionUpdate`. This ensures the server re-resolves everything cleanly for the new selection.

```typescript
const { clearOrderItems, selectOfferForSubscriptionUpdate } = useBasket()

// User changed their mind — clear and re-select
clearOrderItems()
await selectOfferForSubscriptionUpdate({ offer: newOffer, quantity: 1 })
```

`clearOrderItems` is a synchronous operation that empties the local basket state. The subsequent `selectOfferForSubscriptionUpdate` call syncs with the server.

***

### Adding items to a subscription update checkout

Use `addSubscriptionOrderItem` to append an order item to the subscription update basket. Unlike `selectOfferForSubscriptionUpdate` (which replaces all items), this method is additive — it keeps existing items and appends the new one.

The caller constructs the full order item shape, giving visibility and control over what's being added.

```typescript
await addSubscriptionOrderItem(orderItem: UpdateSubscriptionBasketItem): Promise<void>
```

**Parameters:**

| Field                 | Type     | Description                                            |
| --------------------- | -------- | ------------------------------------------------------ |
| `orderItemActionType` | `string` | The action type (e.g. `"update"` for quantity changes) |
| `offer`               | `Offer`  | The offer being modified                               |
| `quantity`            | `number` | The target quantity                                    |

{% hint style="info" %}
The server resolves the effective date based on the direction of the quantity change. Increases take effect immediately; decreases take effect at end-of-term.
{% endhint %}

**Example — seat quantity update flow:**

A common pattern is to use `addSubscriptionOrderItem` when initially adding a quantity change to the basket, then `updateItemQuantity` for subsequent adjustments to items already in the basket.

```tsx
import React, { useState } from "react"
import { useBasket } from "@limio/sdk"

const SeatQuantityUpdater = ({ subscription, subscriptionOffer }) => {
  const {
    initiateCheckout,
    addSubscriptionOrderItem,
    updateItemQuantity,
    orderItems,
    basketLoading
  } = useBasket()
  const [quantityUpdates, setQuantityUpdates] = useState([])

  // Step 1: Start the update checkout session if not already initiated
  const handleInitiate = async () => {
    const { nextActions } = await initiateCheckout({
      order: {
        order_type: "update_subscription",
        forSubscription: { id: subscription.id }
      }
    })
    // The server returns available quantity updates for the subscription
    setQuantityUpdates(nextActions.quantityUpdates ?? [])
  }

  // Step 2: Add a quantity change to the basket (item not yet in basket)
  const handleAddQuantityUpdate = async (offer, newQuantity) => {
    await addSubscriptionOrderItem({
      orderItemActionType: "update",
      offer,
      quantity: newQuantity
    })
  }

  // Step 3: Adjust quantity of an item already in the basket
  const handleAdjustQuantity = async (itemId, newQuantity) => {
    await updateItemQuantity(itemId, newQuantity)
  }

  return (
    <div>
      <button onClick={handleInitiate} disabled={basketLoading}>
        Manage seats
      </button>

      {/* Show available quantity updates from the server */}
      {quantityUpdates.map((item, i) => (
        <div key={item.id ?? i}>
          <span>Current seats: {item.currentQuantity}</span>
          <button
            disabled={basketLoading}
            onClick={() => handleAddQuantityUpdate(item, 10)}
          >
            Set to 10 seats
          </button>
        </div>
      ))}

      {/* Show items already in the basket with quantity adjustment */}
      {orderItems.map((item) => (
        <div key={item.id}>
          <span>Seats: {item.quantity}</span>
          <button
            disabled={basketLoading}
            onClick={() => handleAdjustQuantity(item.id, item.quantity + 1)}
          >
            Add seat
          </button>
        </div>
      ))}
    </div>
  )
}
```

**When to use which method:**

| Scenario                                       | Method                             |
| ---------------------------------------------- | ---------------------------------- |
| Item is **not yet** in the basket              | `addSubscriptionOrderItem`         |
| Item is **already** in the basket              | `updateItemQuantity`               |
| Selecting a completely new plan (replaces all) | `selectOfferForSubscriptionUpdate` |

Your component has access to `orderItems` and `nextActions.quantityUpdates` to determine which method to use.

***

### Quantity updates in subscription update checkouts

`updateItemQuantity` behaves differently in subscription update checkouts. Instead of calling the standard basket API, it routes through the subscription update API so the server can recalculate proration and effective dates.

```typescript
const { updateItemQuantity } = useBasket()

// In a subscription update checkout, this automatically
// uses the subscription update API under the hood
await updateItemQuantity(itemId, 3)
```

You don't need to handle this routing yourself — the SDK detects `order_type: "update_subscription"` and uses the correct endpoint.

***

### Notes

* Start every update flow with `initiateCheckout` using `order_type: "update_subscription"` and `forSubscription: { id }`.
* Always call `clearOrderItems()` before selecting a different offer to avoid stale server state.
* The `ownerId` query parameter identifies which subscription is being updated — pass it through when redirecting.
* Server-driven state means the basket response may include fields not present in standard checkouts (effective dates, next actions, proration details).
* See [Basket (Cart)](https://github.com/innovate42/innovate42-service-template/blob/docs/docs/_external/spaces/developer-docs/limio-sdk/basket-cart.md) for all other basket methods (adding items, promo codes, checkout navigation, etc.).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.limio.com/developers/limio-sdk/subscription-update-checkout.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
