Turning the store off without losing it
What the extension toggle really does, why a lapsed licence 403s instead of 404ing, what customers lose, and the safer way to close the store for a maintenance window.
Install and enable covers switching the store on. The reverse comes up for maintenance, for a migration, and — uninvited — when a licence lapses. It is worth knowing before you need it, because the obvious move is not the one that does what you want.
Turning E-commerce off at System → Extension Manager removes the store from the navigation. It does not close the API, does not stop a checkout, and does not pause anything. Meanwhile the thing that does 403 every request — an invalid licence — is not something you choose.
Neither one deletes a row. If your goal is "stop taking orders for two hours", deactivate your products instead.
Two switches, and only one of them refuses requests
| The extension toggle | The licence | |
|---|---|---|
| Where it lives | status on the extension row where name = 'ecommerce' |
lic/44624493.lic on the server's disk |
| Set from | System → Extension Manager (/admin/system/extension) |
The activation screen, /admin/system/license |
| Controls | Menus, and everything that reads "is this addon in use" | The licence gate in front of every store route |
| When it is off | The store disappears from the nav and keeps working | Every store request answers 403 |
They are independent, and they fail in opposite directions. A toggle that is on with no licence serves a menu that 403s. A licence that is valid with the toggle off serves an API nobody can find a link to.
What the toggle writes
The switch calls PUT /api/admin/system/extension/44624493/status with
{"status": false}, on the permission edit.extension. (The bulk form is
POST /api/admin/system/extension/status with ids and status.) Two things
happen:
-
One column changes.
UPDATE extension SET status = 0 WHERE productId = '44624493'. Nothing else in the database is touched. -
The platform cache is cleared, and the clear is broadcast to every worker process, so no restart is needed for the change to be seen. The enabled- extension set is rebuilt from
SELECT * FROM extension WHERE status = true, andecommerceis no longer in it.
From there, the effects are all about who mentions the store:
GET /api/settingspublishes the enabled-extension names, so the platform's user navigation drops the Store entry pointing at/ecommerce.- The admin menu entry for E-commerce is rendered disabled rather than hidden — greyed out, still visible, so you can see it exists.
- Anything else that asks "is this addon in use" — the admin dashboard, the operations summary, the system health check — stops counting the store.
What the toggle does not do
This is the part that surprises people:
- The backend routes stay registered. They are read from the filesystem at
boot, and nothing re-checks them against the enabled set.
/api/ecommerce/*and/api/admin/ecommerce/*keep answering exactly as before. - Restarting does not change that. Boot-time route loading is why enabling a freshly installed extension needs a restart; it is also why disabling one cannot take the routes away, restart or no restart.
/ecommerceis still reachable by anyone who has the URL, has it bookmarked, or follows a link from an old order email. The storefront renders and its data loads.- Checkout still completes. Nothing in the cart or order handlers consults the extension's status.
So a disabled extension is a store you have stopped advertising, not a store you have closed.
The licence gate is the thing that 403s
Every request whose path starts /api/ecommerce or /api/admin/ecommerce is
matched to the ecommerce extension by the licence gate, which runs early in
the middleware chain — ahead of authentication and rate limiting. It checks that
lic/44624493.lic is readable, and caches that answer for five minutes.
When the file is missing or unreadable, the answer is HTTP 403, not 404 and not 503:
{
"message": "This feature requires a valid license for ecommerce. Please activate your license to continue.",
"statusCode": 403,
"licenseRequired": true,
"productId": "44624493",
"productType": "extension",
"productName": "ecommerce"
}Internally the platform labels this condition Extension license required,
which is what you will see referred to elsewhere. Two consequences worth
holding on to:
- 403 reads like a permissions fault. An operator whose licence lapsed
overnight spends the morning in CRM → Roles checking store permissions
that were never wrong. Check
lic/first — thelicenseRequiredflag in the body is the tell. - Admin and customer surfaces behave differently. In the admin panel the
frontend recognises that body and hard-redirects to
/admin/system/license?productId=44624493. On the customer side there is no redirect:/ecommercedraws its shell and every panel on it fails.
If the licence check itself throws — a filesystem blip, a database hiccup — the gate for E-commerce falls through and serves the request. Only the two newest paid addons fail closed. So an intermittent 403 across the whole store is a missing or unreadable file, not a flaky check.
Licensing itself — what a .lic is, why it does not survive a server move, and
the activation routes — is core's subject:
Licences, activation and the extension manager.
What customers lose the moment the licence goes
Everything under /api/ecommerce is behind the same gate, so all of it stops at
once:
/ecommerce— the landing page, the catalogue, categories, search./ecommerce/order— their own order history, including orders they placed and paid for years ago./api/ecommerce/download/{orderItemId}and the file streamer behind it — downloads and licence keys for digital goods they have already paid for.
That last one is the reason a lapsed licence is a support incident and not just
an outage. Nothing is deleted; the key, filePath and instructions are
still sitting on the order item (see
the data model). They are simply unreachable until
the licence is restored, and the customer's read of it is "I paid you and now I
cannot get my file."
What nothing here touches
Whichever switch is off:
- No rows are deleted. Products, categories, orders, order items, discounts, shipments, reviews and wishlists are exactly as they were.
- Wallets and transactions are core's, not the addon's. Every debit, every platform-revenue credit and every shipping-and-tax pass-through stays on the ledger and stays visible in Finance.
- Order statuses do not move. Nothing sweeps
PENDINGtoCANCELLED, and no refund is issued as a side effect of disabling anything. - Attached digital goods stay attached. Re-enabling makes the same download work again with no re-attachment step.
Pending physical orders simply sit there
There is no cron job in this addon — no timeout, no auto-cancel, no
abandoned-order sweep, no reminder. A PENDING order stays PENDING
indefinitely, holding its stock, until an operator moves it.
That is good news for a maintenance window (nothing expires while you are down) and bad news if you leave the store off for a month: the queue you come back to is the queue you left, and every buyer in it has been charged.
Work the queue down before a long shutdown. See Orders and fulfilment.
Affiliate rewards
Rewards under the ECOMMERCE_PURCHASE condition are created after a checkout
transaction commits. No purchase, no reward — so while the store is unreachable,
none are created. Nothing retroactively fills them in when it comes back.
Rewards already earned live in the affiliate addon's own tables. They are not touched, they remain visible to the referrer, and they remain claimable. The conditions themselves stay configured.
A maintenance window that actually stops orders
If the goal is "no new orders for the next two hours, and no customer notices anything worse than an empty shelf", do not use the extension toggle. Deactivate the products instead.
-
Open the catalogue. Admin → E-commerce → Catalog → Products (
/admin/ecommerce/product). -
Select everything and set the status to inactive. This is
edit.ecommerce.product, and it writesstatus = falseon each row. It is a flag, not a delete — no cascade, nothing to restore. -
Confirm the shelf is empty.
/ecommerce/productreturns nothing (the listing filters onstatus: true), and a direct product URL answers 404. -
Do the work.
-
Set the products back to active the same way.
What that buys you, and why it is the right lever:
| Extension toggle off | Products deactivated | |
|---|---|---|
| New orders | Still possible | Refused — checkout answers Product is not available: <name> |
| Storefront | Loads, unlinked from the nav | Loads, with an empty catalogue |
| Existing order history | Visible | Visible |
| Downloads of goods already bought | Work | Work — deliberately not blocked for a deactivated product |
| Admin screens | Menu entry greyed out | Fully usable |
| Reversible by | One toggle | One bulk status change |
The download behaviour is not an accident: the download handler explicitly allows a deactivated product, on the grounds that a customer who paid keeps access regardless of whether you still sell the thing.
A useful narrower version: deactivate one category (status = false) to
take a product line off sale without touching the rest of the catalogue.
Re-enabling
-
Confirm the licence.
/admin/system/extensionshould show E-commerce with a verified badge. If it does not, activate it from the card — Envato username and purchase code, product id44624493. The licence check is cached for five minutes, so give a fresh activation a moment. -
Toggle the extension on. That sets
status = trueand clears the platform cache across every process. -
Restart the platform if the extension's files changed while it was off — an update, a redeploy, a restored tree:
pnpm restartRoutes and models are read at boot. A toggle alone is enough when only the flag moved.
-
Prove both halves answer. Load
/admin/ecommerceas an admin — you want the store dashboard, not a licence redirect — then/ecommerceas a signed-out visitor. The Store entry should be back in the platform nav. -
Reactivate anything you deactivated, products and categories both, and check one product page on the storefront.
-
Walk the order queue. Anything that went
PENDINGbefore the window is stillPENDINGand still waiting.
Two traps
The switch on each card at /admin/system/extension is disabled unless the
licence verifies. So an extension that is switched on and has lost its licence
cannot be switched off from that screen — the control will not move, and
there is no separate error explaining why.
The page names this state directly: a banner lists every product that is
switched on without a verified licence, and each entry links to its own
activation screen. The way out is to restore lic/ or re-enter the purchase
code, not to fight the switch. Fix the licence first; then the toggle works
again.
Extension updates extract over the existing tree and never delete files that were removed upstream. After re-enabling following an update, a build or boot error naming a file that is not in the release is almost always a leftover from an older version rather than a bad download — delete the orphan rather than re-running the update.
When it will not come back
| Symptom | Look at |
|---|---|
/admin/ecommerce redirects to the licence page |
lic/44624493.lic — missing, unreadable, or written on different hardware |
| Store menu entry still absent after toggling on | The settings/extension cache; reload the admin panel, and confirm the row really is status = 1 |
/admin/ecommerce 404s rather than 403s |
The extension's files are not on this server. That is an install problem, not a licence one — see Install and enable |
| Storefront loads but every panel is empty | The API is 403ing. Check the browser network tab for licenseRequired: true |
| Products invisible after re-enabling | They are still status = false from your maintenance window |
Broader failures are on Troubleshooting.