checking...
v1.0.2

Fantasy Baseball Analytical Engine

Stateless SDaaS API that receives draft state and league settings, returns mathematical valuations, scarcity analysis, and draft simulations. No session state is written — pass the full draft context in every request.

Authentication

All analytical endpoints require an x-api-key header. Usage is tracked per-key.

# curl
curl -X POST https://q6dbuvmuvh.us-east-1.awsapprunner.com/valuation/calculate \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -d '{ ... }'

# axios (recommended)
const amethyst = axios.create({
  baseURL: process.env.AMETHYST_API_URL,
  headers: { 'x-api-key': process.env.AMETHYST_API_KEY },
  timeout: 10000,
});

Endpoints

POST /valuation/calculate Inflation-adjusted auction values + Steal/Reach indicators

Call after every auction pick. Returns every undrafted player ranked by adjusted value. AmethystDraft POSTs a single flat JSON body (see schemas/valuation-request.v1.schema.json); nested league + draft_state is still accepted. Invalid bodies return 400 with { "errors": [{ "field", "message" }] } (JSON path in field).

Request (legacy flat)
{
  "schema_version":       "1.0.0",     // optional; alias schemaVersion
  "checkpoint":           "pre_draft", // optional
  "roster_slots":        [{ "position": "OF", "count": 3 }, /* ... */],
  "scoring_categories":  [{ "name": "HR", "type": "batting" }, /* ... */],
  "total_budget":        260,         // per-team auction budget
  "num_teams":           12,          // optional, default 12
  "league_scope":        "Mixed",     // "Mixed" | "AL" | "NL"
  "scoring_format":      "5x5",       // optional: 5x5 | 6x6 | points
  "drafted_players": [{
    "player_id":  "695243",    // String(mlbId) — canonical key
    "name":       "Player Name",
    "position":   "OF",        // or use positions[] / roster_slot
    "team":       "NYY",
    "team_id":    "team_1",
    "paid":       42,          // optional auction price
    "is_keeper":   false,       // optional
    "pick_number": 3            // optional
  }],
  "deterministic":      false,       // optional — stable timestamps for tests
  "seed":                 42,            // optional — with deterministic, stable tie-breaks
  "player_ids":          ["660271"],   // optional — limit valuations[]; inflation uses full pool
  "user_team_id":        "team_1",       // optional — defaults to team_1 for team_adjusted_value
  "budget_by_team_id":  { "team_1": 200 }, // optional — per-team $ remaining
  "minors":              [],              // optional — [{ team_id, players[] }]
  "taxi":                []               // optional
}
Response

Response header X-Request-Id echoes your id or a generated UUID. OpenAPI: repo openapi/openapi.yaml.

{
  "engine_contract_version": "1",  // API contract id — detect drift vs Draft
  "valuation_model_version": "amethyst-api@1.0.0",  // or git SHA in production image
  "inflation_factor":      1.12,    // >1.0 = inflated market
  "inflation_model":       "replacement_slots_v2",
  "total_budget_remaining": 2184,
  "pool_value_remaining":   1948,
  "players_remaining":      496,
  "recommended_bid_note": "recommended_bid is a phase-aware model clearing target (star floors, pitcher dampening, isotonic smoothing)—a bidding guide, not a prediction of the winning hammer price; room behavior can diverge materially.",
  "team_adjusted_value_note": "team_adjusted_value scales adjusted_value by roster need, dollars per open slot vs league peers, remaining-slot scarcity, and replacement drop-off for eligible slots; when the league snapshot is symmetric (no auction picks, no keeper/minors/taxi off-board ids, equal per-team budgets in budget_by_team_id when provided, equal rostered counts per team), it equals adjusted_value",
  "phase_indicator": "early",
  "user_team_id_used": "team_1",
  "valuations": [{
    "player_id":      "660271",
    "name":           "Shohei Ohtani",
    "position":       "DH",
    "tier":           1,
    "baseline_value": 58,
    "adjusted_value": 65,        // market marginal value
    "recommended_bid": 72.5,      // phase-aware clearing estimate
    "team_adjusted_value": 78.2, // need + $/slot vs league + replacement drop-off
    "edge": 5.7,               // team_adjusted_value − recommended_bid
    "indicator":      "Steal",    // "Steal" | "Reach" | "Fair Value"
    "baseline_components": {
      "scoring_format": "5x5",
      "projection_component": 4.2,
      "scarcity_component": 0.1
    },
    "scarcity_adjustment": 0,       // embedded in baseline_value
    "inflation_adjustment": 7        // adjusted − baseline
  }],
  "calculated_at": "2026-03-07T17:39:19Z"
}

If post-calculation sanity checks fail, the API returns 422 with the same { errors: [...] } shape as Zod validation — no valuations payload. This route is not Redis-cached (fresh prices after catalog sync). Request body limit 1 MB. Per-key rate limits are configurable (RATE_LIMIT_* env vars; see OpenAPI / README).

POST /valuation/player Single-player valuation using full league context

Use when the UI needs one player card only. Uses the same valuation pipeline and inflation math as /valuation/calculate, then returns one player under player.

Request
{
  "player_id": "660271",
  "schema_version": "1.0.0",
  "roster_slots": [{ "position": "OF", "count": 3 }],
  "scoring_categories": [{ "name": "HR", "type": "batting" }],
  "total_budget": 260,
  "num_teams": 12,
  "user_team_id": "team_1",
  "drafted_players": []
}
Response
{
  "engine_contract_version": "1",
  "inflation_factor": 1.12,
  "players_remaining": 496,
  "valuations": [{ /* single row */ }],
  "player": {
    "player_id": "660271",
    "name": "Shohei Ohtani",
    "baseline_value": 58,
    "adjusted_value": 65,
    "recommended_bid": 72.5,
    "team_adjusted_value": 78.2,
    "edge": 5.7,
    "indicator": "Steal"
  }
}

Errors: 400 when player_id is missing, 404 when the player is not in the current valuation pool (drafted, out-of-scope, or unknown id).

POST /catalog/batch-values Baseline value / tier / adp from engine catalog

Use from the Draft app to merge engine baselines with MLB player bios. Same x-api-key as other Brain routes. Cached 120s per body hash when Redis is available. Higher default rate ceiling than valuation; still tunable via RATE_LIMIT_CATALOG_*.

Request
{
  "player_ids":     ["660271", "592450"],
  "league_scope":   "Mixed"
}
Response
{
  "engine_contract_version": "1",
  "players": [{
    "player_id": "660271",
    "name":      "Shohei Ohtani",
    "position":  "DH",
    "team":      "LAD",
    "value":     58,
    "tier":      1,
    "adp":       1
  }]
}
POST /analysis/scarcity Positional depth scores + monopoly warnings

Call after each pick round. Surfaces scarce positions and category monopoly risks.

Request
{
  "drafted_players":     [ /* same DraftedPlayer shape as above */ ],
  "scoring_categories":  [{ "name": "SV", "type": "pitching" }],
  "position":           "SS",    // optional — filter to one position
  "num_teams":          12,
  "league_scope":       "Mixed"
}
Response
{
  "positions": [{
    "position":          "SS",
    "elite_remaining":   2,     // tier-1 still available
    "mid_tier_remaining":5,
    "total_remaining":   18,
    "scarcity_score":    74,    // 0–100, higher = more scarce
    "alert":             "Only 2 elite SS remain"
  }],
  "monopoly_warnings": [{
    "team_id":           "team_3",
    "category":          "SV",
    "share_percentage":  62,
    "message":           "team_3 controls 62% of SV"
  }]
}
POST /simulation/mock-pick ADP + roster-need heuristic pick predictions

Powers AI opponent picks in the Practice Draft environment. Not cached — every call returns fresh predictions based on state.

Request
{
  "pick_order":   ["team_1", "team_2"],   // team_ids in draft order
  "roster_slots": [{ "position": "SP", "count": 5 }],
  "league_scope": "Mixed",
  "teams": [{
    "team_id":         "team_1",
    "budget_remaining": 180,       // optional
    "roster":          [ /* DraftedPlayer[] already on this team */ ]
  }],
  "available_player_ids": ["695243", /* ... */]  // optional explicit pool
}
Response
{
  "predictions": [{
    "team_id":     "team_1",
    "pick_position": 1,
    "confidence":  0.82,              // 0–1
    "predicted_player": {
      "player_id": "660271",
      "name":      "Shohei Ohtani",
      "position": "DH",
      "adp":       1,
      "reason":    "Team needs DH (urgency 90%); best available by ADP."
    }
  }]
}
GET /signals/news Injuries, trades, promotions, demotions from MLB Transactions

Surface player news in the draftroom UI. Cached 15 minutes — cheap to call on every page load.

Query Parameters
# days     — lookback window (default: 7)
# signal_type — filter: injury | role_change | trade | demotion | promotion

GET /signals/news?days=3&signal_type=injury
Response
{
  "signals": [{
    "player_id":     "695243",     // present when matched to DB player
    "player_name":   "Player Name",
    "signal_type":   "injury",
    "severity":      "high",       // "low" | "medium" | "high"
    "description":   "Placed on 10-day IL",
    "effective_date":"2026-03-07",
    "source":        "MLB Transactions API"
  }],
  "count": 4
}

Player ID Contract

All player_id fields are the numeric MLB Stats API player ID cast to a string. Use String(player.id) from any MLB Stats API response.

// ✅ correct
player_id: String(player.id)   // e.g. "660271"

// ❌ wrong
player_id: player._id          // MongoDB ObjectId — not recognized

Error Responses

StatusMeaningAction
401Missing or invalid x-api-keyCheck header is present and key matches issued value
403API key deactivatedContact Amethyst Industries to reactivate
400Validation errorRead error field — missing required field
5xxServer errorDegrade gracefully — draft should continue

Caching

EndpointTTLKey
/valuation/calculateNo cacheAlways recomputed
/valuation/playerNo cacheAlways recomputed
/analysis/scarcity120sHash of request body
/simulation/mock-pickNo cacheStateful per call
/signals/news900sDate range + signal type

Licensing

Amethyst Engine is a generalized Sports Data as a Service (SDaaS) platform. The core API is available for commercial licensing under a revenue-share model. Licensee-specific data instances and strategic configurations remain private and isolated.

License Tiers

TierUse CaseFeaturesPricing
free Evaluation & prototyping All endpoints, rate-limited Contact us
standard Production applications Full access, standard rate limits, usage reporting Revenue share — contact us
premium High-volume & enterprise Elevated rate limits, priority support, custom league scope extensions Custom — contact us

Revenue Share Model

Commercial licenses are structured as a percentage of net revenue generated by your application through use of the Amethyst Engine API. This aligns our incentives with your product's success.

Model
5%
of net licensing revenue
Term
5 yr
from first commercial sale
Under the Reuse Clause of the Amethyst Engine license agreement, founding customers receive a 5% royalty on net licensing revenue for a period of five years following the first commercial sale. This royalty is calculated and reported quarterly based on cumulative API key usage tracked per licensee.

Infrastructure & Maintenance

ComponentStackNotes
API RuntimeNode.js 20 + Express 5 on AWS App RunnerManaged container, auto-scaling
DatabaseMongoDB AtlasDocument-based player & key schemas
CacheRedisLow-latency live-draft response caching
Player DataMLB Stats API syncDaily refresh during season (Mar–Oct)
MonitoringAWS App Runner health checksAutomatic restart on failure

Get a License

Interested in licensing the Amethyst Engine for your fantasy sports product?

The API is sport-agnostic and architected for plug-and-play expansion into additional domains. Licensing terms are negotiated per application. Reach out to discuss your use case, expected volume, and integration timeline.

licensing@amethystindustries.com

Dashboard

Use Product docs for reference and licensing. Try the API works with your key alone. Sign in only when you need API keys or this dashboard home.

Keys snapshot

Summary of keys on your developer account. Full table and issuance live under API keys.

API usage

Enter an API key to view usage statistics, tier, scope, and developer account information. Usage is tracked per key and updated in real time.

Your key is used only to fetch its usage metadata. It is not stored or logged.

Key
Owner
Active
Total requests
Counted on protected API calls
Tier
Last used
Key created

Playground — sample draft

Non-billing experimentation: five presupplied league / draft context JSON files (Activity #9 style) live under /fixtures/checkpoints/. Pick a checkpoint to preview context, copy it for your own tools, then enter one player_id (MLB id string, or a synthetic id from fixture) to call POST /valuation/player — same body as /valuation/calculate plus player_id. See docs/draft-2026-xlsx-mapping.md for how fixtures were built.

Fixture & run

Loading fixtures…

League context (read-only) Checkpoint JSON from /fixtures/checkpoints/

          

Must still be in the undrafted pool for that checkpoint (not on a roster as keeper-only off-board rules apply).

Response

Choose a checkpoint, enter player_id and x-api-key, then run.