Marketplace Data Model
Buyers and sellers meet through listings and search, with every order carrying gross merchandise value, take rate and seller payout, alongside the unmet searches, unsold listings and ratings that show where the match breaks down.
A two-sided online marketplace modeled end to end: independent buyers and independent sellers matched through listings and search, with every order carrying the full economics — gross merchandise value, the category take rate, the platform's cut and the seller's payout. Around that match sit the signals that tell you whether the two sides are actually clearing: what buyers searched for and failed to find, which listings never sold, which orders fell through before settling, and what the ratings say afterwards. Together they let you follow both sides of the flywheel — where demand goes unmet, and where supply gives up.
Example Questions
- Where is liquidity weakest — which
categorieshavebuyerssearching but too little live supply to fill the demand? - Is take-rate optimisation costing us supply, with
sellersin our highest-commissioncategoriesgoing dormant faster than the rest? - How much of our booked GMV never settles, and do
cancellationsand complaints concentrate around the samesellers?
Buyer
The demand side of the marketplace: one row per registered buyer, carrying how they were acquired, where they are, and how much they have transacted. Lifetime order count and a repeat flag make demand-side retention a first-class field — most buyers place a single order and never return, and the share who come back for a second is the health number every marketplace watches.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
buyer_id | STRING | Buyer ID | PK. Unique buyer identifier. |
signup_date | DATE | Signup Date | When the buyer first registered. |
acquisition_channel | STRING | Acquisition Channel | Marketing source that brought the buyer in. |
region | STRING | Region | Buyer's geographic region. |
segment | STRING | Segment | Buyer segment (one-time, occasional, regular, power). |
lifetime_orders | INTEGER | Lifetime Orders | Total orders the buyer has placed to date. |
is_repeat | BOOLEAN | Is Repeat | Whether the buyer has placed 2+ orders — demand-side retention. |
Cancellations
One row for every order that was cancelled — and only those. Each row records who pulled the plug (buyer, seller or platform), at which stage (pre-payment, pre-fulfilment or in-transit), the stated reason, and how much was refunded. Because refund magnitude scales with stage — near zero pre-payment, close to full once fulfilment is underway — this is where an ops or trust-and-safety lead finds the fixable concentration of fill-rate failures.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
cancellation_id | STRING | Cancellation ID | PK. Unique cancellation identifier. |
order_id | STRING | Order ID | Order that was cancelled. FK to Orders |
cancelled_at | TIMESTAMP | Cancelled At | When the cancellation happened. |
cancelled_by | STRING | Cancelled By | Who cancelled: buyer, seller or platform. |
stage | STRING | Stage | Order stage at cancellation: pre-payment, pre-fulfilment or in-transit. |
reason | STRING | Reason | Stated cancellation reason. |
refund_amount | NUMERIC | Refund Amount | Amount refunded to the buyer (never more than the order's gmv). |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Orders | order_id = order_id | N:1 | The order that was cancelled. |
Category
The category tree every listing and order is filed under, and — crucially — the standard take rate the platform charges on sales in each category. Take rate is the biggest lever a category manager holds: raise it and revenue per order rises, but the sellers in that category feel the squeeze. Rates follow real marketplace norms — physical goods sit lower (8–15%), while services and premium or handmade categories carry a higher cut (15–22%).
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
category_id | STRING | Category ID | PK. Unique category identifier. |
name | STRING | Name | Display name of the category. |
parent_category | STRING | Parent Category | Parent grouping in the category tree (Goods, Media, Services). |
take_rate_pct | FLOAT | Take Rate % | Platform's standard commission for the category, as a percent (e.g. 12.0 = 12%) — the take-rate optimisation lever. |
Listings
One row per listing, the unit of supply a buyer actually orders. Each listing belongs to a seller and a category and carries a price and an availability state. The count of live listings per seller is exactly that seller's active inventory, which makes this the backbone behind every order's price and category — and the first place to look when demand arrives and finds nothing to buy.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
listing_id | STRING | Listing ID | PK. Unique listing identifier. |
seller_id | STRING | Seller ID | Seller that owns the listing. FK to Seller |
created_at | TIMESTAMP | Created At | When the listing was created. |
category_id | STRING | Category ID | Category the listing belongs to. FK to Category |
price | NUMERIC | Price | Listed price of the offer. |
status | STRING | Status | Current listing status: active, paused, sold_out or removed. |
is_available | BOOLEAN | Is Available | Whether the listing is live inventory — supply availability. |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Category | category_id = category_id | N:1 | The category this listing is filed under. |
| Seller | seller_id = seller_id | N:1 | The seller who owns this listing. |
Orders
The match at the heart of the marketplace: one row per order placed, tying a buyer to a seller's listing. It carries the full transaction economics — gross merchandise value, the category take rate, the platform's cut and the reciprocal seller payout. Revenue is recognised only on orders that settle: a cancelled order keeps its booked GMV for funnel analysis while its net GMV, platform revenue and seller payout all fall to zero, so gross and net are never confused.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
order_id | STRING | Order ID | PK. Unique order identifier. |
buyer_id | STRING | Buyer ID | Buyer on the order. FK to Buyer |
seller_id | STRING | Seller ID | Seller on the order (always the listing's owner). FK to Seller |
listing_id | STRING | Listing ID | Listing that was purchased. FK to Listings |
category_id | STRING | Category ID | Category of the purchased listing, denormalised for slicing. FK to Category |
ordered_at | TIMESTAMP | Ordered At | When the order was placed. |
quantity | INTEGER | Quantity | Units ordered (gmv = listing price × quantity). |
gmv | NUMERIC | GMV | Gross merchandise value booked for the order. |
take_rate | FLOAT | Take Rate | Platform's cut as a fraction of GMV (= category take_rate_pct / 100). |
platform_revenue | NUMERIC | Platform Revenue | Platform's recognised revenue (gmv × take_rate; zero if cancelled). |
seller_payout | NUMERIC | Seller Payout | Seller's take-home (gmv − platform_revenue; zero if cancelled). |
net_gmv | NUMERIC | Net GMV | GMV net of cancellations (equal to gmv unless cancelled, then zero). |
status | STRING | Status | Order status: pending, fulfilled or cancelled. |
is_fulfilled | BOOLEAN | Is Fulfilled | Whether the order was fulfilled. |
fulfillment_mins | FLOAT | Fulfillment Mins | Order-to-fulfilment time in minutes — fill speed (null unless fulfilled). |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Buyer | buyer_id = buyer_id | N:1 | The buyer who placed this order. |
| Category | category_id = category_id | N:1 | The category this order is filed under. |
| Listings | listing_id = listing_id | N:1 | The listing that was ordered. |
| Seller | seller_id = seller_id | N:1 | The seller who fulfilled this order. |
Reviews
One row per review left after a fulfilled order — the marketplace's trust signal. Only a minority of completed orders are ever reviewed, since reviewing is voluntary, and ratings follow the familiar J-shape: mostly five stars, a hard bump at one star, little in between. The reviewer role separates the buyer's rating of the seller from the seller's rating of the buyer, and the complaint flag — concentrated in the low ratings — marks where trust is breaking down.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
review_id | STRING | Review ID | PK. Unique review identifier. |
order_id | STRING | Order ID | Order the review relates to (always a fulfilled order). FK to Orders |
reviewer_role | STRING | Reviewer Role | Side that left the review: buyer or seller. |
rating | INTEGER | Rating | Star rating 1–5 for the order. |
created_at | TIMESTAMP | Created At | When the review was submitted. |
has_complaint | BOOLEAN | Has Complaint | Whether the review flags a complaint (concentrated in 1–2 star ratings). |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Orders | order_id = order_id | N:1 | The fulfilled order being reviewed. |
Search Requests
One row per search a buyer runs — the top of the demand funnel and the cleanest read on marketplace liquidity. Each request records the category searched, how many results came back, whether the buyer clicked, and whether the search converted into an order, along with the time it took to match. Searches that return nothing, or return results but never convert, are the "demand with no fill" signal a liquidity analyst hunts for.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
request_id | STRING | Request ID | PK. Unique search request identifier. |
buyer_id | STRING | Buyer ID | Buyer who made the search. FK to Buyer |
category_id | STRING | Category ID | Category the search was scoped to. FK to Category |
requested_at | TIMESTAMP | Requested At | When the search was made. |
query | STRING | Query | Raw search text entered by the buyer. |
results_count | INTEGER | Results Count | Number of results returned. |
clicked | BOOLEAN | Clicked | Whether the buyer clicked a result. |
converted | BOOLEAN | Converted | Whether the search led to an order. |
order_id | STRING | Order ID | Order the search converted into, if any. FK to Orders |
time_to_match_mins | FLOAT | Time To Match Mins | Search → transaction latency in minutes (null unless converted). |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Buyer | buyer_id = buyer_id | N:1 | The buyer who ran this search. |
| Category | category_id = category_id | N:1 | The category searched in. |
| Orders | order_id = order_id | N:1 | The order this search led to, where it converted. |
Seller
The supply side: one row per seller, with the primary category they sell in, their buyer rating, how many listings they keep live, and — critically for supply-health work — when they last sold and whether they are still active. Supply is heavily concentrated: a small share of sellers drives most of the platform's GMV, so lifecycle status (active, dormant or churned, driven by sale recency) is where a supply manager looks first when GMV softens.
Fields
| Column | Type | Alias | Description |
|---|---|---|---|
seller_id | STRING | Seller ID | PK. Unique seller identifier. |
onboarded_at | DATE | Onboarded At | When the seller joined the platform. |
category_id | STRING | Category ID | Primary category the seller sells in. FK to Category |
region | STRING | Region | Seller's geographic region. |
rating | FLOAT | Rating | Average buyer rating of the seller (null until first review). |
active_listings | INTEGER | Active Listings | Number of currently live listings. |
is_activated | BOOLEAN | Is Activated | Whether the seller has reached its first sale — supply activation. |
fulfillment_type | STRING | Fulfillment Type | How the seller fulfils orders. |
last_sale_at | DATE | Last Sale At | Date of the seller's most recent sale (null if never sold). |
status | STRING | Status | Lifecycle state from sale recency: active, dormant or churned. |
Relationships
| Related data mart | On | Cardinality | Meaning |
|---|---|---|---|
| Category | category_id = category_id | N:1 | The seller's primary category. |
- 1
Install the Import Model plugin
One plugin, installed once, in your own OWOX workspace.
- 2
Import this model
Point it at this bundle and it creates every data mart above, joins and all.
- 3
Plug in your data and destinations
Connect your own sources and send the results where your team already works.
4. Optional — customize as you wish. Rename a column, drop a mart, add your own: once it is imported it is yours, and nothing here syncs back.