Capacity marketplace
A secondary market where recipients trade spare capacity — listings, an order book, trades, price suggestions, and per-pool market config.
The capacity marketplace lets Workers (modelled today as recipients) buy and sell spare capacity units among themselves. A worker with idle headroom lists it; a worker that is saturated buys units to raise its own cap. It is the over-subscription economics plane of Ductor — a market for capacity itself, settled per pool under a configurable fee and price band. It is a second clearing surface alongside the work markets: the same settlement discipline, applied to the right to handle more work rather than to a unit of work.
Not the same thing as Markets
Markets is auction routing — recipients compete for a unit of work being routed right now (claim races, ping/post, first- and second-price auctions). The unit traded there is an opportunity.
The capacity marketplace trades capacity — the right to handle more work later. No routing decision is being made; recipients are rebalancing their caps by transacting units between each other. Different plane, different unit, don't conflate them.
Opt-in per pool
The marketplace is disabled by default — MarketConfig.Enabled starts
false for every pool. A pool does not participate until you enable it and set
its price band via market config. The service ships as a
contrib module (modules/services/capacity) wired to the marketplace store.
Operations
Ten endpoints under /api/capacity, in four groups.
| Group | Operations |
|---|---|
| Listings | GET · POST /listings · GET · PATCH · DELETE /listings/{listing_id} |
| Order book & pricing | GET /pools/{pool_id}/orderbook · GET /pools/{pool_id}/suggest-price |
| Trades | GET /trades |
| Market config | GET · PUT /pools/{pool_id}/config |
Listings
A listing is spare capacity offered for sale: a seller posts units at a
price_per_unit, optionally bounded by min_purchase/max_purchase,
routable_types, and an expiry. Listings move through
active → filled | expired | cancelled.
| Operation | Method & path |
|---|---|
| List active listings | GET /api/capacity/listings |
| Create listing | POST /api/capacity/listings |
| Get one listing | GET /api/capacity/listings/{listing_id} |
| Update listing | PATCH /api/capacity/listings/{listing_id} |
| Cancel listing | DELETE /api/capacity/listings/{listing_id} |
GET /api/capacity/listings filters by pool_id and paginates
(pagination.page_size up to 1000, pagination.page_token), newest first.
PATCH is a partial update — units, price, purchase bounds, expiry, and
metadata — and DELETE cancels a listing without touching already-executed
trades.
curl -X POST -H "X-Tenant-ID: $DUCTOR_TENANT_ID" \
-H "Content-Type: application/json" \
-d '{"pool_id":"'$POOL_ID'","seller_id":"'$SELLER_ID'","units":50,"price_per_unit":2.5,"currency":"USD","min_purchase":5}' \
http://localhost:8080/api/capacity/listingsOrder book & pricing
GET /api/capacity/pools/{pool_id}/orderbook returns the pool's live market
state — every active listing, total_units_available, and the average, minimum,
and maximum price per unit, plus recent trades.
GET /api/capacity/pools/{pool_id}/suggest-price returns platform pricing
guidance for a pool: a suggested bid and ask, the observed market price, the
spread, available supply, and a demand signal — computed from current market
conditions.
Trades
A trade is a completed capacity transfer. It records the parties
(seller_id, buyer_id), units, price_per_unit, total_price, the
platform_fee and seller_credit, and the buyer's and seller's cap before and
after — so the economic effect on each side is fully auditable.
GET /api/capacity/trades lists completed trades for a recipient_id (with a
limit, default 50).
Trades are listed, not posted here
There is no public endpoint that executes a trade. GET /api/capacity/trades
only reads completed trades. Trade execution runs inside the marketplace engine
(ExecuteTrade in modules/services/capacity/domain/engine.go), which validates
and deducts units atomically to avoid over-selling a listing. The REST surface
exposes listings, the order book, pricing, config, and this read-only trade
history.
Market config
GET/PUT /api/capacity/pools/{pool_id}/config reads and writes the pool's
marketplace configuration — the fee structure, price band, and trading limits
that govern every listing and trade in the pool.
Prop
Type
PUT rejects an inconsistent band (e.g. min_fee > max_fee) with 422.
Related
Yield & Quality analytics
The analytics and configuration APIs that produce the yield and quality signals scoring strategies consume — snapshots, forecasts, heatmaps, and the quality-score pipeline.
Ranked
Ordered routing slates — a durable list of selected, alternate, eliminated, pending, and failed candidates — and an adapter to produce them from any scorer.