A headless commerce engine with a multi-vendor layer on top. The storefront talks to it over JSON and owns none of this.
The layers
| Layer | What it owns |
|---|---|
| Commerce engine | Products, variants, carts, orders, customers, regions, tax. The substrate, and open source. |
| Multi-vendor layer | Sellers, the vendor panel, payout routing. What turns one store into a marketplace. |
| Our own modules | Fee calculation, the Vers Capital ledger types, the platform-specific bits nobody ships in a box. |
| Database | PostgreSQL. One database, migrated, not sharded. |
How a product knows its house
A product and a seller are linked through a join table. That link is what makes a product visible in the store API at all, and it is the single most common cause of a product that exists in admin and cannot be found on the site.
product ──┐
├── product_seller link ── seller ── payout account
region ───┘
└── calculated_price (per region)
no link → invisible in the store API
no region → visible with no price
neither → invisible, and it looks like a caching bugA price only exists in the context of a region. A product with no calculated price for the requested region renders without one, which looks like a front-end fault and is not.
Approval gating
The store API filters to approved sellers only. An application that has not been accepted has a seller record and no shelf, which is what lets a brand set their catalogue up before their listing opens rather than in a panic on the day. See Applying.
Two catalogue sources
| Native | Co-listed | |
|---|---|---|
| Product data lives | In our database | In the seller’s own store |
| Checkout | Ours | Theirs |
| Sync | Not applicable | Pulled, with an order webhook back |
| Fee | Split at capture | Invoiced on attributed sales |
Two sources means two sets of edge cases, which is the cost of letting a brand keep its own store. Mechanics in List on Shopify.
Money
Every amount is an integer number of cents. No floats, anywhere, at any layer, including in a test fixture. Details in Payments and payouts.
Where it runs
- The backend runs as a long-lived service with its own Postgres.
- The storefront is serverless and stateless, and holds no database connection.
- Routing and DNS sit in front of both.
- Search is not deployed. Browse is registry and category driven until it needs to not be.