SofaScore API endpoint
Returns a racket-sport match's point-by-point timeline, with sets and games in play order. Tennis sets list games and each game lists every point with the running score (`0`, `15`, `30`, `40`, `A`, or a plain count in a tie-break), the server, the game winner, a `description` of `ace` or `double_fault` where SofaScore flags it, and break point (`break_point`) or set or match point (`set_or_match_point`) markers per player. Table tennis and badminton sets list their points directly. The ace flag is a lower bound of the match's real ace count. Darts matches are not covered. Returns 404 when SofaScore has no point-by-point data for the match, which includes matches that have not started and sports without it.
/sofascore/event-point-by-pointQuery parameters:
id: required. Numeric SofaScore event (match) id of a tennis, table tennis or badminton match, e.g. 17257382. Get it from sofascore/live-events, sofascore/team-events or sofascore/scheduled-events.Notable response behavior:
games; every game lists its points with the score after each point: home_point and away_point are 0, 15, 30, 40 and A in a normal game and a plain count in a tie-break. A game score holds the games won in the set after that game (home_score, away_score), the server and the game winner (home or away). winner is omitted while the game is being played and server when SofaScore does not know it yet. A game can come without a score when SofaScore did not record one.description is ace or double_fault where SofaScore flags the point (description_code 1 or 2; 0 means no flag). Double faults matched the match statistics exactly on two matches checked; the ace flag is a lower bound (on one match it flagged 18 of the 26 aces in the statistics), so use sofascore/event-statistics for totals.home_point_type and away_point_type are SofaScore's per-player point codes. home_marker and away_marker name the two opportunity codes: break_point (code 2, the returner holds a break point after the point) and set_or_match_point (code 3; SofaScore reports a match point with the same code as a set point). Codes 1 and 5 mark an ordinary point (1 for the player who won it, 5 otherwise; the last point of a tie-break can carry 5 for both players), and code 6 appears only in tie-breaks; other codes carry no marker.points directly and carries a score with the points won in the set.404. An empty sets array is a valid response (a match with no point yet).404 when SofaScore has no point-by-point data for the match. This includes matches that have not started, sports other than tennis, table tennis and badminton, and unknown ids.Example response (shortened):
{
"code": 200,
"msg": "OK",
"data": {
"event_id": 17257382,
"source_url": "https://api.sofascore.com/api/v1/event/17257382/point-by-point",
"fetched_at": "2026-10-07T17:00:00Z",
"set_count": 3,
"sets": [
{
"set": 1,
"games": [
{
"game": 1,
"score": {
"home_score": 1,
"away_score": 0,
"server": "home",
"winner": "home"
},
"points": [
{
"home_point": "15",
"away_point": "0",
"description_code": 0,
"home_point_type": 1,
"away_point_type": 5
},
{
"home_point": "15",
"away_point": "15",
"description_code": 0,
"home_point_type": 5,
"away_point_type": 1
},
{
"home_point": "30",
"away_point": "15",
"description_code": 0,
"home_point_type": 1,
"away_point_type": 5
}
]
},
"...",
{
"game": 13,
"score": {
"home_score": 7,
"away_score": 6,
"server": "away",
"winner": "home"
},
"points": [
{
"home_point": "1",
"away_point": "0",
"description_code": 0,
"home_point_type": 1,
"away_point_type": 5
},
{
"home_point": "2",
"away_point": "0",
"description": "double_fault",
"description_code": 2,
"home_point_type": 6,
"away_point_type": 5
},
{
"home_point": "6",
"away_point": "3",
"description_code": 0,
"home_point_type": 3,
"away_point_type": 6,
"home_marker": "set_or_match_point"
},
{
"home_point": "7",
"away_point": "3",
"description_code": 0,
"home_point_type": 5,
"away_point_type": 5
}
]
}
]
},
"...",
{
"set": 3,
"games": [
"...",
{
"game": 10,
"score": {
"home_score": 4,
"away_score": 6,
"server": "away",
"winner": "away"
},
"points": [
{
"home_point": "15",
"away_point": "30",
"description_code": 0,
"home_point_type": 5,
"away_point_type": 1
},
{
"home_point": "15",
"away_point": "40",
"description_code": 0,
"home_point_type": 5,
"away_point_type": 3,
"away_marker": "set_or_match_point"
}
]
}
]
}
]
}
}
| Field | Filled in, of 3 checked | Values in the sample |
|---|---|---|
| set | 3 | 1 to 3, median 2 |
| games | 3 | median 10 entries |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| id | string | Yes | Numeric SofaScore event (match) id | 17257382 | |
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/sofascore/event-point-by-point?id=17257382" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"event_id": 17257382,
"source_url": "https://api.sofascore.com/api/v1/event/17257382/point-by-point",
"fetched_at": "2026-10-07T17:00:00Z",
"set_count": 3,
"sets": [
{
"set": 1,
"games": [
{
"game": 1,
"score": {
"home_score": 1,
"away_score": 0,
"server": "home",
"winner": "home"
},
"points": [
{
"home_point": "15",
"away_point": "0",
"description_code": 0,
"home_point_type": 1,
"away_point_type": 5
},
{
"home_point": "15",
"away_point": "15",
"description_code": 0,
"home_point_type": 5,
"away_point_type": 1
},
{
"home_point": "30",
"away_point": "15",
"description_code": 0,
"home_point_type": 1,
"away_point_type": 5
}
]
},
"...",
{
"game": 13,
"score": {
"home_score": 7,
"away_score": 6,
"server": "away",
"winner": "home"
},
"points": [
{
"home_point": "1",
"away_point": "0",
"description_code": 0,
"home_point_type": 1,
"away_point_type": 5
},
{
"home_point": "2",
"away_point": "0",
"description": "double_fault",
"description_code": 2,
"home_point_type": 6,
"away_point_type": 5
},
{
"home_point": "6",
"away_point": "3",
"description_code": 0,
"home_point_type": 3,
"away_point_type": 6,
"home_marker": "set_or_match_point"
},
{
"home_point": "7",
"away_point": "3",
"description_code": 0,
"home_point_type": 5,
"away_point_type": 5
}
]
}
]
},
"...",
{
"set": 3,
"games": [
"...",
{
"game": 10,
"score": {
"home_score": 4,
"away_score": 6,
"server": "away",
"winner": "away"
},
"points": [
{
"home_point": "15",
"away_point": "30",
"description_code": 0,
"home_point_type": 5,
"away_point_type": 1
},
{
"home_point": "15",
"away_point": "40",
"description_code": 0,
"home_point_type": 5,
"away_point_type": 3,
"away_marker": "set_or_match_point"
}
]
}
]
}
]
}
}Request schema
No body schema
Response schema
#/definitions/sofascore.eventPointByPointResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | 200 | |||
| data | sofascore.EventPointByPointResponse | No | ||||
| data.event_id | integer | No | 17257382 | |||
| data.fetched_at | string | No | ||||
| data.set_count | integer | No | 3 | |||
| data.sets | array | No | ||||
| data.sets[].games | array | No | ||||
| data.sets[].games[].game | integer | No | 10 | |||
| data.sets[].games[].points | array | No | ||||
| data.sets[].games[].points[].away_marker | string | No | set_or_match_point | |||
| data.sets[].games[].points[].away_point | string | No | 40 | |||
| data.sets[].games[].points[].away_point_type | integer | No | 2 | |||
| data.sets[].games[].points[].description | string | No | ace | Description is `ace` or `double_fault` when SofaScore flags the point; omitted otherwise. DescriptionCode is the upstream code (0 none, 1 ace, 2 double fault). | ||
| data.sets[].games[].points[].description_code | integer | No | 0 | |||
| data.sets[].games[].points[].home_marker | string | No | break_point | HomeMarker and AwayMarker name the codes that mean a player holds a point opportunity after the point: `break_point` (code 2) and `set_or_match_point` (code 3). | ||
| data.sets[].games[].points[].home_point | string | No | 30 | HomePoint and AwayPoint are the points as SofaScore prints them: `0`, `15`, `30`, `40` and `A` in a tennis game, a plain count in a tie-break, table tennis or badminton set. | ||
| data.sets[].games[].points[].home_point_type | integer | No | 5 | HomePointType and AwayPointType are SofaScore's per-player point codes. | ||
| data.sets[].games[].score | sofascore.PointByPointScore | No | ||||
| data.sets[].games[].score.away_score | integer | No | 4 | |||
| data.sets[].games[].score.home_score | integer | No | 6 | |||
| data.sets[].games[].score.server | string | No | away | Server is `home` or `away`; omitted when SofaScore does not know it. | ||
| data.sets[].games[].score.winner | string | No | away | Winner is `home` or `away`; omitted while the game or set is unfinished. | ||
| data.sets[].points | array | No | ||||
| data.sets[].points[].away_marker | string | No | set_or_match_point | |||
| data.sets[].points[].away_point | string | No | 40 | |||
| data.sets[].points[].away_point_type | integer | No | 2 | |||
| data.sets[].points[].description | string | No | ace | Description is `ace` or `double_fault` when SofaScore flags the point; omitted otherwise. DescriptionCode is the upstream code (0 none, 1 ace, 2 double fault). | ||
| data.sets[].points[].description_code | integer | No | 0 | |||
| data.sets[].points[].home_marker | string | No | break_point | HomeMarker and AwayMarker name the codes that mean a player holds a point opportunity after the point: `break_point` (code 2) and `set_or_match_point` (code 3). | ||
| data.sets[].points[].home_point | string | No | 30 | HomePoint and AwayPoint are the points as SofaScore prints them: `0`, `15`, `30`, `40` and `A` in a tennis game, a plain count in a tie-break, table tennis or badminton set. | ||
| data.sets[].points[].home_point_type | integer | No | 5 | HomePointType and AwayPointType are SofaScore's per-player point codes. | ||
| data.sets[].score | sofascore.PointByPointScore | No | ||||
| data.sets[].score.away_score | integer | No | 4 | |||
| data.sets[].score.home_score | integer | No | 6 | |||
| data.sets[].score.server | string | No | away | Server is `home` or `away`; omitted when SofaScore does not know it. | ||
| data.sets[].score.winner | string | No | away | Winner is `home` or `away`; omitted while the game or set is unfinished. | ||
| data.sets[].set | integer | No | 1 | |||
| data.source_url | string | No | ||||
| msg | string | No | OK |
| Status | Description | Schema |
|---|---|---|
| 400 | Bad Request | #/definitions/app.Response |
| 404 | Not Found | #/definitions/app.Response |
| 429 | Too Many Requests | #/definitions/app.Response |
| 503 | Service Unavailable | #/definitions/app.Response |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/sofascore/event-point-by-point?id=17257382" \
-H "x-api-key: $CRAWLORA_API_KEY"