Public JSON API for National Volleyball League standings, fixtures, and head-to-head records across all NVL divisions.
https://nvl.sportangle.co.uk/api/v1
None required — this is a public, read-only API. API keys may be introduced in future.
curl "https://nvl.sportangle.co.uk/api/v1/standings?category=men&division=division-2-north"
GET /api/v1/divisionsReturns all available divisions.
Parameters: None
Example request:
curl "https://nvl.sportangle.co.uk/api/v1/divisions"
Example response:
[
{
"category": "Men",
"division": "DYNAMIK Men's Super League",
"slug": "dynamik-super-league",
"tier": "Super League",
"region": null
},
{
"category": "Women",
"division": "MAAREE Women's Super League",
"slug": "maaree-super-league",
"tier": "Super League",
"region": null
},
{
"category": "Men",
"division": "Division 1 North",
"slug": "division-1-north",
"tier": "1",
"region": "North"
}
]
GET /api/v1/seasonsReturns the seasons addressable by the API. currentSeason is the default when season is omitted from another endpoint.
Parameters: None
Example request:
curl "https://nvl.sportangle.co.uk/api/v1/seasons"
Example response:
{
"availableSeasons": [],
"currentSeason": null
}
Migrated sites return their addressable season values in YYYY-YYYY form, for example 2025-2026 and 2024-2025. An unmigrated site returns no addressable seasons while still serving its current fixtures when season is omitted.
GET /api/v1/fixturesReturns fixtures for a given division. Results are sorted newest first.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
category |
string | Yes | men or women |
division |
string | Yes | Division slug (e.g. division-2-north) — see /divisions for valid slugs |
status |
string | No | Filter by played or scheduled |
limit |
integer | No | Maximum number of fixtures to return |
season |
string | No | Season in YYYY-YYYY form. Defaults to currentSeason; see /seasons. |
Example request:
curl "https://nvl.sportangle.co.uk/api/v1/fixtures?category=men&division=division-2-north&status=played&limit=2"
Example response:
[
{
"fixtureId": "men-division-2-north.json-0",
"date": "2026-03-14",
"time": null,
"category": "Men",
"division": "Division 2 North",
"round": "",
"venue": "",
"homeTeam": "Moss Side",
"awayTeam": "Tameside",
"homeSets": 3,
"awaySets": 1,
"setScores": [
{ "home": 25, "away": 20 },
{ "home": 23, "away": 25 },
{ "home": 25, "away": 18 },
{ "home": 25, "away": 15 }
],
"status": "played"
}
...
]
GET /api/v1/standingsReturns computed league standings for a division, sorted by points then set quotient.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
category |
string | Yes | men or women |
division |
string | Yes | Division slug |
date |
string | No | ISO 8601 date — only count fixtures on or before this date |
detail |
string | No | Set to true to include scoreBreakdown and form fields |
season |
string | No | Season in YYYY-YYYY form. Defaults to currentSeason; finalized past seasons use their stored table. See /seasons. |
Example request:
curl "https://nvl.sportangle.co.uk/api/v1/standings?category=men&division=division-2-north&detail=true"
Example response:
[
{
"position": 1,
"team": "Moss Side",
"played": 12,
"won": 10,
"lost": 2,
"setsWon": 33,
"setsLost": 12,
"setQuotient": 2.75,
"pointsWon": 920,
"pointsLost": 780,
"pointQuotient": 1.179,
"points": 28,
"scoreBreakdown": {
"w30": 5,
"w31": 3,
"w32": 2,
"l23": 1,
"l13": 1,
"l03": 0
},
"form": ["W", "W", "L", "W", "W", "W", "L", "W", "W", "W", "W", "W"]
}
...
]
GET /api/v1/h2hReturns head-to-head records for a team against all opponents (or a specific opponent) in a division.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
category |
string | Yes | men or women |
division |
string | Yes | Division slug |
team |
string | Yes | Exact team name (case-sensitive) |
opponent |
string | No | Filter to a single opponent |
season |
string | No | Season in YYYY-YYYY form. Defaults to currentSeason; see /seasons. |
Example request:
curl "https://nvl.sportangle.co.uk/api/v1/h2h?category=men&division=division-2-north&team=Moss+Side"
Example response:
{
"team": "Moss Side",
"opponents": {
"Tameside": {
"played": 2,
"won": 2,
"lost": 0,
"setsWon": 6,
"setsLost": 2,
"fixtures": [
{
"date": "2026-03-14",
"home": "Moss Side",
"away": "Tameside",
"homeSets": 3,
"awaySets": 1
},
{
"date": "2025-11-09",
"home": "Tameside",
"away": "Moss Side",
"homeSets": 1,
"awaySets": 3
}
]
}
...
}
}
| Field | Description |
|---|---|
position |
League position (1-indexed) |
played |
Total matches played |
won / lost |
Matches won / lost |
setsWon / setsLost |
Total sets won / lost across all matches |
setQuotient |
setsWon / setsLost (3 decimal places). null if no sets lost. |
pointsWon / pointsLost |
Total rally points won / lost (from set scores) |
pointQuotient |
pointsWon / pointsLost (3 decimal places). null if no points lost. |
points |
League points: 3 for a 3-0/3-1 win, 2 for a 3-2 win, 1 for a 2-3 loss, 0 otherwise |
| Key | Meaning |
|---|---|
w30 |
Wins 3-0 |
w31 |
Wins 3-1 |
w32 |
Wins 3-2 |
l23 |
Losses 2-3 |
l13 |
Losses 1-3 |
l03 |
Losses 0-3 |
An array of "W" and "L" values in chronological order (oldest first), one entry per played fixture. Unplayed fixtures are null.
| Field | Description |
|---|---|
fixtureId |
Unique identifier for the fixture |
date |
ISO 8601 date string |
time |
Match time or null |
category |
"Men" or "Women" |
division |
Full division name |
round |
Round name/number (may be empty) |
venue |
Venue name (may be empty) |
homeTeam / awayTeam |
Team names |
homeSets / awaySets |
Sets won by each team (null if unplayed) |
setScores |
Array of { home, away } point scores per set |
status |
"played" or "scheduled" |
All errors return a JSON object with an error field.
| Status | Cause |
|---|---|
400 |
Missing required parameters |
404 |
Division not found, or no matching fixtures/team |
Example:
{ "error": "category and division are required" }
No rate limits are currently enforced. Please be reasonable with request volume — this may change.
const res = await fetch(
'https://nvl.sportangle.co.uk/api/v1/standings?category=men&division=division-2-north'
)
const standings = await res.json()
console.log(standings[0].team, standings[0].points)
import requests
r = requests.get('https://nvl.sportangle.co.uk/api/v1/standings', params={
'category': 'men',
'division': 'division-2-north'
})
standings = r.json()
print(standings[0]['team'], standings[0]['points'])
curl "https://nvl.sportangle.co.uk/api/v1/fixtures?category=women&division=division-1-north&status=scheduled"
The API supports cross-origin requests from any origin — you can call it directly from browser-based applications.
Site HTML, sitemaps, and robots files are produced by the frontend production build (scripts/prerender.js, scripts/generate-seo-files.js). They are not served by these API routes.
National Cup & Shield
Greater Manchester Volleyball Association
Northern Counties Volleyball Association
Run a volleyball league? I can build your results site too.
Get in touch