> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stora.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating to site-scoped protection levels

> Protection levels are moving from your account to your sites. Prepare your integration before your account is switched over.

Protection levels are moving from your account to your sites. Today one set of levels is shared across every site you operate. After this change each site has its own levels, with its own prices.

This guide covers what changes in the API, what you need to do, and when.

## Why

* Protection prices can differ from site to site, which operators with mixed markets need and can't currently do.
* It's a prerequisite for connecting multiple Stripe accounts to one Stora account, which we're building now.

## The two phases

Your account moves through two phases.

<Note>
  Every account is in **Preparation** until we switch it over. We'll tell you before we activate yours, and we'll give you notice.
</Note>

### Preparation

We've replicated every global protection level to every site on your account. Each site copy is a distinct product:

* its own protection level ID
* its own product and price in Stripe
* its own base price

Globals remain the source of truth. We mirror changes down to the copies — edit a global's base price and every site copy follows. Site copies can't be edited independently during this phase, so a customer sees the same price whichever route they come through.

You'll see duplicate products and prices in your Stripe account as a result.

<Warning>
  Don't archive the duplicate products and prices in Stripe. They're the live products for your sites once you're switched over.
</Warning>

Nothing in the API changes by default in this phase. Global levels are still returned by default and still accepted on orders. The Back Office and Storefront still work in terms of global protection levels; the site copies aren't surfaced there.

This phase exists to give you time to migrate.

### Activation

When your account is switched over, site protection levels become authoritative everywhere — API, Back Office and Storefront.

* The API returns site levels and rejects global IDs on new orders.
* Global levels can no longer be created, and their base prices can no longer be changed, in the API or the Back Office.
* The Back Office moves protection management from your account to each site.

## Affected endpoints

| Endpoint                                               | What changes                                                                                                             |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `GET /2025-09/protection_levels`                       | New `site_scoped` and `site_id` parameters available now. Returns site levels by default after activation.               |
| `GET /2025-09/protection_levels/{id}`                  | Resolves site levels as well as globals now. Keeps resolving globals after activation, for referential integrity.        |
| `POST /2025-09/protection_levels/{id}/base_price`      | Still writes to global levels, and we mirror the change to every site copy. Rejected for global levels after activation. |
| `POST /2025-09/orders`                                 | Global protection IDs rejected after activation.                                                                         |
| `PATCH /2025-09/orders/{id}`                           | As above.                                                                                                                |
| `POST /2025-09/orders/{id}/finalize`                   | As above.                                                                                                                |
| `POST /2025-09/orders/{id}/line_items`                 | As above.                                                                                                                |
| `PATCH /2025-09/orders/{id}/line_items/{line_item_id}` | As above.                                                                                                                |
| `GET /2025-09/orders/{id}/validate`                    | An order holding a global protection level stops validating after activation.                                            |
| `POST /2025-09/deals`                                  | Global protection IDs rejected after activation.                                                                         |
| `PATCH /2025-09/deals/{id}`                            | As above.                                                                                                                |

All of this stays within API version `2025-09`. You don't need to upgrade to a later version to migrate.

## Listing protection levels

By default the collection returns your global levels, unchanged:

```text theme={null}
GET /2025-09/protection_levels
```

To reach your site levels, add `site_scoped=true`. This is the parameter we recommend building against. It returns every site level across your account, with the globals excluded — which is exactly what the unfiltered collection will return once you're activated:

```text theme={null}
GET /2025-09/protection_levels?site_scoped=true
```

Use it as your default listing call during preparation. It gives you the whole site-level catalogue in one place, it's the closest thing to the post-activation response you can see today, and it doesn't require you to know your site IDs up front.

If you'd rather narrow to particular sites, filter by site ID instead. Pass several, comma-separated, to cover more than one:

```text theme={null}
GET /2025-09/protection_levels?site_id=site_3e6ffcb963dc4b49,site_76cc3340ef180e55
```

<Note>
  Both `site_scoped` and `site_id` return `409 Conflict` until we've finished preparing your account. If you see `Site-scoped protection levels are unavailable until insurance preparation is complete for this operator`, your site copies don't exist yet — retry once we've confirmed your account is prepared.
</Note>

`site_scoped` is a migration parameter. It exists for this transition, so you won't find it in the API reference — this guide is its documentation. It works while your account is being prepared, and once you're activated it's no longer needed, because by then the plain call returns exactly what it returns today:

```text theme={null}
GET /2025-09/protection_levels
```

So the shape of the migration is: send `site_scoped=true` now, drop it once you're switched over.

`site_id` is not temporary. It's part of the API and is the filter to keep in your integration long term.

The collection never mixes globals and site levels.

### The `site` field

Protection levels have a `site`. It's `null` on a global level, and on a site level it gives you the site's ID:

```json theme={null}
{
  "id": "plvl_e8f3ad0a07e47566",
  "cover_level": { "amount": 2000000, "currency": "GBP", "formatted": "£20,000.00" },
  "prices": [
    {
      "billing_period": "weekly",
      "price": { "amount": 999, "currency": "GBP", "formatted": "£9.99" },
      "stripe_price_id": "price_123"
    }
  ],
  "site": { "id": "site_14b419f1096013f1" },
  "stripe_product_id": "prod_Sj6us30iGDiaXO",
  "public": true
}
```

`site` is expandable, so ask for the full site object when you need more than the ID:

```text theme={null}
GET /2025-09/protection_levels?site_scoped=true&expand=site
```

Note the `stripe_product_id` too — each site copy has its own, which is why the duplicates appear in your Stripe account.

## Setting base prices

Base prices are still written to global levels, and we mirror each change down to every site copy:

```text theme={null}
POST /2025-09/protection_levels/{id}/base_price
```

Passing the ID of a site copy returns `404`. Site copies can't be priced independently during preparation — that's what keeps a customer's price the same whichever route they come through. After activation this reverses: site levels become writable and global levels are rejected.

## Creating and updating orders

Right now, orders accept either a global protection ID or a protection ID belonging to the order's site. After activation, only the latter.

```text theme={null}
POST /2025-09/orders
```

```json theme={null}
{
  "site": { "id": "site_14b419f1096013f1" },
  "line_items": [
    {
      "type": "protection",
      "quantity": 1,
      "price": { "amount": 2999 },
      "item": { "id": "plvl_e8f3ad0a07e47566" }
    }
  ]
}
```

Other order fields are omitted here for brevity. The protection level is the one listed above, and it belongs to the site the order is for — that pairing is the whole change.

Two rules to code against:

1. **Resolve the site first.** Pick the protection level from the site the order is for, not from a stored global ID.
2. **A protection level from the wrong site is rejected**, the same as a global one, once you're activated.

Deals follow the same rule. A `protection` line item on `POST /2025-09/deals` or `PATCH /2025-09/deals/{id}` must reference either an account-level protection level or one belonging to the deal's site.

<Warning>
  If your integration holds a hardcoded or cached protection level ID anywhere, that's the thing most likely to break. Find it now.
</Warning>

## Webhooks

Event types and API version are unchanged:

```text theme={null}
protection_level.created
protection_level.updated
```

Which resource they describe follows your phase:

| Phase       | Global level saved | Site level saved           |
| ----------- | ------------------ | -------------------------- |
| Preparation | Event fires        | No event                   |
| Activated   | No event           | Event fires, with its site |

So during preparation you'll keep receiving events for globals exactly as you do now, and replication won't flood your endpoint. At activation the resource in the payload becomes a site level.

## What doesn't change

* **Existing orders and subscriptions.** They keep the protection level IDs they were created with. We don't rewrite stored references, and historical resources keep returning the IDs you already have.
* **Prices your customers pay.** Site copies start identical to their globals and are kept in sync until activation.
* **Tax.** Not affected by this change.
* **API version.** Everything here is `2025-09`.
* **The Back Office and Storefront**, until activation.

## Getting help

Email [api\_support@stora.co](mailto:api_support@stora.co) with your account name and what you're building.

We're happy to review your integration changes before you ship them, and to switch your account over early if you're ready ahead of us.

<CardGroup cols={2}>
  <Card title="Booking flow" icon="cart-shopping" href="/2025-09/guides/booking-flow">
    See where protection line items sit in the end-to-end order flow.
  </Card>

  <Card title="Webhooks" icon="bell" href="/2025-09/guides/webhooks">
    Configure endpoints and check which API version your payloads use.
  </Card>
</CardGroup>
