Routing Strategies

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.

PlaneBase pathWhat it answers
Yield analytics/api/yield/{pool_id}What is this pool earning per unit, and where?
Quality scores/api/qualityHow 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.

OperationMethod & path
Get / update configGET · PUT /api/yield/{pool_id}/config
Resolve floor priceGET /api/yield/{pool_id}/floor-price
SnapshotGET /api/yield/{pool_id}/snapshot
Detailed snapshotGET /api/yield/{pool_id}/snapshot/detailed
Time seriesGET /api/yield/{pool_id}/timeseries
HeatmapGET /api/yield/{pool_id}/heatmap
ForecastGET /api/yield/{pool_id}/forecast
Compare periodsGET /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/config

Floor 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.

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.

OperationMethod & path
Compute (sync)POST /api/quality/compute
Trigger compute (async)POST /api/quality/trigger-compute
Get / update configGET · PUT /api/quality/config
Pool leaderboardGET /api/quality/pools/{pool_id}/leaderboard
Pool recipientsGET /api/quality/pools/{pool_id}/recipients
Recipient metricsGET /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/compute

Reading scores

LeaderboardGET /api/quality/pools/{pool_id}/leaderboard returns recipients ranked by overall score, descending. The "who's best in this pool?" view.

Pool recipientsGET /api/quality/pools/{pool_id}/recipients is the paginated list of every recipient's score in a pool, filterable by tier.

Recipient metricsGET /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):

OperationPathNotes
Revenue forecastGET /api/forecast/revenue/{pool_id}days horizon, model selector
Volume forecastGET /api/forecast/volume/{pool_id}days horizon, model selector
BreakpointsGET /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.