Skip to content

Feed API

The Feed API gives you the posts LoopFeed’s AI curation has matched to a match, team, player or competition: highlights, clips, previews, interviews, news and more, from every source LoopFeed curates. You don’t need to set up topics or sources.

GET https://q.loop-feed.com/v1/feeds/football/team/9
→ the latest posts about Arsenal
  1. Get your API key from LoopFeed. It looks like lfk_ followed by 43 characters. It is shown only once, so store it in your server’s secrets.

  2. Request a feed from your server:

    Terminal window
    curl -H "Authorization: Bearer lfk_your_key" \
    "https://q.loop-feed.com/v1/feeds/football/team/9?limit=5"
  3. Show it in a browser or app: your server mints a short-lived feed token, and the page uses the token instead of the key.

GET /v1/feeds/{sport}/{kind}/{id}
Sport ({sport})Kinds ({kind})
football: association football (soccer)match, team, player, competition
rugby: rugby leaguematch, team, competition
rugby-union: rugby union and sevensmatch, team, competition

{id} is the numeric ID of the match, team, player or competition in LoopFeed’s sports data. See Finding IDs.

  • A competition feed covers every season of that competition. Its ID stays the same from one season to the next.
  • Player feeds are football only.
  • IDs are unique only within a sport. Football team 18 and rugby league team 18 are different teams, so always include the sport.
ParameterDefaultDescription
limit20Posts per page, up to 100.
cursorThe next value from the previous page. See Paging.
contentTypeOnly these content types, comma-separated, at most 5. For example highlights,clip.
serviceOnly one platform: youtube, twitter, instagram or rss.
tokenA feed token, for browsers and apps instead of the API key.
{
"content": [
{
"id": "cmh0x1y2z0001abcdpost00001",
"externalId": "m0G_UKNoSqY",
"service": "youtube",
"type": "video",
"title": "MADUEKE THE MATCHWINNER! | EXTENDED HIGHLIGHTS | Nottingham Forest vs Arsenal (0-1)",
"text": "Noni Madueke's late goal was enough to secure a valuable 1-0 win away to Nottingham Forest...",
"url": "https://www.youtube.com/watch?v=m0G_UKNoSqY",
"date": "2026-10-19T23:00:00Z",
"created": "2026-10-19T23:04:12.521Z",
"author": { "name": "Arsenal", "username": "Arsenal", "url": "https://youtube.com/channel/UCpryVRk_VDudG8SHXgWcG0w", "verified": true },
"media": [
{ "type": "embed", "embed": "<iframe src='https://www.youtube.com/embed/m0G_UKNoSqY'></iframe>" },
{ "type": "image", "url": "https://i.ytimg.com/vi/m0G_UKNoSqY/maxresdefault.jpg", "width": 1280, "height": 720 }
],
"metadata": {
"contentType": "highlights",
"matches": [
{
"sport": "football", "matchId": "518066",
"homeTeamId": "11", "homeTeamName": "Nottingham Forest",
"awayTeamId": "9", "awayTeamName": "Arsenal",
"leagueId": "10001", "leagueName": "England - Premier League",
"startDateTime": "2026-10-18T15:30:00.000Z"
}
],
"entities": [
{ "sport": "football", "kind": "competition", "id": "10001", "name": "Premier League" },
{ "sport": "football", "kind": "team", "id": "9", "name": "Arsenal" },
{ "sport": "football", "kind": "team", "id": "11", "name": "Nottingham Forest" },
{ "sport": "football", "kind": "player", "id": "4410", "name": "Noni Madueke" }
],
"custom": {}
},
"pinned": false
}
],
"next": "MjAyNi0xMC0xOVQyMzowMDowMFp8Y21oMHgxeTJ6MDAwMWFiY2Rwb3N0MDAwMDE"
}

The example is shortened. Each post has the same shape as items from the topic content API, and its curation is in metadata:

FieldDescription
metadata.contentTypeThe post’s content type, for example highlights.
metadata.matchesThe match the post is about, if any: its ID, teams, competition and kick-off time.
metadata.entitiesThe teams, players and competitions the post is about. Each has a sport, kind, id and name.
  • Posts are newest first, by the time they were published.
  • If the same video was posted by several sources, it appears once.
  • The match status and score in metadata.matches are a snapshot from when the post was curated. Use your live sports data for current scores.

next is the cursor of the following page, or null on the last page. Pass it back unchanged as cursor, with the same filters:

Terminal window
curl -H "Authorization: Bearer lfk_your_key" \
"https://q.loop-feed.com/v1/feeds/football/team/9?limit=20&cursor=MjAyNi0xMC0xOVQyMzowMDowMFp8Y21oMHgxeTJ6MDAwMWFiY2Rwb3N0MDAwMDE"

To check for new posts, request the first page again (no cursor).

There are two ways to authenticate. Use the one that matches where the request comes from.

FromSendOpens
Your serversThe API key, in a headerEvery feed of the sports your subscription covers
Browsers and appsA feed token, as ?token=One feed, until the token expires

Send the key in either header:

Authorization: Bearer lfk_your_key
X-API-Key: lfk_your_key

If you gave LoopFeed your servers’ IP addresses, the key only works from those addresses. Servers that have IPv6 usually connect over it, so give us their IPv6 addresses (or range) as well as their IPv4 ones. A refused request says which address it came from.

A feed token opens one feed for a limited time, from one hour by default up to one day. If a token leaks, only that one feed is exposed, and only until the token expires. Your server mints tokens with the API key:

POST /v1/feeds/tokens
Authorization: Bearer lfk_your_key
Content-Type: application/json
{ "scheme": "football", "kind": "team", "id": "9", "ttlSeconds": 3600 }
FieldDescription
schemeThe sport: football, rugby or rugby-union.
kindmatch, team, player or competition.
idThe numeric ID.
ttlSecondsOptional. How long the token works: 60 to 86400 seconds, default 3600.

The response (201 Created) has the token, its expiry and the path it opens:

{
"token": "Y21zdWIxMjN8Zm9vdGJhbGx8dGVhbXwxM3wxNzYwOTg2MDAw.q2V0...",
"expiresAt": "2026-10-20T19:00:00Z",
"url": "/v1/feeds/football/team/9?token=Y21zdWIxMjN8Zm9vdGJhbGx8dGVhbXwxM3wxNzYwOTg2MDAw.q2V0..."
}

The page then requests https://q.loop-feed.com + url, adding any other parameters with &:

// GET /feed-token?team=9 on your site: returns a token for one team's feed
app.get('/feed-token', async (req, res) => {
const response = await fetch('https://q.loop-feed.com/v1/feeds/tokens', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LOOPFEED_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ scheme: 'football', kind: 'team', id: String(req.query.team) }),
});
res.status(response.status).json(await response.json());
});

Mint a new token when the old one expires, or shortly before. Tokens stop working within a minute if LoopFeed pauses your subscription or rotates your key.

Feeds use the IDs of LoopFeed’s sports data provider, the same as the rest of LoopFeed. For example, Arsenal is football team 9, and the Premier League is football competition 10001.

  • From a post: every curated post lists its teams, players and competitions in metadata.entities, and its match in metadata.matches, with their IDs.
  • From your topics: the Content API lists the teams you set on each topic, and the leagueId of each attached match.
  • Ask us: your account manager can send you the IDs for the competitions you cover.
  • Caching: responses can be cached for 60 seconds (Cache-Control: private, max-age=60). Each response has an ETag. Send it back as If-None-Match, and you get 304 Not Modified with no body when nothing changed.
  • Rate limit: your subscription allows a set number of requests a minute. Over that, you get 429 with a Retry-After header (seconds). Cache feeds on your server rather than requesting them for every visitor.

Errors return JSON with a message:

{ "error": "This feed token is for another feed" }
StatusMeaning
400A parameter is invalid: a non-numeric ID, an unknown contentType or service, a bad cursor, or ttlSeconds out of range.
401No API key or token, or the key or token is unknown or expired, or the subscription is paused.
403The subscription doesn’t cover this sport, the request came from an IP address the key doesn’t allow (the message names the address), the API key was sent from a browser, or the token is for a different feed.
404Unknown sport or kind in the path.
429Rate limit exceeded. Wait for Retry-After seconds.
5xxA temporary problem on our side. Retry with backoff.
Feed APITopic content API
What you getPosts about one match, team, player or competition, from every source LoopFeed curatesYour topic’s posts, from the sources and filters you chose
ModerationLoopFeed’s AI, checked by LoopFeed reviewersYou: hide, pin and edit in your queue
AccessSubscription and API keyPublic, by topic ID