Skip to content

For Shopify agencies

Shopify B2B technical debt: the decisions that get expensive later

By Jahangir Alam · September 24, 2026 · 13 min read

Last verified
Shopify API
2026-07
Audience
Shopify agencies and developers scoping, auditing or inheriting a B2B build
Scope
Structural decisions that are hard to reverse (store type, company tree, where prices live, identity keys, deal state, Plus dependencies), surfaces with a Shopify retirement date (checkout.liquid, Scripts, legacy customer accounts, API versions) at API 2026-07, server-side enforcement, and a handover ledger

Technical debt in a Shopify B2B build comes in two kinds, and they need different handling. The first is structural: decisions Shopify itself says are hard to reverse - a blended or a dedicated B2B store, how buyers are split into companies and locations, where standing prices live, which identity keys join Shopify to the ERP. The second has a due date: code built on a surface Shopify retires on a published schedule - checkout.liquid (13 August 2024 and 28 August 2025), Shopify Scripts (deactivated 30 June 2026), legacy customer accounts (deprecated 26 February 2026) and every API version, each supported for at least 12 months.

Structural debt is paid by deciding before any data exists. Dated debt is paid by writing the dates down and giving someone the job of watching them. Both are documented by Shopify before the build starts; what makes them expensive is finding them after it ends.

This page is for the agency scoping or inheriting a build: the decisions that get expensive later and why, the dated surfaces in one calendar, where rule enforcement has to live, the seven ways a build goes wrong, and the debt ledger to hand over with the project. Where it describes a quote layer, that is one implementation, labelled as such.

Everything about Shopify below was checked against Shopify's own pages on 24 September 2026 at API version 2026-07, unless another date is given; sources are at the end.

Two kinds of debt

Aspect Structural debt Dated debt
What it is A modelling decision that everything else attaches to Code on a surface Shopify has announced it will retire
Examples Store type, company tree, where prices live, identity keys, where deal state lives, Plus dependencies checkout.liquid, Shopify Scripts, legacy customer accounts, API versions and deprecated fields
When it is cheap Before the first company, catalog or order exists Before the date - Shopify publishes it months ahead
What makes it expensive Data attaches to it: orders, catalogs, terms, history The date passes and the code stops running, sometimes silently
How to pay it down Decide deliberately, write the reason down A ledger of surfaces with their dates and an owner for each

The two feed each other. A store that kept wholesale prices in Shopify Scripts carried dated debt (Scripts ended on 30 June 2026) on top of structural debt (the prices were never in a catalog), and paying the first meant paying the second.

The decisions that get expensive later

Six decisions, each with the Shopify constraint that makes it hard to change. Decide them in this order, before the first company exists.

1. Blended or dedicated store. Shopify's own guidance is blunt: "You need to make this decision carefully, as it's not easy to change at a later time. If you set up one type of store and then want to switch to the other type, then you'll need to redo most of your setup work, including companies, catalogs, and online store customizations." A dedicated B2B store is a separate store: "inventory is separate for B2B orders and customers by default", its apps must be "set up and paid for again", and between expansion stores "store settings, products, collections, and inventory aren't synced" - that is a job for an app or the ERP. On a Plus organisation, the expansion-store rules include one free B2B store per contract. None of that is wrong; it is a choice with a running cost, and it should be made because the business needs a separate storefront, not because that is how wholesale used to be run.

2. The company tree. What is one company, and what is a location? Catalogs, payment terms, tax exemptions and ship-to all attach to the location, and history is unforgiving: "B2B orders remain with the company they were created for and can't be migrated to another company", and one customer's migrated orders cannot be split across locations. A tree modelled one-to-one on an old system's customer list, without deciding which records are organisations and which are branches, cannot be corrected by re-migrating orders - it is fixed by rebuilding the tree. The migration playbook sets out the order of work that avoids it.

3. Where standing prices live. Since 2 April 2026 companies, catalogs and payment terms are on every Shopify plan, so the reasons to keep wholesale prices in customer tags, discount codes or duplicate "wholesale" products are gone. Each of those workarounds carries its own maintenance: duplicate products are separate inventory and reporting records by construction, and tag logic lives in the theme or an app rather than in what checkout reads. Catalogs are what B2B checkout, quantity rules and volume pricing read. Design the catalog count up front: off Plus, the cap is three active catalogs across all B2B markets combined, so a plan that assumes one catalog per customer is a Plus plan. Wholesale and retail pricing without duplicate SKUs covers the pricing side, and the catalog rows of the reference the precedence rules.

4. Identity keys. Company.externalId and CompanyLocation.externalId exist for one purpose: a "unique externally-supplied ID" that joins Shopify's records to the ERP's customer and ship-to numbers, and the companies query filters on it. Set on day one it costs nothing. Added a year later it means matching thousands of records by name, and every sync built in between keyed on something else. ERP, CRM and PIM integration patterns sets out who owns which field.

5. Where deal state lives. A draft order is an agreed order awaiting payment or approval: three statuses (OPEN, INVOICE_SENT, COMPLETED), no versions, and draftOrderUpdate replaces the input wholesale. Drafts created on or after 1 April 2025 are deleted after a year without an edit. A build that keeps negotiation in draft orders - the request, the counter, the history of who offered what - is storing it somewhere that can neither hold it nor keep it. A Shopify draft order is not a quote sets the draft's states against the ones a negotiation needs.

6. Plus dependencies. Some B2B features are on Shopify Plus: direct catalog assignment to a company or location, unlimited active catalogs, deposits, partial payments, a payment request per fulfilment, and - easily missed - custom apps that contain Shopify Function APIs, which Shopify documents as usable only on Plus stores (public App Store apps with functions run on any plan). None of these is a mistake. Each one ties the build to the plan, and the merchant should know that before they depend on it. Do you need Shopify Plus for B2B? has the plan line by line.

Debt with a due date

Shopify publishes retirement dates months ahead. The debt is not the old surface; it is not knowing the build uses it.

Shopify B2B debt calendar, August 2024 to October 2026 A timeline of dated Shopify changes that turn existing code into debt. 13 August 2024: checkout.liquid stops working for the Information, Shipping and Payment steps. 1 October 2024: the REST Admin API becomes legacy. 1 April 2025: new public apps must be built on the GraphQL Admin API. 28 August 2025: checkout.liquid and additional scripts are sunset for the Thank you and Order status pages on Plus, and the additional scripts box becomes view-only. 26 February 2026: legacy customer accounts are deprecated; they never supported B2B. 2 April 2026: B2B arrives on every plan, which makes tag-based wholesale a choice rather than a necessity. 15 April 2026: Shopify Scripts can no longer be edited or published. 30 June 2026: Shopify Scripts is deprecated and published scripts are deactivated. 1 July 2026: API 2026-07 deprecates DraftOrderInput.customerId in favour of purchasingEntity and removes the grams field. 26 August 2026: the deadline for non-Plus stores to upgrade the Thank you and Order status pages. 1 October 2026: API 2026-10 becomes stable, and each version is supported for at least 12 months. 2024 2025 2026 13 Aug 2024 checkout.liquid off for Information, Shipping, Payment 1 Oct 2024 REST Admin API legacy 1 Apr 2025 new public apps GraphQL only 28 Aug 2025 checkout.liquid + additional scripts sunset on Thank you / Order status (Plus) 26 Feb 2026 legacy customer accounts deprecated 2 Apr 2026 B2B on every plan 15 Apr 2026 Scripts editing ends 30 Jun 2026 Scripts deactivated 1 Jul 2026 - API 2026-07 DraftOrderInput.customerId deprecated, grams removed 26 Aug 2026 non-Plus Thank you / Order status deadline 1 Oct 2026 - API 2026-10 each version: 12 months or more
Orange: a surface stopped working or was deprecated. Blue: an API rule changed. Teal: a platform change that turned a workaround into a choice.
Surface Date What happened What replaces it
checkout.liquid, in-checkout steps 13 Aug 2024 Stopped working for Information, Shipping and Payment Checkout extensibility
checkout.liquid and additional scripts, Thank you and Order status (Plus) 28 Aug 2025 Sunset; the additional scripts box became view-only Extensions in checkout, blocks, web and app pixels
Thank you and Order status pages (non-Plus) 26 Aug 2026 Upgrade deadline The same
REST Admin API 1 Oct 2024 legacy; 1 Apr 2025 for new public apps New public apps must be GraphQL-only GraphQL Admin API
Legacy customer accounts Deprecated 26 Feb 2026; sunset date to be announced No new stores, no updates; never supported B2B Customer accounts and their UI extensions
Shopify Scripts Editing ended 15 Apr 2026; deactivated 30 Jun 2026 Published scripts "no longer work" Shopify Functions
DraftOrderInput.customerId, marketRegionCountryCode Deprecated at 2026-07 Still accepted, on the removal path purchasingEntity (a customer or a purchasing company)
DraftOrderLineItem.grams Removed at 2026-07 Gone weight
Every API version Quarterly; each supported 12 months or more An unsupported version "falls forward" to the oldest accessible stable version, silently Upgrade every quarter or at least once a year

Two rows deserve a second look for B2B specifically. checkout.liquid never worked for B2B checkout - Shopify lists checkout.liquid customisations among the things B2B does not support - so a B2B store never had that debt, but a blended store's D2C checkout might, and the fix touches both. And the API version row is the one that bites quietly. A custom app that names a version Shopify has stopped supporting does not fail: Shopify answers with the oldest version it still supports, and a field that was deprecated in between can simply stop being there. A public app on the App Store has a harder deadline: "If your app continues to use unsupported resources after the upgrade deadline, it's delisted from the Shopify App Store", with new installs blocked for at least seven days.

The Scripts row is the clearest recent example of both kinds of debt arriving at once. A store whose wholesale discounts or B2B shipping rules lived in Scripts had until 30 June 2026 to move them; the move to Functions is also the moment to ask whether those prices belong in a catalog instead, which is structural. Note the Functions plan rule when you scope it: a custom app with functions runs only on Plus, so a non-Plus merchant replacing Scripts is choosing between a public app and native features. The draft-order limits post covers the one documented draft-order caveat for discount functions.

Enforcement belongs on the server

The quietest form of debt is a rule that looks enforced and is not. Theme code runs in the buyer's browser; it can show or hide a button, but a determined buyer, a cached page or a second storefront does not run it. The rule that matters for money has to live where Shopify checks it.

Shopify gives you three server-side places. Catalogs decide the price a signed-in company location sees. Quantity rules - minimum, maximum and increment per variant - are enforced at cart and checkout, not only displayed. And the cart and checkout validation Function API runs server-side checks "to ensure that orders meet specific criteria before allowing customers to proceed", on B2B checkout and on draft orders in the admin and at checkout, with the buyer's purchasingCompany available to the function; a store can activate up to 25.

Know the two places it does not reach: the validation API does not run on the Create Order API or on order editing. An integration that writes orders directly through orderCreate - an ERP import, a migration script - bypasses the rules a buyer is held to, so those rules need to be enforced in the integration too. That is a design note for the statement of work, not a defect.

Seven ways a B2B build goes wrong

Each of these is a pattern traced to a constraint on this page, not a measured frequency - nobody publishes those, and we do not claim an order. Each is one of the decisions above, made late or by default.

  1. The store type was chosen for launch speed. A dedicated store because that is how wholesale used to be run, then inventory sync, double app billing and split reporting for as long as the store exists. Shopify says switching means redoing companies, catalogs and customisations.
  2. The company tree copied the old customer list. Branches became companies, or organisations became locations, and orders cannot move between companies to fix it.
  3. Prices stayed in tags after catalogs arrived. The workaround outlived its reason (B2B on every plan since 2 April 2026) and now needs its own maintenance, beside a catalog system that checkout already reads.
  4. Nobody set externalId. The ERP sync keys on names or emails, and every duplicate becomes a support ticket.
  5. Negotiation lived in draft orders. No versions, no counter, update replaces the whole input, and an idle draft is deleted after a year.
  6. Checkout logic sat on a retiring surface. Scripts, checkout.liquid or additional scripts, with the date known and not tracked.
  7. No one owned the API upgrade. A custom app pinned to a version that later fell forward, and a field it read was no longer there.

None of these is a Shopify bug. Each is a constraint that was documented before the build and discovered after it.

The debt ledger to hand over

The cheapest repayment is a page in the handover document that states each decision and its reason. It costs an hour at the end of a build and saves the next team from rediscovering it.

  • Store type - blended or dedicated, and the business reason. If dedicated: what syncs between stores, and by what.
  • Company tree rule - what one company is, what one location is, and who agreed it on the merchant's side.
  • Where each price lives - catalogs (which ones, and the active count against the plan's cap), quantity rules, volume breaks, anything still in tags or discounts and why.
  • Identity keys - the externalId scheme for companies and locations, and the source-system field each maps to.
  • Where deal state lives - which system owns requests, proposals, counters and approvals, and what it hands Shopify.
  • Plus dependencies - every feature in the build that exists only on Plus, so a plan change is a known cost.
  • Surfaces with a Shopify date - any extension, function, script, theme block or API the build relies on that has an announced deprecation, with the date.
  • API version - the version each custom app pins, the date that version leaves support, and the named owner of the quarterly upgrade.
  • Enforcement map - which rules are enforced by catalogs, quantity rules or validation functions, and which only in the theme.
  • Integrations that bypass checkout - anything writing orders through orderCreate, and where it re-applies the buyer rules.

The 50-test launch plan is the companion: the ledger records what was decided, the test plan proves it works.

Where a quote layer sits

Labelled as one implementation. A quote app adds a system of record for the deal, so it can add debt of its own. The question that decides how much is what it stores: references to Shopify's records, or copies of them. A copied customer list or price list is a second source of truth that someone has to keep in sync; a reference is read from Shopify when needed.

QuotWay stores references: a quote holds the Shopify IDs of the customer, company, location, contact, product and variant, a snapshot of the product titles on each version, and the prices that were negotiated - the catalog baseline, the buyer's ask, the offer and the final price. It keeps no standing price list; a company contact's proposal starts from their company-location catalog price, resolved when the request comes in. Negotiation state stays in the quote - versions, counters, approvals, and sent proposals whose lines are locked, so a change is a new version or a counter rather than an edit. Only the agreed result becomes a draft order, created with purchasingEntity rather than the deprecated customerId and, on the Enterprise plan, the location's payment terms. Company-aware quoting is on the Enterprise plan - the plan lines are on the pricing page - and the company-aware side is on the Shopify B2B quoting feature page; the architecture behind the split is in what lives in Shopify and what belongs in the quote layer.

Whichever app you evaluate, ask the storage question directly; how to evaluate a Shopify B2B app lists it with the other 52.

The Shopify facts in this post are kept current in the Shopify B2B reference.

FAQ

What is technical debt in a Shopify B2B build?

Two things. Structural decisions that Shopify says are hard to reverse - blended or dedicated store, the company tree, where standing prices live, identity keys - and code on a surface with a published retirement date, such as checkout.liquid, Shopify Scripts, legacy customer accounts and API versions. The first is paid by deciding early; the second by tracking the dates.

Can I switch from a separate wholesale store to one blended store later?

Yes, but it is a rebuild rather than a setting. Shopify's store-type guidance says the choice is "not easy to change at a later time" and that switching means redoing "most of your setup work, including companies, catalogs, and online store customizations". Expansion stores do not sync settings, products, collections or inventory between them.

Do Shopify Scripts still work for B2B pricing?

No. Shopify Scripts was deprecated on 30 June 2026 and published scripts were deactivated; editing had already ended on 15 April 2026. The replacement is Shopify Functions. A custom app containing functions runs only on Plus stores; public App Store apps with functions run on any plan.

Does the checkout.liquid deprecation affect B2B?

Not B2B checkout itself, which never supported checkout.liquid customisations. It affects a blended store's D2C checkout: checkout.liquid stopped working for the Information, Shipping and Payment steps on 13 August 2024, and for the Thank you and Order status pages on 28 August 2025 on Plus. Non-Plus stores had until 26 August 2026 to upgrade those two pages.

What happens if a custom app uses an old API version?

Nothing visible at first. Each stable version is supported for at least 12 months; after that, a request naming it "falls forward" to the oldest accessible stable version, so fields removed in between stop being returned. Public apps that keep using unsupported resources are delisted from the App Store, with installs blocked for at least seven days. Pin a version and give someone the quarterly upgrade.

Is tag-based wholesale pricing technical debt now?

It is a workaround whose original reason has gone. Since 2 April 2026 companies and catalogs are on every Shopify plan, and catalogs are what B2B checkout, quantity rules and volume pricing read. A tag-based setup still works, but it is extra logic to maintain beside a native system - move it when you next touch pricing, and plan the catalog count against the three-active-catalog cap below Plus.

Can a B2B order be moved to a different company?

No. Shopify states that B2B orders "remain with the company they were created for and can't be migrated to another company". That is why the company tree is the decision to get right before any orders exist.

Sources

Shopify pages, read on 24 September 2026 at API version 2026-07 unless dated otherwise:

QuotWay's storage model is described from its own data schema.

Related articles

See how QuotWay handles this on your store.

We’d like to set analytics cookies to understand how the site is used. They’re not required — declining changes nothing about how the site works, and you can change your mind any time on our privacy page.