Marketplace
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.
GMV keeps growing while buyers search and find nothing, and no report shows which categories are short of supply.
Paste this into your AI assistant. It builds the Marketplace model's Data Marts in your data warehouse from your platform data, and shows which categories have buyers searching but too few live listings.
The prompt
Read https://www.owox.com/ai-agent-setup.md and follow it to set up OWOX Data Marts for me, starting from /data-models/marketplace.md. The task: build the Marketplace model with its Search Requests, Listings and Category Data Marts, then show me which categories have buyers searching but too little live supply to fill the demand. Tag the links you give me with utm_campaign=ai-task and utm_term=m1. Use what you know about my context and goals
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.
How this business is managed
- Supply — grows the number of sellers who actually sell, and keeps their catalogues live while they do.
- Demand — turns buyers' searches into orders, and brings the buyers who order back for a second one.
- Trust & Safety — keeps orders from being cancelled after they are placed, and buyers from ending up with a complaint.
Key metrics
- Net GMV — Orders · Net GMV by Orders · Ordered At.
- Take rate — Orders · Take Rate, platform revenue over net GMV, on a 0–1 scale.
- Active sellers — Orders · Active Sellers, distinct sellers with a non-cancelled order in the period.
- Cancellation rate — Orders · Cancellation Rate, by order count, on a 0–1 scale.
Key Data Marts
- Orders — every match of a buyer to a seller's listing, with its full economics.
- Search Requests — the demand that arrives, and how much of it ends in an order.
- Seller — the supply side, and where each seller is in its life on the platform.
- Listings — the catalogue buyers can order from today.
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?
To connect live data to your data model, plug in the data sources you need
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. |
repeat_buyer_share | FLOAT | Repeat Buyer Share | Calculated Field. Share of ordering buyers who placed two or more orders, lifetime, as a 0–1 fraction. Registered buyers who never ordered are left out of both sides, so the rate reads retention, not activation. Recent signup cohorts read lower because they have had less time to reorder. |
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). |
sellers_with_cancellations | INTEGER | Sellers With Cancellations | Calculated Field. Distinct sellers behind the cancelled orders in the selected rows, read through the order. Filter Cancelled By to |
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 searches arrive and find 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 | Order Commission Rate | Per-order commission rate, as a 0–1 fraction — the category's standard rate (category take_rate_pct / 100), kept even on a cancelled order that earns nothing. For take rate across orders use Take Rate (net_take_rate), never an average of this field. |
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 Time (min) | Order-to-fulfilment time in minutes — fill speed (null unless fulfilled). |
net_take_rate | FLOAT | Take Rate | Calculated Field. Platform revenue as a share of net GMV, as a 0–1 fraction — commission earned per dollar of GMV net of cancellations, pending orders included. A ratio of sums, so a large order weighs more than a small one; averaging Order Commission Rate ( |
cancelled_orders | INTEGER | Cancelled Orders | Calculated Field. Orders cancelled before settling, counted at whatever grain the report asks for. The numerator of Cancellation Rate. |
cancellation_rate | FLOAT | Cancellation Rate | Calculated Field. Share of orders placed that were cancelled, as a 0–1 fraction — by order count, not by value. Reads Cancelled Orders, so the two always agree. |
aov | FLOAT | Average Order Value | Calculated Field. Net GMV per non-cancelled order. Cancelled orders leave both sides, so a wave of cancellations does not drag the basket size down; pending orders count, because their GMV is still booked. |
active_sellers | INTEGER | Active Sellers | Calculated Field. Distinct sellers with at least one non-cancelled order in the selected rows — supply that actually sold. A distinct count: rows do not add up to the total, because one seller sells in several categories and months. |
order_size_band | STRING | Order Size Band | Calculated Field. Small, Medium, Large or Premium, from the order's gross GMV. A row-level formula that behaves as a dimension: group and filter by it. Bands are the order-value quartiles at round dollar edges. |
gmv_per_active_seller | FLOAT | GMV per Active Seller | Calculated Field. Net GMV per seller who made a sale, in dollars — supply productivity. Reads Active Sellers, so the divisor is a distinct count: recompute it at each grain, never sum or average the rows. |
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; the live supply they could have found is in Listings.
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 (min) | 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 the recency of their orders, or unactivated until the first sale) 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 (sold in the last 30 days), dormant (31–90 days), churned (more than 90 days) or unactivated (never sold). |
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.
You are booked. The invitation is on its way to , with the calendar invite and the meeting link.