SportFeeds API Documentation

Real-time, verified sports posts from X — filtered by league, team, player, game, or geo. No X API key required: licensing and compliance are handled for you.

Quick Start
Get your first API response in under a minute
curl -H "Authorization: YOUR_API_KEY" "https://api.sportfeeds.com/v1/posts?leagues=NFL"
Sign up for an API keyFree plan includes 200 API calls / month
Real-time Feeds

Posts indexed within seconds of going live.

Verified Data

Tagged with players, teams, leagues, and games.

Low Latency

Sub-second p95 from cached endpoints.

Authorization

All SportFeeds API endpoints require authentication via the Authorization header.

Authentication Method
API Key via Authorization header
curl -H "Authorization: YOUR_API_KEY" "https://api.sportfeeds.com/v1/posts?leagues=NFL"

Key delivery modes

Each key is fixed to one delivery mode when it is created, so a single account can run Direct and Sync side by side. Keys created before delivery modes shipped stay flexible and behave exactly as they always have — nothing to migrate.

Direct
Any plan.

Built for live, per-end-user requests. Call whenever you need to — there is no cadence gate. Maximum 100 items per call; use `page` for more.

Sync
Paid plans only, and the Sync terms must be accepted when the key is created.

Built for scheduled pulls into your own store. Polls are paced to your plan's sync interval (a poll that arrives early returns 429 SYNC_INTERVAL_NOT_ELAPSED). Maximum 1000 items per call, and paging through a poll you already started is not cadence-checked. Sync keys can also request the optional `include_geo` block.

Grandfathered
Every key created before delivery modes shipped.

Flexible — behaviour is unchanged and still follows your account's original delivery setting. Nothing needs to be migrated. Create a new key if you want a mode-fixed Direct or Sync key.

Manage your keys, and choose a mode for new ones, from the Dashboard.

For AI Agents

/agents.md is a complete, agent-ready integration guide: authentication, every parameter, league and sport codes, ID translation, the engagement rating, error handling, quota hygiene, polling patterns, a ready-made tool schema, and TypeScript/Python reference clients. Drop it into your repo and a coding agent can integrate SportFeeds without further instruction.

Claude Code
Pull the guide into the repo, then reference it from CLAUDE.md.
1. Fetch the guide
mkdir -p docs && curl -s https://sportfeeds.com/agents.md \
  -o docs/sportfeeds-agents.md
2. Append to CLAUDE.md
## SportFeeds API
Full integration guide: @docs/sportfeeds-agents.md

- Base URL: https://api.sportfeeds.com/v1 — the ONLY content endpoint is GET /posts.
- Auth: header "Authorization: Bearer $SPORTFEEDS_API_KEY". Server-side only.
- List params are PLURAL and comma-separated: leagues=, sports=, teams=, players=, sources=.
- Never call /posts/leagues, /posts/teams, /posts/players, /posts/games,
  /posts/nearby or /posts/trending — they return 410.
- "football" means soccer; the NFL game is "americanfootball".
- Poll incrementally with since=<created_at of newest post seen>. Never re-page history.
- If a response has a non-empty warnings[] array, the query is wrong — fix it, don't ship it.

Then add SPORTFEEDS_API_KEY=… to your .env (and .gitignore it).

Cursor / Windsurf
The guide is already written as agent rules — save it as one.
Install as a project rule
mkdir -p .cursor/rules && curl -s https://sportfeeds.com/agents.md \
  -o .cursor/rules/sportfeeds.md

For Windsurf, write it to .windsurfrules instead.

Custom GPT / Assistants API
Actions schema plus code-only instructions.

1. Add openapi.json as the action schema.

2. Set authentication to API Key → Bearer.

3. Paste the parameter and league/sport code sections of agents.md into the instructions so the model sends codes, not names.

Any tool-calling framework
One tool covers every retrieval mode.

Register the sportfeeds_get_posts JSON schema from agents.md and paste the parameter reference, code lists and rating scale into the system prompt.

Mode is inferred from the parameters, so the model should make one combined call — never fan out across leagues, teams and media types.

Video playback & design practices

Raw X video URLs are hotlink-protected: they often work in preview but fail in incognito, third-party embeds, or mobile webviews. Route every video through a small proxy on your own domain that forwards the request with X's expected headers (Referer: https://x.com/), and cache the responses on your CDN. SportFeeds does not host a customer-facing media proxy.

https://your-domain.com/video-proxy?url=%3Cmedia.url%3E

Always render the X icon in the top-right of a post card linking to the original post, keep author attribution, and link the timestamp to post_url. See the full guide in agents.md §10.

Rules agents get wrong most often
  • List parameters are plural: leagues, sports, teams, players, sources.
  • football means soccer; the NFL game is americanfootball.
  • Pass league/sport codes only — never league names or provider IDs.
  • Unknown parameters are ignored but return a warnings[] array and an X-SportFeeds-Warning header. Treat that as a build error.
  • Poll with since; responses cache for 60s, so faster polling only burns quota.
  • 400 / 401 / 402 / 410 are terminal — retry only 429, 503 and 5xx, with backoff.
GET

/posts

Unified

One endpoint, six modes. Filter by league, team, player, game, geo, or omit everything to get trending. Mode is auto-selected by which params you pass.

Overview

Endpoint
GET https://api.sportfeeds.com/v1/posts
Query Modes
Trending
GET /v1/posts
By League
GET /v1/posts?leagues=NFL,NBA
By Team(s)
GET /v1/posts?id_type=espn_guid&teams=...,...
By Player(s)
GET /v1/posts?id_type=espn_guid&players=...,...
By Game
GET /v1/posts?id_type=espn_guid&match=teamA,teamB&start_time=2024-01-15T20:00:00Z
Nearby (Geo)
GET /v1/posts?lat=40.71&lng=-74.00&radius_km=50
Parameters
ParameterRequiredTypeExampleDescription
leagues
OptionalArray<String> (CSV)NFL,NBAComma-separated league codes, or `ALL`. Supported codes: NFL, NCAAFB, NBA, WNBA, NCAAMB, MLB, NHL, PGA, GOLF, EPL, MLS, FIFA, SOCCER, LALIGA, BUNDESLIGA, SERIEA, LIGUE1, UCL, SAPREMIERSHIP, ISL, CRICKET, IPL, SA20, RUGBY, URC, SUPERRUGBY, SIXNATIONS, RWC, MMA, UFC, PFL, DPWORLDTOUR, SUNSHINETOUR. Case-insensitive.
sports
OptionalArray<String> (CSV)football,basketballFilter to one or more parent sports: americanfootball, football, basketball, baseball, hockey, golf, cricket, rugby, mma, tennis, boxing, motorsport, athletics, cycling, wrestling. Case-insensitive. `football` means association football (soccer) — the NFL/NCAA game is `americanfootball`. `soccer` is still accepted as an alias for `football`. Returns posts across all leagues under those sports. Combine with `leagues` to narrow further. Invalid values return a 400 error.
teams
OptionalArray<String> (CSV)s:40~l:46~t:13Team IDs (≤10). Pair with `id_type`.
players
OptionalArray<String> (CSV)1f6592b3-...Player IDs (≤100). Pair with `id_type`.
id_type
OptionalStringespn_guidID system used by `teams`/`players` (espn_guid, espn_uid, sportradar, code, ...)
match
OptionalStringteamA,teamBTwo team IDs comma-separated; combined with `start_time` to query a specific game.
start_time
OptionalISO timestamp2024-01-15T20:00:00ZGame start time (paired with `match`).
include_pregame
OptionalBooleantrueInclude pregame posts when querying a game.
lat
OptionalFloat40.7128Latitude (with `lng` and optionally `radius_km`).
lng
OptionalFloat-74.0060Longitude.
radius_km
OptionalInteger50Search radius in km (default 145, max 4830).
category
OptionalStringnewsFilter by post category: news, highlight, other.
news_type
OptionalString (CSV)injury,tradeFilter news posts by type: injury, trade, signing, cut, suspension, contract_extension, roster_move, return_from_injury, retirement, coaching_change, draft, other.
news_status
OptionalStringverifiedFilter news posts by status: verified or rumor.
news_origin
OptionalStringbreakingFilter news posts by origin: breaking (first to report) or relaying (re-reporting others).
include_news
OptionalBooleantrueInclude the news classification fields (category, news_type, news_status, news_origin, news_attribution) on each post. Automatically enabled when any news filter is used.
media_type
OptionalStringvideoFilter by media type: photo, video, gif, animated_gif, none
aspect_ratio
OptionalStringlandscapeFilter by aspect ratio: landscape, portrait, square
min_score
OptionalInteger5Minimum engagement score (0–10). 7+ = top performing, 8–10 = viral. Each post's rating is returned as `score`.
min_duration
OptionalInteger (ms)10000Minimum video duration in milliseconds.
highlight
OptionalBooleantrueReturn only highlight clips.
has_player
OptionalBooleantrueReturn only posts with at least one tagged player.
include_geo
OptionalBooleantrueSync keys only. Adds a `geo` object to each post — `allowed_countries` (ISO 3166-1 alpha-2 codes cleared for that source), `blocked_countries`, and `updated_at`. Omitted unless requested; ignored on Direct and legacy keys.
custom_sources
OptionalBooleantrueInclude posts from your custom sources. Available on paid plans, within your plan's custom source allowance.
sources
OptionalArray<String> (CSV)FIFAWorldCup,SkySportsReturn posts only from these sources (max 500). Accepts X.com handles (case-insensitive) or numeric X.com account IDs. Public sources are open to all; private custom sources require them to be enabled on your account.
user_location
OptionalStringUSEnd-user region as an ISO 3166-1 alpha-2 country code (e.g. US, ZA). Returns only content from sources cleared for viewing in that region; sources not marked viewable there are excluded. An invalid code returns a 400 error.
sort
OptionalStringrecentSort order: recent, top, trending.
since
OptionalISO timestamp2024-01-15T00:00:00ZReturn posts created after this timestamp.
since_id
OptionalString1879726815913861526Return posts created after this post id.
limit
OptionalInteger10Items per page. Default 20. Maximum 100 on Direct and legacy keys; keys issued as Sync accept up to 1000. Use page to retrieve more.
page
OptionalInteger1Page number (1-based). On a Sync key, page 1 (or no page) starts a poll and stamps your cadence; page 2+ requested within your sync interval continues that same poll and is not cadence-checked. A continuation requested after the interval has elapsed counts as a new poll.
Data Points

AttributeParent ElementTypeDescription
iditems[]StringNative X post id.
post_urlitems[]StringDirect URL to the post on X.
textitems[]StringPost body text.
created_atitems[]ISO timestampOriginal post timestamp (UTC).
media_typeitems[]Stringvideo | photo | gif | animated_gif | none
mediaitems[]Array<MediaObject>Attached media; see Media Object below.
scoreitems[]IntegerEngagement rating 0–10, built from interaction checkpoints at 1m/5m/15m/30m/1h/6h/12h after publishing. 7+ = top performing, 8–10 = viral. Pair with `min_score` to filter server-side.

Errors
StatusCodeMeaning & recommended action
400INVALID_PARAMETERBad / missing param. Validate input before retrying.
400SINCE_ID_NOT_FOUNDReference post unavailable. Drop `since_id` and retry.
401UNAUTHORIZEDMissing or invalid API key.
403FORBIDDENEndpoint or league not on your plan.
404NOT_FOUNDA requested source could not be resolved. Team and player filters that match nothing are not an error — they return HTTP 200 with an empty `items` array.
429RATE_LIMITEDBurst limit exceeded. Back off.
429USAGE_LIMIT_REACHEDMonthly call cap reached. Calls are paused until your next billing period — no overage is billed. Includes used and limit.
429SYNC_INTERVAL_NOT_ELAPSEDSync keys only: you polled before your interval elapsed. Response includes poll_interval_seconds, retry_after_seconds and next_allowed_at, plus a Retry-After header. A small buffer (10s on intervals up to 60s, 30s above) absorbs scheduler jitter. Paging through a poll you already started (page 2+ inside the interval) is never blocked.
500INTERNAL_ERRORRetry with exponential backoff.

Try it out

Sign in to test API calls with your key.

Sign In / Get Started Free

Example Response

{
"pagination": {
"page": 1,
"limit": 10,
"has_next": true,
"has_prev": false
},
"items": [
{
"id": "1879726815913861526",
"post_url": "https://x.com/NFLonFOX/status/1879726815913861526",
"text": "Patrick Mahomes throws his 3rd TD of the game! 🏈",
"created_at": "2024-01-15T20:45:00Z",
"media_type": "video",
"score": 8,
"media": [
{
"type": "video",
"url": "https://video.twimg.com/...mp4",
"preview_image_url": "https://pbs.twimg.com/...jpg",
"width": 1280,
"height": 720,
"duration_ms": 24500
}
],
"author": {
"username": "NFLonFOX",
"name": "NFL on FOX",
"profile_image_url": "https://pbs.twimg.com/profile_images/...jpg",
"verified": true
},
"players": [
{
"espn_guid_id": "1f6592b3-ff53-d321-8dc5-6038d48c1786",
"sportfeeds_id": 90000001,
"name": "Patrick Mahomes"
}
],
"teams": [
{
"espn_guid_id": "s:20~l:28~t:12",
"sportfeeds_id": 90000050,
"name": "Kansas City Chiefs"
}
]
}
]
}
GET

/account/information

Free

Retrieve your company information, billing cycle, and current API usage. Free — call as often as needed.

Example Response
{
  "company": { "name": "Acme Sports Inc", "plan": "paid", "subscription_status": "active" },
  "billing_cycle": {
    "current_period_start": "2026-02-07T20:16:36+00:00",
    "current_period_end":   "2026-03-07T20:16:36+00:00"
  },
  "usage": { "current_calls": 12450 }
}

Sign in to test this endpoint.

Sign In
GET

/account/x-ids

Returns post IDs that should be deleted from your storage to remain compliant with the X platform's developer agreement. Recommended polling cadence depends on your plan (daily / weekly / monthly).

Example Response
{
  "ids_to_delete": ["1846572934857291245", "1846572934857291246"],
  "as_of": "2026-04-30T05:00:00Z"
}

Sign in to test this endpoint.

Sign In
GET

/account/sources

Returns every source your account can query, tagged as default (globally available) or custom (added to your company). Each source includes a geo_availability block listing ISO 3166-1 alpha-2 country codes where the source is explicitly viewable or blocked. Includes a counts block for quick verification. Available on paid plans, which see their own custom sources; enterprise accounts also receive the full default catalogue. Sandbox accounts get a 403.

A source's source_type can change from custom to default over time. When a customer-added handle proves broadly useful, SportFeeds promotes it into the standard catalog: posts keep flowing, the response shape is unchanged, and the handle stops counting toward your custom source limit. After promotion its sport, league and geo settings are managed by SportFeeds. Treat source_type as a current-state field, not a stable identifier.

Enterprise only

This endpoint requires an active Enterprise subscription. Contact sales to enable access.

Example Response
{
  "ok": true,
  "counts": { "total": 185, "default": 177, "custom": 8 },
  "sources": [
    {
      "platform": "X",
      "username": "acme_custom",
      "name": "Acme Custom Feed",
      "type": null,
      "league": "multiple",
      "source_type": "custom",
      "geo_availability": {
        "viewable": ["US", "CA"],
        "blocked": []
      }
    },
    {
      "platform": "X",
      "username": "nba",
      "name": "NBA",
      "type": "league",
      "league": "NBA",
      "source_type": "default",
      "geo_availability": {
        "viewable": [],
        "blocked": ["ZA"]
      }
    }
  ]
}

Sign in to test this endpoint.

Sign In
GET

/ids

One endpoint for all ID lookups. Pass entity to choose teams, players, leagues, or posts.

List all teams in a league. Returned alphabetically by location. Auto-paginated up to 1,000 per call.

GET /ids?entity=teams&league=NFL&reference_id=sportradar_id
Parameters
NameTypeRequiredDescription
entitystring
Yes
One of: teams, players, leagues, posts.
leaguestring
Yes
League code (NFL, NBA, MLB, NHL, PGA).
reference_idstringNoExternal id column to include in each item. Response key matches the value you pass. Allowed: sportradar_id, espn_id, sportsdataio_id, nba_id, yahoo_dfs_id, apisports_id, grid_id, code, external_id.
lookupstringNoReturn only the single team matching this value (resolved against reference_id if provided, otherwise sportfeeds_id).
Example Response
{
  "ok": true,
  "count": 32,
  "items": [
    {
      "sportfeeds_id": 12000045,
      "location": "Atlanta",
      "name": "Falcons",
      "conference": null,
      "division": null,
      "league": "NFL",
      "sportradar_id": "e6aa13a4-0055-48a9-bc41-be28dc106929"
    }
  ]
}

Sign in to test this endpoint.

Sign In