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.
Two of the signals that drive yield-optimized
routing — yield and quality — aren't magic numbers. They come from a
standalone analytics and configuration plane you can read, tune, and recompute
on its own. This page documents that plane: the /api/yield, /api/quality,
and /api/forecast endpoints.
These are the signals behind the Priced stage of the clearing lifecycle. A dynamic floor is a computed number, not a guess — the floor-price endpoint here is where that computation lives — and the quality score is the axis a Bid is weighed on beyond price alone. When the market clears work, this is the plane it reads from.
This is the source, not the scorer
Scoring → Yield optimized explains how a strategy combines signals at route time — expected value ≈ conversion × value × quality × margin. This page is the other side: the APIs that measure and store those signals so the scorer has something to read. If you want to know how routing uses the numbers, read scoring; if you want to know where the numbers come from, read on.
| Plane | Base path | What it answers |
|---|---|---|
| Yield analytics | /api/yield/{pool_id} | What is this pool earning per unit, and where? |
| Quality scores | /api/quality | How good is each recipient, and why? |
| Forecast | /api/forecast/{metric}/{pool_id} | What will revenue and volume do next? |
Yield analytics
Yield is revenue per routed unit, sliced by segment, recipient, and time.
The nine endpoints under /api/yield/{pool_id} cover configuration, a live
floor price, point-in-time snapshots, and time-shaped views (series, heatmap,
forecast, period compare). All reads require yield:read; config writes require
yield:write.
| Operation | Method & path |
|---|---|
| Get / update config | GET · PUT /api/yield/{pool_id}/config |
| Resolve floor price | GET /api/yield/{pool_id}/floor-price |
| Snapshot | GET /api/yield/{pool_id}/snapshot |
| Detailed snapshot | GET /api/yield/{pool_id}/snapshot/detailed |
| Time series | GET /api/yield/{pool_id}/timeseries |
| Heatmap | GET /api/yield/{pool_id}/heatmap |
| Forecast | GET /api/yield/{pool_id}/forecast |
| Compare periods | GET /api/yield/{pool_id}/compare |
Configuration
GET/PUT /api/yield/{pool_id}/config reads and writes the pool's yield
optimization settings.
Prop
Type
PUT rejects an invalid band (floor > ceiling) with 422.
curl -H "X-Tenant-ID: $DUCTOR_TENANT_ID" \
http://localhost:8080/api/yield/$POOL_ID/configFloor price
GET /api/yield/{pool_id}/floor-price resolves the currently effective
floor for a pool, optionally scoped to a segment. It returns the floor_price
and the effective_at timestamp it became active — the price no route below
which the pool will clear.
Snapshots
GET /api/yield/{pool_id}/snapshot returns a point-in-time roll-up — revenue,
volume, yield per unit, acceptance rate, and fill rate — optionally filtered by
segment and a from/to window. GET /api/yield/{pool_id}/snapshot/detailed
adds optional per-recipient breakdowns when you pass include_recipients=true.
Time-shaped views
GET /api/yield/{pool_id}/timeseries buckets yield by granularity (1h,
1d, …) over a from/to window, each point carrying revenue, volume, and
yield per unit. Use it to chart trends and feed dashboards.
GET /api/yield/{pool_id}/heatmap returns a two-dimensional grid with
configurable x_axis and y_axis dimensions — hour_of_day, day_of_week,
or an attribute — each cell carrying a value and a volume. It answers "when
and for whom is this pool most profitable?".
GET /api/yield/{pool_id}/compare takes two windows
(period_a_start/end, period_b_start/end) and returns a snapshot for each
plus percentage changes in revenue, volume, and yield per unit — the "is it
getting better?" query.
Yield forecast
GET /api/yield/{pool_id}/forecast projects revenue, volume, yield per unit,
and a confidence score over a period (7d, 30d, …). This is the
yield-flavored forecast; the dedicated Forecast API below exposes
the same modeling with more control over model choice and horizon.
Quality scores
This is where recipient quality scores come from. A quality score is a
composite (0–1, surfaced 0–100) of six weighted dimensions computed from a
recipient's recent history. The scorer's quality term
(Scoring → Yield optimized) reads the
number this pipeline produces — it does not compute it.
| Operation | Method & path |
|---|---|
| Compute (sync) | POST /api/quality/compute |
| Trigger compute (async) | POST /api/quality/trigger-compute |
| Get / update config | GET · PUT /api/quality/config |
| Pool leaderboard | GET /api/quality/pools/{pool_id}/leaderboard |
| Pool recipients | GET /api/quality/pools/{pool_id}/recipients |
| Recipient metrics | GET /api/quality/recipients/{recipient_id} |
The six dimensions
Each recipient's overall score is a weighted blend. The default weights (they
must sum to 1.0, enforced with 422) live in
modules/services/quality/config.go:
Prop
Type
Scores map to tiers by threshold — platinum (≥ 0.90), gold (≥ 0.75), silver
(≥ 0.50), bronze (≥ 0.25), and probation below that. The config also carries a
compute_interval_minutes and a lookback_days/window over which signals are
measured.
Cold-start and probation
Quality carries a minimum-samples floor and a probation threshold in its
domain config (min_samples, probation_threshold, probation_action): a
recipient with too little history is held at the new/probation tier rather than
trusted on a lucky streak. This is the analytics-side counterpart to the
min_outcomes gate on the
yield-optimized scorer.
Computing scores
Recomputation is explicit. POST /api/quality/compute runs a synchronous
recompute for an entity_type (e.g. recipient) scoped to a pool_id and
returns the computed scores inline. POST /api/quality/trigger-compute queues
an asynchronous job and returns a job ID; pass force=true to recompute even
when scores are still fresh.
curl -X POST -H "X-Tenant-ID: $DUCTOR_TENANT_ID" \
-H "Content-Type: application/json" \
-d '{"entity_type":"recipient","pool_id":"'$POOL_ID'"}' \
http://localhost:8080/api/quality/computeReading scores
Leaderboard — GET /api/quality/pools/{pool_id}/leaderboard returns
recipients ranked by overall score, descending. The "who's best in this pool?"
view.
Pool recipients — GET /api/quality/pools/{pool_id}/recipients is the
paginated list of every recipient's score in a pool, filterable by tier.
Recipient metrics — GET /api/quality/recipients/{recipient_id} returns one
recipient's score with its dimensional breakdown and tier — the explainable
"why is this recipient gold?" record.
Forecast
The /api/forecast API is standalone predictive analytics over a pool's history.
Three read endpoints (all require forecast:read):
| Operation | Path | Notes |
|---|---|---|
| Revenue forecast | GET /api/forecast/revenue/{pool_id} | days horizon, model selector |
| Volume forecast | GET /api/forecast/volume/{pool_id} | days horizon, model selector |
| Breakpoints | GET /api/forecast/breakpoints/{pool_id} | anomaly / structural-change detection |
Revenue and volume forecasts take a days horizon (default 30) and a model
(auto, arima, or holtwinters), returning daily points with confidence
intervals and the model's RMSE. Breakpoint detection returns timestamps with
before/after values and percentage change for each detected structural change.
Overlap with yield forecast
GET /api/forecast/revenue/{pool_id} and
GET /api/yield/{pool_id}/forecast both project revenue. The
yield endpoint is the quick, yield-shaped projection bundled with the yield
analytics; the /api/forecast API is the dedicated modeling surface with
explicit model choice, a days horizon, confidence intervals, RMSE, and
breakpoint detection. Reach for /api/forecast when the forecast is the
product; use the yield endpoint when you just want a number alongside the other
yield stats.
Related
Agent Procurement
Buyer-side clearing for agent work — typed bids in exact micro-units, pinned identity that cannot drift, and a freeze that never loses a bid.
Capacity marketplace
A secondary market where recipients trade spare capacity — listings, an order book, trades, price suggestions, and per-pool market config.