Fangorithm API

Version v1 · MLB Data · Season 2026-regular

Overview

The Fangorithm API is an extension of fangorithm.com. To get started, create an account and visit your account settings — an API key is generated for you automatically.

We also support the x402 protocol for pay-per-request access without an account. See the x402 section below for details.

For Agents & LLMs

This API is machine-discoverable. Point an agent at any of these:

GET/openapi.jsonOpenAPI 3.1 contract
POST/mcpMCP server (Streamable HTTP, JSON-RPC 2.0) — requires an API key
GET/llms.txtPlain-text overview for LLMs
GET/.well-known/api-catalogRFC 9727 discovery linkset

Authentication

All endpoints (except /health) require an API key via the X-API-Key header.

curl -H "X-API-Key: YOUR_KEY" https://api.fangorithm.com/v1/mlb/teams

x402

We support the x402 protocol for pay-per-request access with stablecoins — no account or API key required. Requests are settled on-chain in USDC via an x402 facilitator.

Supported Networks

NetworkChain IDAsset
Base mainneteip155:8453USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Solana mainnetsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpUSDC EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

Pricing

Prices are in USDC base units (6 decimals) — 1000 = $0.001, 5000 = $0.005.

RoutePrice
/v1/mlb/players, /v1/mlb/players/:id$0.001
/v1/mlb/players/:id/stats, /v1/mlb/players/:id/splits$0.002
/v1/mlb/teams, /v1/mlb/teams/:id, /v1/mlb/teams/:id/roster$0.001
/v1/mlb/teams/:id/stats, /v1/mlb/teams/:id/splits$0.002
/v1/mlb/games, /v1/mlb/games/:id$0.001
/v1/mlb/games/:id/boxscore, /v1/mlb/games/:id/play-by-play$0.005
/v1/mlb/standings, /v1/mlb/park-factors, /v1/mlb/park-factors/:id, /v1/mlb/daily-matchups$0.001
/v1/mlb/players/:id/game-logs$0.005

Payments must settle within 60 seconds. x402 requests bypass the tiered rate limit — each call is paid individually.

Request Flow

1. Call an endpoint without an X-API-Key or PAYMENT-SIGNATURE header. The server responds with 402 Payment Required and a JSON body describing accepted payment options:

curl -i https://api.fangorithm.com/v1/mlb/players/12345/stats
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: <base64 of body>

{
  "x402Version": 1,
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "maxAmountRequired": "2000",
      "resource": "/v1/mlb/players/12345/stats",
      "description": "Get MLB player season stats",
      "payTo": "0x37459795E8f7B289c3cD646Ba92544a8EC433872",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "maxTimeoutSeconds": 60
    },
    {
      "scheme": "exact",
      "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
      "maxAmountRequired": "2000",
      "resource": "/v1/mlb/players/12345/stats",
      "description": "Get MLB player season stats",
      "payTo": "5C7ARtmtA2jVrgphoZocTacs7fa175frEVbWnGMGNtj3",
      "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "maxTimeoutSeconds": 60
    }
  ],
  "error": "Payment required. Include a PAYMENT-SIGNATURE header or an X-API-Key header."
}

2. Sign a payment payload matching one of the accepts entries, base64-encode it, and retry the request with a PAYMENT-SIGNATURE header. On success, the response includes a PAYMENT-RESPONSE header with the settled transaction details.

Node.js (x402-fetch)

The easiest integration uses the official x402-fetch library, which wraps fetch and handles the 402 challenge/retry automatically with a viem wallet.

import { wrapFetchWithPayment } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY);
const fetchWithPayment = wrapFetchWithPayment(fetch, account);

const res = await fetchWithPayment(
  "https://api.fangorithm.com/v1/mlb/games/20260615-LAD-SF/boxscore"
);
const data = await res.json();
console.log(data);

// Decode the settlement header if you want the on-chain tx
const settled = JSON.parse(atob(res.headers.get("PAYMENT-RESPONSE")));
console.log("Paid by:", settled.payer);

cURL (manual)

# 1) Get the challenge
curl -s https://api.fangorithm.com/v1/mlb/players/545361 | jq .

# 2) Build & sign a payment off-chain, base64 it, then:
curl -H "PAYMENT-SIGNATURE: $SIGNED_PAYLOAD_B64" \
     https://api.fangorithm.com/v1/mlb/players/545361
Payment errors return 402 with code PAYMENT_INVALID, unsupported networks return 400 with UNSUPPORTED_NETWORK, and facilitator outages return 502 with PAYMENT_VERIFICATION_FAILED or PAYMENT_SETTLEMENT_FAILED.

Public Payment Wallets

All x402 payments settle to the addresses below. These are the same payTo values returned in the 402 challenge — always verify against the live response before signing.

NetworkAddress
Base (EVM)0x37459795E8f7B289c3cD646Ba92544a8EC433872
Solana5C7ARtmtA2jVrgphoZocTacs7fa175frEVbWnGMGNtj3

Rate Limits

TierRequests / minute
Free3
Member100

Rate limit info is returned in the RateLimit-Limit response header.

Players

GET /v1/mlb/players List players
teamFilter by team abbreviation?team=NYY
positionFilter by position (comma-separated)?position=SS,2B
seasonSeason identifier?season=2026-regular
sortSort field and direction?sort=name:asc
limitResults per page (max 200)?limit=25
offsetPagination offset?offset=50
GET /v1/mlb/players/:id Get a player by ID
GET /v1/mlb/players/:id/stats Player stats
GET /v1/mlb/players/:id/splits Player splits
GET /v1/mlb/players/:id/game-logs Per-game logs for the current season
:idMLB ID only — the player's mlb_id/v1/mlb/players/660271/game-logs
seasonSeason identifier (current season only)?season=2026-regular
limitEntries per page?limit=25
offsetPagination offset?offset=50

Entries are sorted ascending by game date and refreshed daily. Per-pitch at-bat detail is served by /v1/mlb/games/:id/play-by-play.

Teams

GET /v1/mlb/teams List teams
sortSort field and direction?sort=name:asc
limitResults per page?limit=25
offsetPagination offset?offset=10
GET /v1/mlb/teams/:id Get a team by ID or abbreviation
GET /v1/mlb/teams/:id/stats Team season stats
GET /v1/mlb/teams/:id/roster Team roster
GET /v1/mlb/teams/:id/splits Team splits

Games

GET /v1/mlb/games List games (filter required)
dateRequired* Date in YYYYMMDD?date=20260615
teamRequired* Team abbreviation?team=LAD
statusFilter by status?status=COMPLETED
seasonSeason identifier?season=2026-regular

* At least one of date or team is required.

Valid statuses: UNPLAYED, LIVE, COMPLETED, COMPLETED_PENDING_REVIEW

GET /v1/mlb/games/:id Get a game by ID
GET /v1/mlb/games/:id/boxscore Game boxscore
GET /v1/mlb/games/:id/play-by-play Play-by-play data

Standings

GET /v1/mlb/standings League standings (current season)
seasonSeason identifier (current season only)?season=2026-regular
sortSort field and direction?sort=standings.winPct:desc
limitResults per page?limit=15
offsetPagination offset?offset=15

Returns all 30 teams sorted by win percentage, each with standings (wins, losses, winPct, gamesBack, run differential) and record (streak, home/away/division/last-ten splits). Group by divisionId / conferenceId client-side. Refreshed daily.

Park Factors

GET /v1/mlb/park-factors List park factors for all venues
seasonSeason identifier?season=2026-regular
teamFilter by home-team abbreviation (comma-separated)?team=COL,BOS
sortSort field and direction?sort=parkFactors.runs:desc
limitResults per page?limit=30
offsetPagination offset?offset=0
GET /v1/mlb/park-factors/:id Get park factors by venue ID or home-team abbreviation

Factors are normalized indexes (100 = league average) for runs, hits, home runs, and more, alongside per-game counting stats. Refreshed daily.

Daily Matchups

GET /v1/mlb/daily-matchups Probable pitchers and lineups for a date
dateDate in YYYYMMDD — defaults to today (UTC); pass explicitly to avoid late-night UTC rollover?date=20260615
teamFilter by team abbreviation (comma-separated, matches home or away)?team=LAD
sortSort field and direction?sort=gameTime:asc
limitResults per page?limit=15
offsetPagination offset?offset=0

Each matchup includes venue, probable pitchers, and batting-order lineups with a lineupStatus of projected or official. Synced twice daily — official lineups land in the evening (UTC) refresh.

Response Format

All responses return JSON with this structure:

{
  "version": "v1",
  "timestamp": "2026-06-15T12:00:00.000Z",
  "data": { ... },
  "meta": { "season": "2026-regular" },
  "pagination": {
    "total": 150,
    "limit": 50,
    "offset": 0,
    "hasNext": true,
    "hasPrev": false,
    "nextOffset": 50,
    "prevOffset": null
  }
}

Errors

{
  "version": "v1",
  "timestamp": "...",
  "error": {
    "code": "NOT_FOUND",
    "message": "Player not found."
  }
}

HTTP Status Codes

400Bad request / invalid params
401Missing or invalid API key
404Resource not found
429Rate limit exceeded
500Internal server error

Error Codes

INVALID_API_KEYKey not recognized
RATE_LIMIT_EXCEEDEDToo many requests
FILTER_REQUIREDMissing required filter
NOT_FOUNDRoute or resource missing

Health Check

GET PUBLIC /health No auth required