SofaScore API endpoint
Returns every shot in a football or ice hockey match. Football shots carry the shooter, side, outcome (`shot_type`), situation, body part, expected goals (xG and xGOT), minute, and pitch and goal-mouth coordinates. Ice hockey shots carry the shooter, team, side, shot technique (`shot_type`, for example `wrist`), `outcome` (`made`, `saved`, `missed` or `blocked`), `strength` (`even`, `powerplay` or `shorthanded`), period and period clock, rink `coordinates` and, for most shots, `xg`. An empty `shots` list is a valid response (a live match with no shots yet). Returns 404 when SofaScore has no shot map for the match, which includes matches that have not started, basketball and other sports without one, and fixtures without expected-goals coverage.
/sofascore/event-shotmapQuery parameters:
id: required. Numeric SofaScore event (match) id of a football or ice hockey match, e.g. 16363867 (football) or 15950163 (ice hockey).Notable response behavior:
shot_type is the outcome (observed values: goal, save, miss, block, blocked-off-line); situation and body_part are SofaScore's own labels (observed: assisted, corner, set-piece, fast-break, free-kick, regular, throw-in-set-piece; left-foot, right-foot, head). They are not validated as closed sets.xg is expected goals and xgot expected goals on target; either is omitted when SofaScore does not provide it. goalkeeper is present on shots a goalkeeper faced.player_coordinates and block_coordinates use SofaScore's 0-100 pitch scale; goal_mouth_coordinates locates the shot on the goal frame (z is height).minute, player_coordinates, goal_mouth_coordinates, goalkeeper, situation, body_part): team is the shooting team, outcome is one of made, saved, missed or blocked, strength is even, powerplay or shorthanded, period is 1ST, 2ND or 3RD in regulation (overtime labels were not checked), period_time_seconds is the time into the period, reversed_period_time_seconds the time left in it (football shots carry these two clock fields too), time_seconds the time into the game, and coordinates is one x/y rink position in SofaScore's rink units. xg is present on most shots and absent on blocked shots (21 of 94 in the match checked).shot_type is the shooting technique (seen: wrist, snap, slap, tip-in, bat, backhand, wrap-around, deflected), not the outcome as in football; use outcome for the result. xgot and goalkeeper are not provided for hockey.404.shots array is a valid response (a live match with no shots yet), not an error.404 when SofaScore has no shot map for the match. This includes matches that have not started and fixtures without expected-goals coverage.Example response, ice hockey (shortened):
{
"code": 200,
"msg": "OK",
"data": {
"event_id": 15950163,
"source_url": "https://api.sofascore.com/api/v1/event/15950163/shotmap",
"fetched_at": "2026-10-07T17:00:00Z",
"count": 94,
"shots": [
{
"id": 19632948,
"player": {
"id": 1458085,
"name": "Jackson Blake",
"short_name": "J. Blake",
"slug": "jackson-blake",
"position": "R",
"jersey_number": "53"
},
"is_home": false,
"shot_type": "wrap-around",
"xg": 0.0704,
"time_seconds": 105,
"team": {
"id": 3680,
"name": "Carolina Hurricanes",
"short_name": "Hurricanes",
"slug": "carolina-hurricanes"
},
"outcome": "missed",
"strength": "even",
"period": "1ST",
"period_time_seconds": 105,
"reversed_period_time_seconds": 1095,
"coordinates": {
"x": 17,
"y": 56
}
},
{
"id": 19632957,
"player": {
"id": 788026,
"name": "Sebastian Aho",
"short_name": "S. Aho",
"slug": "sebastian-aho",
"position": "C",
"jersey_number": "20"
},
"is_home": false,
"shot_type": "wrist",
"time_seconds": 151,
"team": {
"id": 3680,
"name": "Carolina Hurricanes",
"short_name": "Hurricanes",
"slug": "carolina-hurricanes"
},
"outcome": "blocked",
"strength": "even",
"period": "1ST",
"period_time_seconds": 151,
"reversed_period_time_seconds": 1049,
"coordinates": {
"x": 58,
"y": 24
}
}
]
}
}
| Field | Filled in, of 33 checked | Values in the sample |
|---|---|---|
| id | 33 | |
| player | 33 | |
| goalkeeper | 33 | |
| is_home | 33 | true in 16 of 33 |
| shot_type | 33 | miss (10), block (8), goal (8) and 2 more |
| situation | 33 | assisted (16), corner (7), set-piece (4) and 4 more |
| body_part | 33 | right-foot (15), left-foot (13), head (5) |
| goal_mouth_location | 33 | “low-centre” and 9 other values |
| xg | 33 | 0.02 to 0.97, median 0.08 |
| xgot | 33 | 0 to 1, median 0 |
| minute | 33 | 6 to 90, median 59 |
| added_time | 4 | 1 to 6, median 4 |
| time_seconds | 33 | 342 to 5,639, median 3,521 |
| player_coordinates | 33 | |
| goal_mouth_coordinates | 33 | |
| block_coordinates | 16 | |
| period_time_seconds | 33 | 24 to 2,689, median 1,203 |
| reversed_period_time_seconds | 33 | 11 to 2,572, median 1,211 |
| goal_type | 8 | regular in all 8 |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| id | string | Yes | Numeric SofaScore event (match) id | 16363867 | |
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/sofascore/event-shotmap?id=16363867" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"event_id": 16363867,
"source_url": "https://api.sofascore.com/api/v1/event/16363867/shotmap",
"fetched_at": "2026-07-08T00:00:00Z",
"count": 33,
"shots": [
{
"id": 8504160,
"player": {
"id": 839956,
"name": "Erling Haaland",
"short_name": "E. Haaland",
"slug": "erling-haaland",
"position": "F",
"jersey_number": "9"
},
"goalkeeper": {
"id": 1012928,
"name": "Robin Roefs",
"short_name": "R. Roefs",
"slug": "robin-roefs",
"position": "G",
"jersey_number": "22"
},
"is_home": true,
"shot_type": "goal",
"situation": "assisted",
"body_part": "right-foot",
"goal_type": "regular",
"goal_mouth_location": "low-right",
"xg": 0.67196875810623,
"xgot": 0.86413210630417,
"minute": 81,
"time_seconds": 4858,
"player_coordinates": {
"x": 3.3,
"y": 53.2,
"z": 0
},
"goal_mouth_coordinates": {
"x": 0,
"y": 47.8,
"z": 7
}
}
]
}
}Request schema
No body schema
Response schema
#/definitions/sofascore.eventShotmapResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | 200 | |||
| data | sofascore.EventShotmapResponse | No | ||||
| data.count | integer | No | ||||
| data.event_id | integer | No | 16363867 | |||
| data.fetched_at | string | No | ||||
| data.shots | array | No | ||||
| data.shots[].added_time | integer | No | 4 | |||
| data.shots[].block_coordinates | sofascore.Coordinates | No | ||||
| data.shots[].block_coordinates.x | number | No | ||||
| data.shots[].block_coordinates.y | number | No | ||||
| data.shots[].block_coordinates.z | number | No | ||||
| data.shots[].body_part | string | No | right-foot | |||
| data.shots[].coordinates | sofascore.Coordinates | No | ||||
| data.shots[].coordinates.x | number | No | ||||
| data.shots[].coordinates.y | number | No | ||||
| data.shots[].coordinates.z | number | No | ||||
| data.shots[].goal_mouth_coordinates | sofascore.Coordinates | No | ||||
| data.shots[].goal_mouth_coordinates.x | number | No | ||||
| data.shots[].goal_mouth_coordinates.y | number | No | ||||
| data.shots[].goal_mouth_coordinates.z | number | No | ||||
| data.shots[].goal_mouth_location | string | No | low-left | |||
| data.shots[].goal_type | string | No | regular | |||
| data.shots[].goalkeeper | sofascore.PlayerBrief | No | PlayerBrief record, 6 fields: id, jersey_number, name, position, short_name, slug. Described under SofaScore event at-bat pitches API. | |||
| data.shots[].id | integer | No | ||||
| data.shots[].is_home | boolean | No | ||||
| data.shots[].minute | integer | No | 90 | |||
| data.shots[].outcome | string | No | saved | |||
| data.shots[].period | string | No | 1ST | |||
| data.shots[].period_time_seconds | integer | No | 458 | |||
| data.shots[].player | sofascore.PlayerBrief | No | PlayerBrief record, 6 fields: id, jersey_number, name, position, short_name, slug. Described under SofaScore event at-bat pitches API. | |||
| data.shots[].player_coordinates | sofascore.Coordinates | No | ||||
| data.shots[].player_coordinates.x | number | No | ||||
| data.shots[].player_coordinates.y | number | No | ||||
| data.shots[].player_coordinates.z | number | No | ||||
| data.shots[].reversed_period_time_seconds | integer | No | 742 | |||
| data.shots[].shot_type | string | No | goal | |||
| data.shots[].situation | string | No | assisted | |||
| data.shots[].strength | string | No | powerplay | |||
| data.shots[].team | object | No | Ice hockey fields. Hockey shots carry the shooting team, an outcome, the strength situation and the period clock instead of a minute, and one rink position instead of pitch and goal-mouth coordinates. | |||
| data.shots[].team.country | string | No | Spain | Country the team belongs to. | ||
| data.shots[].team.id | integer | No | 2817 | SofaScore team id. Use it with the team endpoints. | ||
| data.shots[].team.name | string | No | FC Barcelona | Full team name. | ||
| data.shots[].team.national | boolean | No | True for a national team. | |||
| data.shots[].team.short_name | string | No | Barcelona | Shortened team name. | ||
| data.shots[].team.slug | string | No | barcelona | URL slug of the team on SofaScore. | ||
| data.shots[].time_seconds | integer | No | ||||
| data.shots[].xg | number | No | 0.19 | |||
| data.shots[].xgot | number | No | 0.08 | |||
| 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-shotmap?id=16363867" \
-H "x-api-key: $CRAWLORA_API_KEY"