> For the complete documentation index, see [llms.txt](https://docs.peakcommerce.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.peakcommerce.com/guides/administration-guides/guide-deactivating-a-zuora-rate-plan-safely.md).

# Guide: Deactivating a Zuora Rate Plan Safely

### Overview

Deactivating a rate plan in Zuora looks like a one-click catalog cleanup — but if that plan is still referenced by a **product set** and offered by a live **acquisition journey**, the click can take your checkout down. New customers keep being offered a plan the billing system will no longer accept, every order against it fails, and in-flight checkout sessions lose their ability to convert.

This guide explains exactly what happens, in what order, and gives you the **safe sequence for retiring or replacing a rate plan** so customers never see the gap. The short version: **PeakCommerce first, Zuora last.** Retire the plan from your product sets before you deactivate it in the billing catalog — never the other way around.

### What happens when you deactivate a rate plan in Zuora

The impact unfolds in three phases, and the middle one is the dangerous part.

**Phase 1 — in Zuora, immediately.** The rate plan can no longer be used on new orders. Zuora rejects order submissions that reference it. Subscriptions that already contain the plan are not cancelled by deactivation — they keep billing — but the plan is gone as a target for *new* subscribe orders.

**Phase 2 — in PeakCommerce, nothing changes yet (the dangerous window).** PeakCommerce sells from its own synced copy of your catalog, and that copy only updates when a **catalog sync** runs — a manual re-sync, or the automatic drift watcher, which by default checks once a day (3:00 AM server time) and re-syncs when it detects a difference. Until a sync runs:

* The plan still shows as active and **fully sellable** in PeakCommerce.
* Product sets keep offering it; storefront and journey pickers render it as a normal, selectable card.
* A new customer can select it, complete signup, enter payment details — and the order **fails at the final commit step**, when PeakCommerce submits it to Zuora and Zuora rejects the deactivated plan. The customer has done all the work and gets an error at the finish line. Every one of these failures is recorded in **API Call Stats** and the journey's session log, but the customer is already lost.

If the plan was part of a **bundle**, the same applies to the bundle: the member referencing the dead plan flows into the order and the whole order fails at Zuora.

**Phase 3 — after a catalog sync, degraded but honest.** Once a sync runs, the local plan is marked inactive, and PeakCommerce fails safe:

* In the product set editor, the item shows as a catalog gap: *"Plan is inactive in the billing system — reactivate it or remove it from the product set."*
* On public storefronts and journey pickers, the card collapses to **"Pricing not available — please contact us"** and can't be selected.
* A journey link that prefills the dead plan (a `?p=` URL) is rejected **at journey start** with a clear error, instead of failing at the end.

Phase 3 is safer than Phase 2 — customers can no longer walk into a doomed checkout — but it is still a broken storefront: your acquisition journey is showing an "unavailable" slot (or refusing prefilled links) until you swap in a replacement.

### In-flight checkout sessions: the part a swap can't fix

A journey session **snapshots its plan at the moment it starts**. When a visitor enters an acquisition journey, the selected plan's identifiers are stamped into the session's context, and later steps read those stamped values — they do **not** re-resolve the product set as the visitor moves through the flow.

Two consequences:

* **Fixing the product set only helps&#x20;*****new*****&#x20;sessions.** Product-set edits take effect immediately for every session that starts afterward (no journey republish needed) — but a session that started before your fix still carries the old plan and will fail at the commit step when Zuora rejects it.
* **The exposure tail is long.** Idle sessions live for up to 30 days before they're expired, so a visitor can resume an old session days later and still hit the failure. There is no mechanism that re-points an existing session at a replacement plan.

This is why the ordering below keeps the old plan **alive in Zuora** until after the product set stops offering it: sessions started before the swap can then still convert, and the failure tail never happens.

### Existing subscriptions on the deactivated plan

* **Billing continues.** Deactivating a rate plan in Zuora does not cancel or alter subscriptions that already contain it.
* **Portal display.** The customer's current plan stays visible in their portal (a customer's own plan is always shown), but once the local catalog marks the plan inactive, its card inside a change-plan picker can render as unavailable rather than as a normal plan card.
* **Changes to those subscriptions.** Amendments that touch the deactivated plan — plan swaps away from it, quantity changes, cancellations that reference it — are governed by Zuora's own rules for deactivated plans. If Zuora rejects such a change, PeakCommerce surfaces the rejection to the operator and records it in API Call Stats. Test a change against one affected subscription before assuming the fleet is fine.

### Retention offers pinned to the plan

If a retention **offer** pins its discount instrument to a rate plan you deactivate, the offer's editor and detail page will show a conformance warning ("pinned rate plan is inactive in the synced catalog") — but conformance warnings **never block**, and the apply itself is only checked at accept time. A cancelling customer who accepts the offer would then hit a billing-system rejection at the worst possible moment. When you retire a plan, check **Commerce → Offers** for any offer pinned to it and re-pin to the replacement.

### The safe swap: retire a rate plan without customers noticing

Follow this order. The principle: **the new plan must be fully sellable before the old one stops being offered, and the old plan must stop being offered before Zuora stops accepting it.**

1. **Create the replacement rate plan in Zuora.** Leave the old plan active.
2. **Sync the catalog** — Settings → Catalog Sync (use "Re-sync now" rather than waiting for the nightly drift watcher). Confirm in **Catalog Sync History** that the run succeeded and the new plan arrived.
3. **Add the replacement to the product set** (Commerce → Product Sets) — and to any **bundle** whose member referenced the old plan. Because product sets resolve live, every *new* checkout session sees the replacement immediately; no journey republish is required.
4. **Verify end-to-end.** Run a real checkout on the replacement plan in your sandbox (or a test order in production): the picker shows it, prefill links resolve, and the order commits cleanly.
5. **Remove the old item from the product set.** New sessions stop offering the old plan from this moment. Update any marketing/prefill URLs (`?p=`) that pointed at it, and re-pin any retention offers.
6. **Wait out the in-flight tail.** Sessions that started before step 5 still carry the old plan. Keep the old plan active in Zuora long enough for those sessions to finish naturally — a few days covers the overwhelming majority; the absolute ceiling is the 30-day session lifetime. (If you can see from your session activity that nothing in-flight references the old plan, you can shorten this.)
7. **Deactivate the old rate plan in Zuora**, then **re-sync the catalog** once more so PeakCommerce marks it inactive locally. Any residual reference now renders as a clean "unavailable" state instead of a failing checkout.

### If it already happened: recovery runbook

Someone deactivated the plan in Zuora first, and checkouts are failing now. Restore service in this order — it takes minutes:

1. **Confirm the failure.** API Call Stats shows failed Zuora order submissions; the journey's session log shows `create_order` failures naming the rejected plan.
2. **Fastest fix, if acceptable: reactivate the plan in Zuora.** This immediately restores checkout for everyone — including in-flight sessions — and buys you time to do the coordinated swap above.
3. **Otherwise, swap forward:** create/identify the replacement plan in Zuora → **re-sync the catalog** → **add the replacement to the product set** → **remove the old item**. New checkout sessions convert from that moment.
4. **Accept the in-flight losses knowingly.** Sessions that started before your fix will still fail at commit (their plan is stamped). If the old plan can be temporarily reactivated in Zuora, those sessions can still convert; if not, they can't be rescued.
5. **Reconcile afterward:** check Catalog Drift / Sync History for the deactivation event, review API Call Stats for the failure window, and audit retention offers and prefill URLs that referenced the old plan.

### Where to watch

* **Settings → Catalog Drift** — drift events show exactly which products/plans diverged and what an auto re-sync deactivated.
* **Settings → Catalog Sync History** — every sync run, its status, and net changes.
* **API Call Stats** — failed Zuora order submissions during an incident window.
* **The journey's session view** — per-session commerce-action failures, including the billing system's rejection message.

### FAQ

**Do I need to republish the journey after changing the product set?** No. Product sets are resolved live when each new session starts — set membership changes apply to new checkouts immediately. (Republishing is only needed for changes to the journey's own configuration.)

**Will fixing the product set rescue customers already mid-checkout?** No. A session's plan is stamped at session start and never re-resolved. Sessions started before the fix will fail at commit unless the old plan is still (or again) active in Zuora.

**Does deactivating a plan in Zuora affect customers already subscribed to it?** Their billing continues unchanged. The risks are around *changes*: change-plan flows and amendments touching the dead plan are subject to Zuora's rules, and the plan's card may show as unavailable inside pickers.

**Why did checkout keep offering the plan after we deactivated it?** PeakCommerce sells from its synced catalog copy. Until a catalog sync runs (manual, or the nightly drift watcher), the local copy still lists the plan as active and sellable. That sync-lag window is precisely why the safe order is "product set first, Zuora last."

**What about a plan that's part of a bundle?** Same rules, one more step: the bundle's member list references plans, so swap the member in the bundle definition as well as the base product set, and verify the bundle checkout end-to-end before deactivating anything.

### Related

* [Catalog Drift](https://gitlab.com/peak-hercules/peak-help-docs/-/tree/main/product/settings/billing-catalog/catalog-drift.md)
* [Catalog Sync History](https://gitlab.com/peak-hercules/peak-help-docs/-/tree/main/product/settings/billing-catalog/catalog-sync-history.md)
* [Product Sets](https://gitlab.com/peak-hercules/peak-help-docs/-/tree/main/product/using-peakcommerce/products-and-bundles/product-sets.md)
* [Offers & Discounts](https://gitlab.com/peak-hercules/peak-help-docs/-/tree/main/product/using-peakcommerce/products-and-bundles/offers-and-discounts.md)
* [Zuora Billing Integration](https://gitlab.com/peak-hercules/peak-help-docs/-/tree/main/integrations/zuora-integration/zuora-billing-integration.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.peakcommerce.com/guides/administration-guides/guide-deactivating-a-zuora-rate-plan-safely.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
