> 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/feature-guides/retain-and-manage/guide-csr-assisted-change-plan.md).

# Building a CSR-Assisted Change-Plan Flow

### Overview

Sometimes the customer doesn't want to self-serve — they call, they email, they ask a human to "just move me to the bigger plan." A **CSR-assisted change-plan flow** lets a customer-service rep run that upgrade, downgrade, or add-on change **on the customer's behalf**, with the *same* governed rules a self-service change would follow: the timing and proration your business mandates, and only the discount your policy allows.

This guide builds the CSR side of plan changes and shows how business rules and policy keep a human-run change as safe as an automated one.

### The example we'll build

**Atlas, a B2B software company,** wants its support team to handle plan changes without giving reps free rein on pricing. A customer asks to upgrade to Enterprise; the rep opens the account, runs the change-plan flow, applies an approved 10% loyalty discount (the most policy allows), and the upgrade takes effect immediately with proration — all recorded against the rep, not the customer.

### Before you begin

* **Business rules** that govern change-plan behavior (under **Rules & Automation → Business Rules**) — at minimum, how upgrades and downgrades are timed and prorated.
* **Concession bands** configured if reps will apply a discount (section 5 below) — so the amount is defined by policy, not typed in freehand.
* Reps with a **role and profile** that grants the change-plan permission and scopes them to the accounts they're allowed to touch.

### 1. Create the CSR change-plan journey

1. Go to **Content → Journeys** and click **+ New Journey**.
2. Set **Type** to **CSR Self-Service** — this is the rep-facing variant, so an agent drives the flow on the customer's behalf (the customer-facing version is a **Customer Self-Service** journey).
3. Build a change flow that loads the customer's **existing** subscription and lets the rep adjust it:

   **Find/confirm account → Choose new plan / add-ons → Review (timing, proration, discount) → Confirm**

   These flows **amend the live subscription** (a true upgrade/downgrade), not create a duplicate order — so an `update_order` action applies the change to the existing subscription.

### 2. Give the rep a live order summary while they work

On the plan-selection steps, place the **order summary rail** beside the plan picker. It's the rep's running receipt, updating live as they click, and it's structured as a before → after story:

* **Products they have now** — the customer's current base plan and add-ons with today's prices, totalled as **Current monthly**. Read-only: a clean snapshot of the current bill.
* **Products they'll have** — the resulting set after the rep's selections. New items carry a **New** pill; anything whose price moved carries a **per-line delta pill** (+/− amount), and each changed line has a **remove** control (with **Undo** on removals of currently-attached add-ons), so the change stays reversible line by line. The zone totals to **New monthly**. Percentage-priced add-ons reprice automatically against the *new* base — move the base and every percentage add-on moves with it.
* **Due today** — the prorated amount owed right now, pulled from a **real billing-system preview**, never estimated from the full monthly price. Until the preview returns, the rail says "Calculating…" rather than showing a number that could be wrong — and if live pricing can't be reached, it says so and confirms the exact amount before anything is applied.

A **timing banner** across the top of the rail states the change's direction and consequence in one line: an upgrade reads *"Upgrade — effective today · prorated for this cycle"*, a downgrade reads *"Downgrade — starts \<next period / end of term> · nothing due today."* No rep has to explain proration from memory — the rail already did.

**Free trials anchor to $0.** If the customer is mid-trial, **Due today shows $0** and the rail notes that the new monthly price starts when the trial ends — so a trial-period plan change never looks like an immediate charge.

### 3. The Summary & Billing Preview step

The final review step (the **CSR Billing Preview** component, titled **Summary & Billing Preview** by default) presents the whole change for sign-off before commit:

* **Before → after zones** side by side — *Products they have now* vs. *Products they'll have* — with the same per-line **delta pills**, **New** badges, and struck-through removals as the rail, so the review step reads identically to what the rep just built.
* A full-width **Net monthly change** row: the single number for "what does this do to their bill."
* A **live billing-system quote** breaking down the prorated charge for the days left in the cycle, any proration credit, and tax — feeding a prominent **Due today** total. On a downgrade it plainly states nothing is charged today and when the new price starts.
* The **Confirm** button, with the resolved effective date shown right beneath it.

> **Builder note — wire the commit actions, or Confirm commits nothing.** The Confirm button itself only *advances the journey* to the next step. The plan change is committed by the **commerce actions on the Summary step** — `record_order` + `update_order` — which fire when the journey advances, reading the rep's selections from the journey context. If those actions aren't configured on the step, confirming will sail through to the thank-you screen **without changing the subscription**. Configure both actions on the Summary step and, if an action fails, the failure surfaces on the Confirm button — it is never silently skipped.

### 4. Let business rules decide timing and proration

The rep shouldn't have to remember "upgrades are immediate, downgrades wait until end of term" — your **business rules** enforce it:

* A rule's **Direction** (upgrade vs. downgrade), **Change timing** (Immediate, End of term, or a Specific offset), and **Proration** decide *when* and *how* the change applies.
* **Scope** narrows which products, plans, and audiences a rule covers, and **Priority** breaks ties (first matching rule wins).
* Add-on handling (**Dependency behavior**, **Co-term to base**) keeps add-ons aligned with the base term.

So when the rep moves Atlas's customer to Enterprise, the matching **upgrade** rule applies it immediately with proration — automatically, the same as a self-service upgrade would. When a rule locks the timing (say, downgrades to end-of-term), the order summary explains **why** and shows the resolved effective date, with a link straight to the matching rule in **Business Rules** — so a rep who's asked "can't you just do it now?" can answer with the policy, not a shrug.

### 5. Keep discounts within policy — concessions

This is the heart of "assisted, not unlimited." A rep can *offer* a discount, but not invent one — and the mechanism is **concessions**: a per-journey discount policy that decides what a rep can grant, records every grant, and books each one to the right revenue bucket.

**Enable it on the journey.** In the journey editor, the change-plan journey's step editor has a **Concessions** tab with a master toggle. Concessions are journey configuration on purpose: the journey already carries its audience, so the bands you offer *are* the authority model for the reps who run it.

**Bands map discount depth to accounting.** A band is a value range (say, 0–10%) tied to a **GL bucket label** and pinned to a specific **catalog discount instrument** — the actual discount product in your billing catalog that carries the grant. Bands and reasons are workspace-level shared objects: attaching a band to a journey never copies it, so the same discount depth always posts to the same GL bucket everywhere it's offered. Bands must not overlap — exactly one instrument must resolve for any value, and an overlap is flagged as a configuration error rather than resolved by guessing. A band whose pinned instrument has drifted out of the catalog is plainly marked un-offerable until it's re-pinned.

**Reasons, durations, ceiling.** The tab also configures a **shared reason vocabulary** (every grant carries a reason code; some reasons can require a written note), the **duration presets** reps can pick (e.g. 1 / 3 / 6 periods, optionally a custom duration), and the **self-serve ceiling** — the maximum discount, as a percentage, this journey's reps can grant.

**The rep's composer.** Reps meet all of this as a staff-only zone in the **order-summary rail**: quick-pick value chips derived from the bands (clamped to the ceiling, so a chip can never offer an unusable value), the reason and duration menus, and an **authority meter** showing where the draft sits against the ceiling. The composer renders *only* from the journey's resolved configuration — it never invents an option, so a rep can only compose something the journey actually permits.

**Advisory in the UI, authoritative on the server.** The meter and the disabled Apply button exist so the rep understands *why* a value is refused before trying it — but the server re-decides everything at preview and again at commit, regardless of what the client sent. Fixed-amount bands are measured against the **same percentage ceiling** by converting the amount to its equivalent percentage of the base charge; when the base can't be determined, the server **refuses the grant** rather than assuming it's within authority.

**Guardrails against stacking.** One concession may be active on a subscription at a time, and a **re-offer window (15 days)** blocks a fresh grant on a subscription that just received one. Both checks are re-run against a live read at commit time — another rep, or an automated retention flow, may have granted something in between.

**Every grant is recorded and travels downstream.** Grants land in a **usage ledger** (a failure after the billing call is recorded as a failed ledger row and surfaced — never swallowed to keep the journey looking clean), and the applied concession is published into **journey context variables** — `{{concession.reasonCode}}`, `{{concession.glLabel}}`, `{{concession.value}}`, `{{concession.totalValueCents}}`, and more — so downstream commerce actions can forward it to your CRM, ERP, or warehouse through the existing field-mapping surface, with no new plumbing.

**Honest limits, v1.** Concessions are currently **self-serve only**: a band marked as requiring approval is not offerable yet (the approval workflow is a later phase), so over the ceiling simply cannot be applied — there is no "request approval" path. And note the older **offers-engine** path still exists and still powers **retention offers** in cancellation/save flows; concessions govern the rep-composed discount in change-plan work.

### 6. Split who can change versus who can cancel

Changing a plan and cancelling one are different powers, and you can grant them separately:

* The **change-plan** permission lets a rep upgrade/downgrade/add-on; a separate **cancel-plan** permission controls who can end a subscription.
* Give your front-line reps change-plan, and reserve cancel for a senior tier — set both on the rep's **profile**.

### 7. Branch for downgrades and saves

A rep-run downgrade is a churn signal too — handle it like one:

* On a **downgrade**, branch to a **retention** offer (a discount or a better-fit plan) before the downgrade commits — the same branching that powers a self-service retention flow (see [Building a Multi-Branch Retention Journey](/guides/feature-guides/retain-and-manage/guide-building-a-multi-branch-retention-journey.md)).
* On an **upgrade**, you might branch to suggest a complementary add-on.

### 8. Keep the change attributable

Because a rep is acting *for* the customer, attribution matters for audit:

* Changes a rep makes are recorded against the **rep**, and when a rep works inside a customer's context, the action is attributed to the operator (not silently logged as the customer).
* Review rep activity in the **audit log** (user menu, bottom-left → **Settings → Audit Logs**).

### Get creative

* **Approval ladder.** For discounts above the standard cap, branch to a "needs supervisor approval" step rather than blocking the rep outright.
* **Guided save scripts.** On a downgrade or cancel, surface the retention offers as on-screen prompts so reps say the right thing.
* **One flow, two front doors.** Build the customer self-service change and the CSR-assisted change as parallel journeys sharing the same rules, so both audiences get identical, governed behavior.

### Tips

* **Use CSR Self-Service, not Customer Self-Service.** The journey type sets the audience — pick the rep-facing variant or you'll expose the flow to the wrong people.
* **Wire the commit actions on the Summary step.** Confirm only advances the journey; the `record_order` + `update_order` commerce actions on that step do the committing. No actions, no change — the most common "it said confirmed but nothing happened" mistake.
* **Let rules and policy do the governing.** Don't hard-code timing or discounts into the journey; business rules set timing/proration, and the journey's concession bands and ceiling cap discounts.
* **Trust the rail's Due today, not mental math.** It's the billing system's prorated figure. If it reads "Calculating…", the preview hasn't returned yet — it will never quietly substitute the full monthly price for a prorated one.
* **Split change from cancel.** Grant the two permissions separately so front-line reps can adjust plans without being able to cancel them.

### FAQ

**How is this different from the customer self-service change flow?**

Only the **journey type**: **CSR Self-Service** is rep-driven (the agent acts on the customer's behalf), **Customer Self-Service** is customer-driven. They can share the same business rules and discount policy, so behavior is identical — just a different front door.

**Can a rep give any discount they want?**

No. The rep's composer offers only the **concession bands, reasons, and durations** the journey's configuration permits, and the **self-serve ceiling** is enforced by the server at preview and commit — a value over the ceiling, or outside every configured band, simply cannot be applied, no matter what the client sends. On top of that, only one concession can be active on a subscription at a time, and a re-offer window blocks a repeat grant on a subscription that just received one. Every grant is ledgered with its reason and GL bucket.

**Who can cancel versus change?**

Those are separate permissions. Grant **change-plan** to front-line reps and reserve **cancel-plan** for a senior tier via the rep's profile.

**The rep confirmed the change but the subscription didn't update. Why?**

Almost always: the Summary step is missing its commerce actions. The Confirm button only advances the journey — the commit is performed by the `record_order` + `update_order` actions configured on that step. Add them and re-test. (A genuine commit failure, by contrast, shows an error at the Confirm button rather than advancing.)

**Why does Due today show $0 on an upgrade?**

Two legitimate reasons: the customer is in a **free trial** (nothing is charged until the trial ends — the rail says so), or the change resolved as a **downgrade/end-of-term change**, which bills nothing today by design. An upgrade outside a trial shows the prorated amount from the billing preview.


---

# 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/feature-guides/retain-and-manage/guide-csr-assisted-change-plan.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.
