---
title: "Marketplace"
url: /patterns/marketplace
---

# Marketplace

> Sell what many suppliers offer, under your brand, with each payment split on Stripe between the supplier and you.

```text title="Order: its lifecycle"
placed ──claim──▶ claimed ──fill──▶ filled ──accept · 40──▶ accepted
   │                                   │
   └──unclaimed in 4h: rematched       └──contest──▶ contested ──upheld──▶ refunded
                                                          └──────denied──▶ accepted
```

| One sale, split once · USD | Share | Amount |
| --- | --- | --- |
| `Order.place`, accepted | the Lookup's price | 40 |
| The researcher | 85% | 34 |
| You | your take, 15% | 6 |

A Marketplace is the other patterns sold by many suppliers at once. You own the storefront, the Customer and the rules; each supplier owns its items in the catalog, does the work and is paid on Stripe.

```ts title="definition.ts"
import { define } from 'apis.dev'

/** Company research from verified researchers, ordered in one call and paid when you accept it. */
export default define({
  name: 'research', domain: 'research.apis.dev',
  …
  Researcher: {                                         // a supplier: the second account kind
    supplier: { verify: ['identity', 'tax'], payout: 'stripe' },
    name: 'string', lookups: '<-Lookup.researcher',
  },
  Lookup: {                                             // one item in a supplier's catalog
    researcher: '->Researcher.lookups', orders: '<-Order.lookup',
    title: 'string', days: 'number', price: 'decimal(8,2)',
    status: { publish: [], pause: 'published', resume: 'paused' },
  },
  Order: {                                              // what the buyer watches
    lookup: '->Lookup.orders', company: 'url', answer: 'string?',
    status: {
      place: { match: ['rating', 'price'], claimWithin: '4h' },
      claim: { in: 'placed', role: 'researcher' },
      fill:  { in: 'claimed', role: 'researcher' },
      accept: 'filled', contest: 'filled',
    },
  },
  offer: {
    'Lookup.publish': 0,
    'Order.place': { price: 'lookup.price', bounds: [10, 500], when: 'accepted',
                     accept: 'customer', acceptWithin: '5d', remedy: 'refund' },
    take: 0.15,                                         // your share of each sale, split on Stripe
  },
})
```

The supplier sets each Lookup's price inside your `bounds`, and every price is public on the catalog and on `/pricing`. You set the take, the terms and who may sell.

## Suppliers and their catalog
A supplier is a second kind of account: it signs up, is verified, publishes what it sells and is paid out. The developer portal serves it beside your Customers, and every supplier move is a Verb its own agents can call.

| Family | What it does |
| --- | --- |
| Join and verify | Identity, tax and any credential your `verify` names, checked before a supplier publishes anything |
| The catalog | Each supplier's items, written by them or synced from their own system as an [Integration](/patterns/headless-saas.md#integrations), shown under your brand |
| Matching | An order goes first to the supplier of the item it names; unclaimed, it is rematched by the keys you rank |
| Capacity and track record | What each supplier can take on, their on-time and acceptance rates, and their ratings, all from the record |
| Supplier orgs | A supplier with members, Roles and agents of its own, under one payout account |

| Thing | States | What moves it |
| --- | --- | --- |
| A supplier | `applied`, `verifying`, `verified`, `paused`, `removed` | Verification passes or fails; you or the supplier pause; you remove, and the record is kept |
| A payout account | `onboarding`, `enabled`, `restricted` | Stripe's onboarding, and any later request Stripe makes of the supplier |
| A catalog item | `published`, `paused`, `removed` | The supplier; a supplier who is paused pauses every item |

## An order, from placed to paid
An order is a Thing the buyer watches, like an outcome in a [Service API](/patterns.md#service-api). The supplier claims it, fills it, and the buyer accepts or contests it under the [Outcome contract](/reference/platform.md#outcome-contract) your Offer names.

```http title="POST /orders, the buyer places an order"
HTTP/1.1 201 Created
Location: /orders/order_1
X-Action-Id: act_1
X-Cost: price=0, currency="USD"
X-Request-Id: req_5c1e0a9b7d2f48e6a310

{
  "id": "order_1",
  "lookup": "lookup_7",
  "company": "acme.com",
  "answer": null,
  "status": "placed",
  "createdAt": "2026-10-27T09:00:00Z",
  "updatedAt": "2026-10-27T09:00:00Z"
}
```

Placing an order holds its price on the buyer's balance or card, and nothing is charged. Acceptance charges it and splits it. Silence for 5 days accepts it, and a contest upheld refunds it in full.

## The split
Every sale splits once, at the moment the Offer charges, into a line per payee. The supplier's share goes to their own Stripe account, and your take stays in yours.

| Family | What it does |
| --- | --- |
| Splits per line | Each sale names its payees and their shares; a sale built on another product's Verb pays that seller too, at its printed price |
| Charge on proof | Held at placement, charged on the move the Offer names: accepted, delivered or shipped |
| Payouts | To each supplier on Stripe, on the schedule you set, with a statement per payout |
| Refunds and clawbacks | A refund reverses every share pro rata; a share already paid out is taken from the supplier's next payout |
| Tax forms | Collected at onboarding, issued each year for every supplier paid |

The seller's view of an accepted order arrives on a [Watch](/reference.md#events), with its split.

```json title="Order.accepted · to you"
{
  "id": "evt_9",
  "type": "Order.accepted",
  "at": "2026-10-29T14:20:00Z",
  "seq": 9,
  "data": { "id": "order_1", "status": "accepted" },
  "charged": { "price": 40, "currency": "USD" },
  "split": [
    { "payee": "researcher_3", "amount": 34 },
    { "payee": "you", "amount": 6 }
  ]
}
```

The buyer sees the price and the receipt. The researcher sees their 34 and its payout. Neither sees the other's books.

## Contracts and the platform's part
| You declare | The platform does |
| --- | --- |
| A Noun marked `supplier`, with what it must pass | Runs the account kind: sign-up, verification, payout onboarding on Stripe, tax forms, the supplier's side of the portal |
| The catalog Noun and its lifecycle | Serves every supplier's items under your brand, on the landing site, `/pricing` and the offer card |
| `match` and `claimWithin` | Routes each order, rematches an unclaimed one, and records why each match was made |
| The take, the bounds and the Outcome contract | Holds, charges, splits, pays out, refunds and claws back, all on Stripe |
| Nothing for the record | Keeps each supplier's track record, ratings and disputes, and shows them on every item |

| Subsystem | What a Marketplace takes from it |
| --- | --- |
| Definition and compile | The `supplier` Noun, the bounds and the take, checked at deploy: shares above the price are refused |
| Identity, access and policy | Two account kinds, verification, Roles on supplier moves, mandates for supplier agents |
| Model and records | The catalog, orders, ratings and stock |
| Data and Sources | Each supplier's catalog feed, read and written back |
| Runtime | The claim clock, the rematch, and `Order.accepted` with its split on the Event |
| Work | Matching, capacity, track record, fulfilment and disputes |
| Commerce | Holds, splits, the take, payouts, refunds and clawbacks |
| Interfaces and distribution | The catalog on the site, the supplier portal, the offer card per item |
| Trust and operations | Supplier risk, fraud on both sides, and the evidence behind every contest |

## What buyers, suppliers and their agents meet
A buyer browses one catalog under one brand, orders in one call, and pays once. An agent finishes the same path with no UI:

1. It searches the catalog with `listLookups`, and reads each item's price, days and track record.
2. It places the order with `placeOrder`, within its `Max-Cost` and mandate.
3. It watches the order, reads the answer when filled, and accepts it or contests it with the receipt.

A supplier, or the supplier's agent under a mandate, claims orders with `claimOrder`, fills them with `fillOrder`, and reads each payout. A contested fill shows the supplier the buyer's reason and the evidence before anything is refunded.