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.
curl -H "Authorization: YOUR_API_KEY" "https://api.sportfeeds.com/v1/posts?leagues=NFL"
Posts indexed within seconds of going live.
Tagged with players, teams, leagues, and games.
Sub-second p95 from cached endpoints.
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.
mkdir -p docs && curl -s https://sportfeeds.com/agents.md \ -o docs/sportfeeds-agents.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).
mkdir -p .cursor/rules && curl -s https://sportfeeds.com/agents.md \ -o .cursor/rules/sportfeeds.md
For Windsurf, write it to .windsurfrules instead.
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.
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.
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.
- List parameters are plural:
leagues,sports,teams,players,sources. footballmeans soccer; the NFL game isamericanfootball.- Pass league/sport codes only — never league names or provider IDs.
- Unknown parameters are ignored but return a
warnings[]array and anX-SportFeeds-Warningheader. 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.
/posts
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
GET https://api.sportfeeds.com/v1/postsGET /v1/postsGET /v1/posts?leagues=NFL,NBAGET /v1/posts?id_type=espn_guid&teams=...,...GET /v1/posts?id_type=espn_guid&players=...,...GET /v1/posts?id_type=espn_guid&match=teamA,teamB&start_time=2024-01-15T20:00:00ZGET /v1/posts?lat=40.71&lng=-74.00&radius_km=50| Parameter | Required | Type | Example | Description |
|---|---|---|---|---|
leagues | Optional | Array<String> (CSV) | NFL,NBA | Comma-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 | Optional | Array<String> (CSV) | football,basketball | Filter 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 | Optional | Array<String> (CSV) | s:40~l:46~t:13 | Team IDs (≤10). Pair with `id_type`. |
players | Optional | Array<String> (CSV) | 1f6592b3-... | Player IDs (≤100). Pair with `id_type`. |
id_type | Optional | String | espn_guid | ID system used by `teams`/`players` (espn_guid, espn_uid, sportradar, code, ...) |
match | Optional | String | teamA,teamB | Two team IDs comma-separated; combined with `start_time` to query a specific game. |
start_time | Optional | ISO timestamp | 2024-01-15T20:00:00Z | Game start time (paired with `match`). |
include_pregame | Optional | Boolean | true | Include pregame posts when querying a game. |
lat | Optional | Float | 40.7128 | Latitude (with `lng` and optionally `radius_km`). |
lng | Optional | Float | -74.0060 | Longitude. |
radius_km | Optional | Integer | 50 | Search radius in km (default 145, max 4830). |
category | Optional | String | news | Filter by post category: news, highlight, other. |
news_type | Optional | String (CSV) | injury,trade | Filter news posts by type: injury, trade, signing, cut, suspension, contract_extension, roster_move, return_from_injury, retirement, coaching_change, draft, other. |
news_status | Optional | String | verified | Filter news posts by status: verified or rumor. |
news_origin | Optional | String | breaking | Filter news posts by origin: breaking (first to report) or relaying (re-reporting others). |
include_news | Optional | Boolean | true | Include 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 | Optional | String | video | Filter by media type: photo, video, gif, animated_gif, none |
aspect_ratio | Optional | String | landscape | Filter by aspect ratio: landscape, portrait, square |
min_score | Optional | Integer | 5 | Minimum engagement score (0–10). 7+ = top performing, 8–10 = viral. Each post's rating is returned as `score`. |
min_duration | Optional | Integer (ms) | 10000 | Minimum video duration in milliseconds. |
highlight | Optional | Boolean | true | Return only highlight clips. |
has_player | Optional | Boolean | true | Return only posts with at least one tagged player. |
include_geo | Optional | Boolean | true | Sync 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 | Optional | Boolean | true | Include posts from your custom sources. Available on paid plans, within your plan's custom source allowance. |
sources | Optional | Array<String> (CSV) | FIFAWorldCup,SkySports | Return 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 | Optional | String | US | End-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 | Optional | String | recent | Sort order: recent, top, trending. |
since | Optional | ISO timestamp | 2024-01-15T00:00:00Z | Return posts created after this timestamp. |
since_id | Optional | String | 1879726815913861526 | Return posts created after this post id. |
limit | Optional | Integer | 10 | Items 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 | Optional | Integer | 1 | Page 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. |
| Attribute | Parent Element | Type | Description |
|---|---|---|---|
id | items[] | String | Native X post id. |
post_url | items[] | String | Direct URL to the post on X. |
text | items[] | String | Post body text. |
created_at | items[] | ISO timestamp | Original post timestamp (UTC). |
media_type | items[] | String | video | photo | gif | animated_gif | none |
media | items[] | Array<MediaObject> | Attached media; see Media Object below. |
score | items[] | Integer | Engagement 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. |
| Status | Code | Meaning & recommended action |
|---|---|---|
| 400 | INVALID_PARAMETER | Bad / missing param. Validate input before retrying. |
| 400 | SINCE_ID_NOT_FOUND | Reference post unavailable. Drop `since_id` and retry. |
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 403 | FORBIDDEN | Endpoint or league not on your plan. |
| 404 | NOT_FOUND | A 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. |
| 429 | RATE_LIMITED | Burst limit exceeded. Back off. |
| 429 | USAGE_LIMIT_REACHED | Monthly call cap reached. Calls are paused until your next billing period — no overage is billed. Includes used and limit. |
| 429 | SYNC_INTERVAL_NOT_ELAPSED | Sync 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. |
| 500 | INTERNAL_ERROR | Retry with exponential backoff. |
Try it out
Sign in to test API calls with your key.
Sign In / Get Started FreeExample Response
/account/information
Retrieve your company information, billing cycle, and current API usage. Free — call as often as needed.
{
"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/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).
{
"ids_to_delete": ["1846572934857291245", "1846572934857291246"],
"as_of": "2026-04-30T05:00:00Z"
}Sign in to test this endpoint.
Sign In/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.
{
"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/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.
| Name | Type | Required | Description |
|---|---|---|---|
| entity | string | Yes | One of: teams, players, leagues, posts. |
| league | string | Yes | League code (NFL, NBA, MLB, NHL, PGA). |
| reference_id | string | No | External 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. |
| lookup | string | No | Return only the single team matching this value (resolved against reference_id if provided, otherwise sportfeeds_id). |
{
"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