A goal is worth watching, not reading. The GOALISE Football Highlights API gives you the video: match highlights, single goal clips, press conferences and post-match reaction, each one bound to the fixture it came from, with a thumbnail, a watch link, an embed URL and the geo restrictions the rights holder set on it.
One endpoint does all of it:
GET https://api.goalise.com/api/v3/highlights
It is part of API v3 and uses the access token you already have. Clips come back with the most recent kick-off first, 120 to a page.
What a highlight clip looks like
Every row is a video plus everything you need to decide whether and how to show it:
{
"id": 593001,
"type": "VERIFIED",
"category": "match-highlights",
"title": "Maldini la Decide di Testa | CAGLIARI-LECCE | HIGHLIGHTS | SERIE A 2026/27",
"description": null,
"img_url": "https://i.ytimg.com/vi/7YVc_sZqfwg/hqdefault.jpg",
"url": "https://www.youtube.com/watch?v=7YVc_sZqfwg",
"embed_url": "https://www.youtube.com/embed/7YVc_sZqfwg",
"channel": "Serie A",
"source": "youtube",
"match": {
"id": 466659,
"league": { "id": 646, "name": "Serie A", "logo": "https://...", "type": "League" },
"home_team": { "id": 404, "name": "Cagliari", "logo": "https://..." },
"away_team": { "id": 668, "name": "Lecce", "logo": "https://..." },
"timestamp": 1788798600,
"start_date": "2026-09-12 20:45:00",
"timezone": "UTC",
"status": { "long": "Match Finished", "short": "FT", "elapsed": 90 },
"score": { "home": 1, "away": 0 }
},
"restriction": {
"state": "Allowed countries restriction",
"allowed_countries": ["IT"],
"blocked_countries": [],
"embeddable": true
}
}
Note img_url and embed_url: a video list is a grid of thumbnails and a player, and both arrive ready to use. There is no second call to a hosting platform's own API to find out what the clip looks like or how to play it.
One caveat on id: it is the video provider's identifier, not a GOALISE one. It tells two clips apart and nothing else — no other endpoint accepts it.
The fixture comes with the clip
This is where v3 changed. In v2 a clip named its fixture with four bare integers — the match id, the competition id and the two team ids — so rendering a video card with "Cagliari 1–0 Lecce, Serie A" meant three more requests per clip. A page of 120 clips could mean hundreds.
In v3 the fixture is a real match object: both clubs with their crests, the competition, the kick-off time, the status and the score. A video page renders from one request.
The camelCase the provider used was also brought in line with the rest of the API: imgUrl is img_url, embedUrl is embed_url, allowedCountries is allowed_countries.
How to filter football highlights
You have to narrow the list — an unfiltered call answers 400 rather than trying to return everything ever ingested. The filters combine:
| Parameter | What it does |
|---|---|
match_id | Every clip of one fixture — the video block on a match page. |
league_id | Every clip from the fixtures of one competition — a league video feed. |
team_id | Every clip from one club's fixtures, home or away — a club video hub. |
date_from / date_to | Kick-off on or after, and on or before, a day in Y-m-d. Counted in the zone timezone names. |
category | Keep one kind of clip. See the categories below. |
type | VERIFIED (default), UNVERIFIED or all. |
timezone | IANA zone the fixture's start_date renders in, and the zone the date filters count days in. timestamp stays UTC. |
page | Page number, 1-based, 120 rows a page. |
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
"https://api.goalise.com/api/v3/highlights?team_id=404&category=goal-clip&timezone=Europe/Madrid"
Clip categories
The provider files every video under one of nine categories, and ?category= takes any of them:
| Category | What it is |
|---|---|
match-highlights | The edited highlights package of a fixture. |
goal-clip | A single goal. On these rows description usually carries the scorer and the minute — "James Sands 45+1". |
pre-match-content | Build-up published before kick-off. |
post-match-content | Reaction and analysis after the final whistle. |
press-conference | Manager and player press duties. |
behind-the-scenes | Access footage from the club or the competition. |
live-coverage | Streams and live programming tied to the fixture. |
discussion-analysis | Punditry and breakdowns. |
other | Anything the provider did not file elsewhere. |
A highlights reel and a goal clip are different products. If you are building a scores app, goal-clip next to a live scoreline is the one that keeps people on the page; match-highlights is what a results page wants.
VERIFIED and UNVERIFIED clips
Every row is labelled. VERIFIED means an official rights-holder upload — a league's or a club's own channel. UNVERIFIED means a third-party link.
Only VERIFIED is returned unless you ask otherwise. That default is deliberate: unverified rows have no embed URL and no thumbnail, so they cannot be played inline and cannot be drawn as a video card. Pass ?type=UNVERIFIED to see only those, or ?type=all for both.
For almost every product the default is the right answer. Leave it alone unless you have a specific reason to surface third-party links.
Geo restrictions: know before you serve
Football video is sold market by market, and a clip that plays in Italy may be blocked in Germany. Every row carries the rights position exactly as the provider reports it, with no verdict applied — the API does not decide for you, because only you know where your viewer is:
allowed_countries— ISO alpha-2 codes the clip is limited to. Empty means there is no allow-list.blocked_countries— ISO alpha-2 codes it is blocked in. Empty means there is no block-list.embeddable— whether inline embedding is permitted at all. Independent of the country lists, andnullwhen unknown.state— the provider's own label for the restriction.
One gotcha worth knowing. Do not branch on state. The upstream provider misspells its own unrestricted value as "No restricitons applied", and that string is passed through verbatim rather than silently corrected. Decide from the two country lists, which are clean. It is the kind of detail that costs an afternoon if you meet it in production instead of in the docs.
A reasonable rule for a viewer in country XX: show the clip when allowed_countries is empty or contains XX, and blocked_countries does not contain XX. Embed it inline only when embeddable is true and embed_url is present; otherwise link out to url.
What you can build with it
- A video block on a match page. One call with
match_idreturns everything filed against the fixture — the highlights package, the individual goals, the press conference. - A club video hub.
team_idgives every clip from that club's fixtures, home and away, and each one already knows the opponent and the score. - A league video feed.
league_idplus a date range is a matchday round-up, ready to page through. - A goals-only feed.
category=goal-clipwith a date range is the raw material for a daily digest or a social scheduler. - Editorial workflows. Pair clips with the Football News API so a story ships with the video of the goal it is about.
- AI and agent workflows. The Football MCP Server exposes the same catalogue as tools an assistant can call by itself.
Errors and edge cases
- No filter — 400. The endpoint will not return an unscoped list.
- An id that belongs to nothing — 404 with code
not_found. v2 answered 200 with an empty list here, which was indistinguishable from a fixture that simply has no video. In v3, an empty page means "nothing published yet" and a 404 means "that id does not exist". - A malformed date, a reversed range, an unknown category, type or timezone — 400.
- A fixture with no video — an empty
responsearray with the usual envelope. Normal, and common for lower-tier competitions. embed_urlis null — the provider reports the clip as non-embeddable. Link tourlinstead of putting it in a player.matchis null — the clip was ingested before the fixture was bound to a local match. Rare, but do not assume the object is always there.
Errors carry a machine-readable code in errors[].code. Branch on the code, never on the message text.
Getting started
- Get your access token. It is on your account page, and the same token works across the whole API. No subscription yet? Choose a plan.
- Pick a scope. A fixture, a competition, a team or a date range.
- Read the reference. Every parameter and field is documented in the API reference.
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
"https://api.goalise.com/api/v3/highlights?match_id=466659"
Video availability follows the competition. Check the coverage page for what is collected where.
Frequently asked questions
What is a football highlights API?
It is an endpoint that returns football video clips as structured data rather than as a web page: for each clip, the fixture it belongs to, its category, a thumbnail, a watch link, an embed URL and the countries it may be shown in. That lets an app or a website list and play match highlights without scraping anyone's site.
How do I get highlights for a specific match?
Call GET /api/v3/highlights?match_id={id} with your bearer token. You get every clip filed against that fixture — the highlights package, individual goal clips, the press conference — newest first.
Can I embed the video clips in my own site or app?
When the rights allow it. Each clip carries embed_url for inline playback and an embeddable flag, plus allowed_countries and blocked_countries. The API reports the rights position and applies no verdict of its own, so you decide per viewer. Where embed_url is null, link out to url instead.
Are the highlights official?
By default, yes. Every row is labelled VERIFIED or UNVERIFIED, and only VERIFIED — official rights-holder uploads — is returned unless ?type= asks for otherwise. Unverified rows are third-party links with no embed URL and no thumbnail.
Can I get goal clips separately from full highlights?
Yes. Pass ?category=goal-clip for single goals, or ?category=match-highlights for the edited package. On goal clips the description field usually names the scorer and the minute.
How far back do highlights go, and how many come per page?
Clips are returned most recent kick-off first, 120 rows a page, and date_from and date_to narrow the range by the fixture's kick-off day in whichever zone you pass to ?timezone=.
Do highlights cost extra?
No. GET /highlights is an endpoint like any other: the same access token, the same plan, one request against your allowance per call.
What happens if a match has no highlights?
You get a 200 with an empty response array. A 404 means something different — that the match, league or team id you passed belongs to nothing at all.
Get an access token and start pulling clips, read the full reference, or ask support if you want a hand wiring up the rights logic.