VBWD’s shop plugin adds one-off product sales alongside subscriptions: additive product types, a shared catalogue contract, cart-backed checkout, and invoices with reconciling per-line tax.
Not every product is a subscription; VBWD’s shop plugin adds one-off sales with typed products and correct tax, composed with the same billing engine.
Recurring revenue is not the whole story
Subscriptions are a clean business model until a customer asks for something that does not fit a monthly plan. A one-time setup fee. A physical product. A single report. A course with lifetime access. The moment you say “we only sell subscriptions,” you either turn that revenue away or bolt on a second system to catch it.
VBWD takes a different route. It is a self-hosted, source-available platform (Python/Flask, PostgreSQL, Redis, a Vue 3/TypeScript frontend, all in Docker) built as an agnostic core with everything domain-specific living in plugins. Subscriptions are one plugin. The shop is another. They run side by side on the same users, the same invoices, and the same payment adapters.
What the shop plugin actually adds
The shop plugin handles one-off purchases: products a customer buys once rather than renewing. That sounds obvious, but the design decision underneath it is the interesting part. The core platform knows nothing about “products.” It knows about sellable things, prices, carts, and invoices. The shop plugin supplies the product concept and the catalogue, and it never touches core code to do so.
Practically, that means you can add e-commerce to an existing VBWD install without rewriting anything. Enable the plugin, and you get a product catalogue, a cart-backed checkout, and product line items that land on the same invoices your subscriptions already use.
Product types without touching core
Most shop systems assume every product looks the same: a title, a price, a description, maybe a weight. Real catalogues are messier. A downloadable dataset needs a file reference and a license term. A physical item needs shipping dimensions. A consulting package needs a scope field.
VBWD models this with a ProductTypeRegistry. Each product carries a product_type_slug, and a product type is an additive cluster of custom fields. Registering a new type adds fields to products of that type only, without a schema migration on core and without changing how other product types behave.
# A product type is registered by a plugin, not baked into core
registry.register_product_type(
slug="dataset",
fields=[
Field("download_url", type="string", required=True),
Field("license_term", type="string"),
Field("row_count", type="integer"),
],
)
The payoff is that “add a new kind of thing to sell” becomes a plugin change, not a core change. Your dataset products, your physical goods, and your service packages coexist in one catalogue while each keeps the fields it actually needs.
Catalogue: one filter contract, many plugins
The catalogue list is not special to the shop. VBWD uses an agnostic filter and pagination wire contract that every list-producing plugin shares. Responses come back in the same shape regardless of what is being listed:
{
"items": [ ... ],
"total": 128,
"page": 2,
"per_page": 24,
"pages": 6
}
Filtering, sorting, and pagination are handled by shared core helpers. What stays inside the shop plugin is the policy: which facets exist, how a category filter maps to a query, which fields are searchable. This split matters when you run more than one catalogue-style feature, because the frontend components that render a filter bar and page through results work the same way whether they are showing shop products, a dataset marketplace, or anything else that lists things.
Checkout, tax, and discounts that reconcile
Checkout is cart-backed. A customer adds products to a cart, and the checkout state is derived from that persisted cart rather than from a throwaway in-memory object. Payment itself runs through swappable adapter plugins, so Stripe, PayPal, or YooKassa is a configuration choice, not a rewrite. You can read more about how the money side fits together on the billing page.
Pricing goes through a unified price model. A price is an amount, a currency, and a per-rate tax breakdown, and the value object is never rounded mid-calculation. Rounding only happens at the edges where a number is presented or written to an invoice line. This avoids the classic bug where three line items each round to the nearest cent and the invoice total is off by one.
Discounts are handled with more care than most systems bother with. A discount line carries a negative per-rate tax breakdown, mirroring the tax on what it discounts. When the invoice sums its lines, the tax reconciles exactly instead of leaving a rounding scar between the net discount and the tax owed.
Line: Product A 100.00 (tax 20% -> 20.00)
Line: Product B 50.00 (tax 7% -> 3.50)
Line: Coupon -10% -15.00 (tax breakdown: -2.00 @20%, -0.35 @7%)
------------------------------------------------------
Net + tax per rate stay consistent; the total balances.
Every invoice carries per-line tax, so mixed-rate carts (a 20% physical good next to a 7% digital item) produce a correct, auditable invoice rather than a single blended number that no accountant will accept.
How it composes with subscriptions and billing
Because the shop is a plugin on an agnostic core, it does not own the customer or the invoice. It contributes products and line items to shared machinery. That is what makes composition work.
A typical VBWD install runs a bundle: the subscription plugin for recurring plans, the shop plugin for one-off sales, a discount plugin for promotions, token-payments for credit-style balances, and the invoice plugin tying them together. A single customer can hold an active subscription, buy a one-off product, and redeem a coupon, and all of it lands on invoices that share the same tax and pricing rules.
You are not stitching a store and a billing system together with webhooks and hoping the totals match. They are the same system, drawing on the same price model. The way these pieces layer is described further in the documentation.
Product and landing pages come from the CMS, not from frontend code. A plugin publishes public pages through a layout-and-widget mechanism, so a new product landing page or a full catalogue page ships without editing the Vue router. Marketing can build pages without a frontend deploy.
Honest limits
The shop plugin is not a hosted, click-to-launch store. VBWD is self-hosted, which means you run the Docker stack, manage PostgreSQL and Redis, and handle your own updates. That is the trade for owning your data and paying no platform cut on sales. If you want a managed storefront with a monthly SaaS fee, this is the wrong tool.
The custom-field product types are additive clusters, not a full PIM. Deep merchandising features (complex variant matrices, warehouse-level inventory, multi-location fulfilment) are things you would extend through additional plugins or integrate externally, not built-in expectations.
Licensing is worth reading before you commit. VBWD is source-available under BSL 1.1: free to use, including commercially, until your VBWD-attributable sales cross the 6.7 BTC per year threshold, after which a commercial license applies. The license converts to Apache-2.0 over time. It is not public domain and it is not CC0, so check the terms against your revenue plans on the pricing page.
Takeaway
If you already run subscriptions on VBWD, the shop plugin lets you sell one-off products on the same customers, the same invoices, and the same payment adapters without a second billing system. The design choices that matter are the ones you do not see day to day: product types that extend without core changes, a shared catalogue filter contract, and a price model where tax and discounts reconcile to the cent.
You get recurring and one-off revenue in one place, on infrastructure you control, with no cut taken off the top. For most teams that already sell subscriptions, that is the difference between turning revenue away and booking it.
Learn more about VBWD
VBWD is a self-hosted, source-available platform for building subscription products, marketplaces, and AI-powered apps. Explore it further:
- 🌐 Website and documentation: vbwd.cc — see the plugins, architecture, and developer docs.
- 💻 Source code and plugins on GitHub: github.com/VBWD-platform
- 🎥 Watch VBWD in action: demo video 1 and demo video 2
- 💼 Follow the project on LinkedIn: linkedin.com/company/vbwd