OpenLup
Open source · Apache-2.0 · development preview

Subscription-first commerce for physical goods, on code you own

The subscription layer in the open: renewals, dunning, payment recovery, self-service. Not a Shopify add-on. Not a billing API.

Shell
npm install --save-exact @openlup/core@0.37.0
Development preview. npm 0.37.0. Running on velipet.com, the author’s shop.
One late payment
Pinned by a pgTAP test of the late-payment shift.

Built and tested on

TypeScript · Node.js 24 · PostgreSQL 16 · Vercel · Supabase · OCI image

Providers sit behind ports. Ownership and extension

The case for owning it

Shelf space is rented. Subscribers are not

Finite shelf
A listing you rent, capped by what fits
No relationship
The buyer is theirs, not yours
Direct compounds
Subscription is where repeat value can accrue to you
Closed or generic
Rent the subscription layer, or own a system that lacks it

Subscriptions are the business, not an add-on. OpenLup keeps them in the open core, with no app fee and no revenue share.

Categories

Replenishment
The same products, delivered again on the customer’s cadence
Curated boxes
A box assembled for each cycle, from your catalogue
Repeat order
The customer’s own basket, ordered again when they want it

The core knows neither your brand nor your country.

What ships in the open core

The subscription layer, in code you own

Subscription engine
Cycles, renewals, pauses, skips, line swaps, add-ons
Dunning and recovery
A retry ladder that terminates, and one-use recovery links
Customer self-service
Pause, skip, swap a line, repair a card; off by default
Operator panel
Order queue with an attention ladder, holds, replacements
Transactional messaging
Outbox, consent, delivery reconciliation, health verdict
Working store from npm
Install from npm, guest checkout, sandbox payments, renewals and recovery
In progress · M19a
Subscription care
Pause and resume, reminders, escalation, win-back, order now, save offers
Planned · M19b1a
Payment recovery and account
Recovery reminders and pages, saved addresses, billing profile, operator replacements
Planned · M19b1b
Subscription editor
Classic editor with price preview; swap, mix, portion and size levers
Planned · M19b2

227 pgTAP files · 2 389 test files · 113 platform migrations · measured on npm 0.37.0

Also in the tree

A neutral store starter to begin from; kernels for bundles, inventory, pricing, promotions, shipping, risk and company identity; and example adapters for payments, fulfilment and e-mail.

The full cycle

One system from first order to the next renewal

Happy path above, failure and repair below, messaging under both.

The split

Open coreYours
Checkout to renewal, the subscription pathBrand look and identity
Subscriptions, dunning, mandates, recoveryCopy, tone, configurator logic
Messaging with schedule and observabilityTaxes, carriers, fiscal rules
Customer account and self-service actionsERP, WMS, CRM integrations
Operator panelPricing and promotion rules
Payments, fulfilment, invoicing behind portsHosting choice
Runtime, migrations, scheduler, storage

Nothing is withheld. Limits are documented.

What the engine promises

Subscriptions, dunning, mandates and recovery are open core and will not become paid tiers.

TypeScript
export type SubscriptionEngineErrorCode =
  | "invalid_timestamp"
  | "invalid_template"
  | "inactive_subscription"
  | "edit_window_closed"
  | "line_not_found"
  | "duplicate_line"
  | "invalid_slide_target"
  | "invalid_transition"
  | "terminal_cycle"
  | "missing_payment_method"
  | "dunning_not_exhausted";

Refusals are values. Nothing throws.

Deep dive: the cycle shift

A late payment shifts the cycle. It never compresses it

The customer keeps the cadence they paid for, whatever the payment did.

28 days
the gap bought
17 days
what a day-11 recovery used to leave
28 days
what it leaves now
Pinned by a pgTAP test of the late-payment shift.
Why the clamp is load-bearing

The next cycle is the cycle’s own scheduled date plus its cadence plus the days the payment was late, and it never moves earlier. The clamp means a replayed payment webhook cannot pull a charge forward into a window the customer already paid for.

A late parcel moves the next cycle too

With delivery alignment on, the next cycle starts from the latest confirmed delivery plus the cadence, and renewals wait while a parcel’s outcome is unknown, so parcels never stack up. The mode is off by default.

Deep dive: the retry ladder

The retry ladder terminates. It does not cap

Nothing repeats its last slot forever.
24 h · 72 h · 168 h
Fixed in the managed SQL, injectable in the pure core
A class can end it early
When the issuer refused the instrument, the ladder stops at once
Recovery is a token
Single-use and owner-bound; redemption requires the owner’s session
Transactional messaging

Transactional e-mail with an outbox and reconciliation

Outbox and e-mail ledger, each a state machine
Marketing consent checked before a send
Delivery reconciliation when a webhook drops
Health verdict per deployment

E-mail is the one channel today.

Ownership and extension

Your layer is yours. Our releases arrive as pinned packages

AdapterOn npmLaneProof scope
Supabase PostgreSQL (managed database)yesmanagedData gateway and job ledger for the managed rail. Fresh-install, upgrade and existing-store restore proofs for this rail remain partial.
Supabase AuthyesmanagedCustomer and operator sign-in on the managed rail. Operator sign-in smoke checks and a hosted settings readback remain open.
Supabase StorageyesmanagedBlob storage binding. Serving and access proofs remain open.
Portable PostgreSQL (self-host and Amazon RDS recipes)yesportableLocal self-host recipe receipt, local store transfer and restore witnesses, and one hosted RDS PostgreSQL 16 recipe run on a single synthetic instance. No hosted transfer or recovery has run, and none of this is production qualification.
NeonnoportableNo receipt yet. A Neon recipe receipt and Neon to Amazon RDS transfer and recovery are planned in the hostability round.
Generic OIDC and JWKS identityyesportableOpt-in access-token verifier. A real-issuer lifecycle witness passed on one disposable hosted origin; no production qualification.
S3-compatible object storageyesportable and managedLocal recipe with two gateway accounts and one hosted run on a single synthetic bucket in one region. No production qualification.
Vercel (Node functions, scheduled jobs, Blob)yesmanagedBlob binding and the reference default bundle with the managed database, without the Edge runtime. A Vercel host for the portable neutral store is planned in the hostability round.
Generic Node host and OCI imageyesportableLocal self-host receipt and one hosted run on a single synthetic VM with restart, drain and A to B to A rollback checks. No production qualification.
Netlify (independent PaaS candidate)noportableCandidate only, not yet measured. It is evaluated in the hostability round.
Resend emailyesportable and managedOpt-in adapter on the communications entry with offline conformance. No provider-account evidence.
Klaviyo marketing syncyesportable and managedOpt-in adapter with offline conformance only; account verification is pending.
Stripe paymentsyesmanagedOpt-in example adapter with an injected client. Refund creation and split authorization and capture are not available, some hosted paths are not observed, and real money runs only on the managed rail.
Tpay paymentsyesmanagedOpt-in example adapter with simulator evidence only. Real settlement and provider readback are not verified.
OmniPack warehouse fulfillmentyesmanagedOpt-in, default-off example with offline conformance. Exact absence, label create and void and cancellation are not available, and some dispatch and reconciliation paths have not been exercised.
Polish company registries (VAT whitelist, GUS/CEIDG)noportable and managedNot packaged. A packaged example lookup adapter comes in the A5 adapter round.
External sales channels (normalized import)yesportable and managedNormalized ingest contracts and bindings. No real connector ships, and conversion to a physical order refuses on the portable rail.

Proof scope as the OpenLup roadmap states it; passing conformance does not qualify a provider.

Where it runs

Three runtime bundles: Vercel with Supabase, Node with Supabase, Node with plain PostgreSQL. None is a supported production recipe yet. Real money runs on the managed rail today; a portable real-money rail is on the roadmap. No hosted service exists.

Built with agents

Built with AI agents, and built to be extended with them

Agents work within explicit human authority. A human is answerable for every line.

Dependencies point inward
No I/O, no ambient clock in the kernel
Engine refusals are values, not exceptions

The properties that make a codebase legible to an agent.

OpenLup is built with Claude Code and Codex: they implement, verify and review, and every change stays within the maintainer’s grant.

Comparison

Where the subscription layer lives

ProductKindSubscriptions, dunning, self-servicePublished feesRead
Saleoropen-source platform, BSD-3-Clauseno subscription engine; recurring payments built on the Transaction APInone; self-hosted2026-11-06
WooCommerce Subscriptionspaid extension for WooCommerce, by Woosubscriptions; retries off by default; self-service in My Account$279 per year2026-11-06
Medusaopen-source platform, MITnot in core; a documented recipenone; self-hosted2026-11-06
Syliusopen-source platform, MIT; paid Plus modulesubscriptions in Sylius Plus (0.x); dunning not documentedSylius Plus from €800 per year2026-11-06
ShopwareMIT Community; commercial plansBeyond plan subscriptions; pause, cancel; dunning not documentedBeyond, custom price2026-11-06
Stripe Billingbilling engine, SaaS; no storefront or fulfilmentsubscriptions; Smart Retries; customer portal0.7% of billing volume or from $620/month (US)2026-11-06
Shopify SubscriptionsShopify appsubscriptions; configurable retries; customer self-servicefree app on a Shopify plan from $39/month (US)2026-11-06
RechargeShopify appsubscriptions; dunning in every plan; customer portalfrom $149/month + 1.50% + 20¢ per order2026-11-06
LoopShopify appsubscriptions; 15 retries on Starter; customer portalfree plan; from $99/month + 1.0% per order2026-11-06
JUOShopify appsubscriptions; dunning not documentedfrom $199/month + 1.25% + 19¢ per order2026-11-06
OpenLupopen-source platform, Apache-2.0subscriptions, dunning and self-service in the open corenone per order; self-hostedpolicy

Feature presence and published fees only, read on each product’s own pages on the date shown; card processing is extra everywhere. One deployment serves one store today.

Policy

Written down before there was money at stake

One-way ratchet
Open never becomes paid
.github/TIER_POLICY.md
Paid value, if ever
In the operational layer, never in withheld code
.github/TIER_POLICY.md
DCO, no CLA
There is no CLA, and there will not be one
.github/GOVERNANCE.md
AI contributions welcome
Disclosure, never a ban
.github/AI_CONTRIBUTION_POLICY.md
No SLA, said plainly
None is offered today
.github/SUPPORT.md
Fork is part of the offer
Apache-2.0, fresh-history root
.github/PUBLICATION_COMPLETENESS.md
Read the six sentences in full

Anything published under Apache-2.0 stays open. Permanently. Open never becomes paid. In the operational layer, never in withheld code. There is no CLA, and there will not be one. AI-assisted contributions are welcome. They are not banned, and they will not be banned. Nothing in this project carries a service-level agreement. The first public OpenLup root is a mechanically derived, fresh-history subset of the pre-split development repository, not a hand-assembled copy.

Commerce is strictly additive: paid work is built on top of a stabilized open core, never carved out of it. There are no tiers. Everything the project publishes is open.

Proof

Built for a real shop first, published second

Not designed in the abstract. Extracted from the author’s own shop, velipet.com, which runs it in production with real customers and real money.

113
platform migrations
227
pgTAP files
2 389
test files
23
server domains
18
core entry points
3
runtime bundles

Measured on npm 0.37.0. velipet.com is the author’s shop, not an independent adopter; it adopts the published packages, and its changes go through OpenLup’s own review and releases.

Subscriptions are the business. They should not be a monthly app fee and a revenue share. I built OpenLup so a brand can own them.

Bart Roszkowski, author of OpenLup, co-founder of Vue Storefront (now Alokai)
Roadmap

What has to be true before this is called stable

Three doors

FAQ

Can I use it today?

To evaluate a whole store, yes: the neutral starter installs from npm on PostgreSQL, with sandbox payments. Real money runs on the managed rail, and nothing is stable, supported or certified yet.

What stays free?

Everything published under Apache-2.0, permanently. Subscriptions, renewals, dunning, mandates, recovery and messaging will not become paid tiers.

Will there be a paid version?

No tiers today. Paid work, if it comes, is strictly additive: built on top of a stabilized open core, never carved out of it.

What do I build myself?

Brand, copy, storefront, catalogue, your market's taxes and carriers, your ERP and CRM integrations, your pricing rules, your hosting.

Which providers work?

None are certified. Example adapters exist for payments, fulfilment, e-mail, auth and storage, each with its proof scope written down.

Is it multi-brand?

One deployment serves one store today.

Who runs it in production?

velipet.com, the author’s own shop. It is not an independent adopter.

Can I contribute with an AI agent?

Yes. Disclose it and stay accountable for every line. An agent opens a pull request only with a maintainer’s explicit authority.

Can I fork it?

Yes. Apache-2.0 and a fresh-history root. The name and logo are not part of the licence, so a fork takes its own name.

Open source subscription commerce for physical goods

Development preview. Stable begins at the P1-SF gate.