Chapter 2 Making Your First API Call
For today’s exercise, we will use the Match Day 1 clash between Juventus and recently promoted Como which ended in a 3-0 win for the Old Lady. That game left Juventus as the club to have won the most games on Match Day 1 in Serie A [60] history.
Head over to the ID Finder where you will obtain the ID value of 19155072 which we shall need for our url of interest.
2.1 Getting Fixture Details.
We will retrieve the details for this fixture using Lua and the complete URI below which you can test out on your browser.
https://api.sportmonks.com/v3/football/fixtures/{ID}?api_token=YOUR_TOKEN
local http = require("socket.http")
local ltn12 = require("ltn12") -- Needed for response storage
function fetchFixtureData(fixtureId)
local baseUrl = "https://api.sportmonks.com/v3/football/fixtures"
local apiToken = "API Token"
local apiUrl = string.format("%s/%s?api_token=%s", baseUrl, fixtureId, apiToken)
-- Prepare a response table
local response = {}
local _, statusCode = http.request{
url = apiUrl,
sink = ltn12.sink.table(response) -- Capture the response body
}
-- Check the status code and print the result
if statusCode == 200 then
print("Response: " .. table.concat(response))
else
print("Failed with status: " .. tostring(statusCode))
end
end
-- Call the function with a specific fixture ID
fetchFixtureData("19155150")
Response: {"data":{"id":19155150,"sport_id":1,"league_id":384,"season_id":23746,"stage_id":77471748,"group_id":null,"aggregate_id":null,"round_id":341521,"state_id":5,"venue_id":1721,"name":"Inter vs Juventus","starting_at":"2024-10-27 17:00:00","result_info":"Game ended in draw.","leg":"1\/1","details":null,"length":90,"placeholder":false,"has_odds":true,"has_premium_odds":true,"starting_at_timestamp":1730048400},"subscription":[{"meta":{"trial_ends_at":"2024-10-16 14:50:45","ends_at":null,"current_timestamp":1736507811},"plans":[{"plan":"Enterprise plan (loyal)","sport":"Football","category":"Advanced"},{"plan":"Enterprise Plan","sport":"Cricket","category":"Standard"},{"plan":"Formula One","sport":"Formula One","category":"Standard"}],"add_ons":[{"add_on":"All-in News API","sport":"Football","category":"News"},{"add_on":"pressure index add-on","sport":"Football","category":"Default"},{"add_on":"Enterprise Plan Predictions","sport":"Football","category":"Predictions"},{"add_on":"xG Advanced","sport":"Football","category":"Expected"}],"widgets":[{"widget":"Sportmonks Widgets","sport":"Football"}]}],"rate_limit":{"resets_in_seconds":3573,"remaining":2998,"requested_entity":"Fixture"},"timezone":"UTC"}
Explanation
The socket.http is a library for making HTTP requests in Lua, while the statement ltn12: Provides utilities for handling streams and storing response data in Lua tables.
We then created a function fetchFixtureData that accepts one parameter: fixtureId, representing the unique ID of a football fixture.
A statement to construct the url using the Base URL which is the main API endpoint and a token for authentication is then made to dynamically construct our url of interest.
We then check the response, and if the response is code 200 [OK] then it indicates that the request was successful.
The statement table.concat(response) combines all parts of the response table into a single string for easy printing.
If the request fails, the script prints the HTTP status code which you can cross reference with error codes from our documentation. However, there is a drawback. The response is difficult to read. We will fix this in the next section.
2.2 Pretty Print Fixture Details.
You must have heard of the term pretty print while working with an API that returns a JSON response. We shall modify the earlier piece of code to print the JSON response in a much more readable format without the use of an external library.
local http = require("socket.http")
local ltn12 = require("ltn12")
-- Pretty-print function for JSON strings
local function prettyPrintJSON(jsonString, indentSize)
indentSize = indentSize or 2
local indent = string.rep(" ", indentSize) -- Create indentation
local level = 0
local prettyJSON = ""
for i = 1, #jsonString do
local char = jsonString:sub(i, i)
if char == "{" or char == "[" then
prettyJSON = prettyJSON .. char .. "\n" .. string.rep(indent, level + 1)
level = level + 1
elseif char == "}" or char == "]" then
level = level - 1
prettyJSON = prettyJSON .. "\n" .. string.rep(indent, level) .. char
elseif char == "," then
prettyJSON = prettyJSON .. char .. "\n" .. string.rep(indent, level)
else
prettyJSON = prettyJSON .. char
end
end
return prettyJSON
end
-- Function to fetch and pretty-print fixture data
function fetchFixtureData(fixtureId)
local baseUrl = "https://api.sportmonks.com/v3/football/fixtures"
local apiToken = "API_Token"
local apiUrl = string.format("%s/%s?api_token=%s", baseUrl, fixtureId, apiToken)
local response = {}
local _, statusCode = http.request{
url = apiUrl,
sink = ltn12.sink.table(response)
}
if statusCode == 200 then
local rawJson = table.concat(response)
print("Pretty-Printed JSON Response:")
print(prettyPrintJSON(rawJson))
else
print("Failed with status: " .. tostring(statusCode))
end
end
-- Call the function with a specific fixture ID
fetchFixtureData("19155072")
Pretty-Printed JSON Response:
{
"data":{
"id":19155072,
"sport_id":1,
"league_id":384,
"season_id":23746,
"stage_id":77471748,
"group_id":null,
"aggregate_id":null,
"round_id":341513,
"state_id":5,
"venue_id":118500,
"name":"Juventus vs Como",
"starting_at":"2024-08-19 18:45:00",
"result_info":"Juventus won after full-time.",
"leg":"1\/1",
"details":null,
"length":90,
"placeholder":false,
"has_odds":true,
"has_premium_odds":true,
"starting_at_timestamp":1724093100
},
"subscription":[
{
"meta":{
"trial_ends_at":"2024-10-16 14:50:45",
"ends_at":null,
"current_timestamp":1734917581
},
"plans":[
{
"plan":"Enterprise plan (loyal)",
"sport":"Football",
"category":"Advanced"
},
{
"plan":"Enterprise Plan",
"sport":"Cricket",
"category":"Standard"
},
{
"plan":"Formula One",
"sport":"Formula One",
"category":"Standard"
}
],
"add_ons":[
{
"add_on":"All-in News API",
"sport":"Football",
"category":"News"
},
{
"add_on":"pressure index add-on",
"sport":"Football",
"category":"Default"
},
{
"add_on":"Enterprise Plan Predictions",
"sport":"Football",
"category":"Predictions"
},
{
"add_on":"xG Advanced",
"sport":"Football",
"category":"Expected"
}
],
"widgets":[
{
"widget":"Sportmonks Widgets",
"sport":"Football"
}
]
}
],
"rate_limit":{
"resets_in_seconds":3600,
"remaining":2999,
"requested_entity":"Fixture"
},
"timezone":"UTC"
}
As you can see, we have a more readable format; we shall move on to the next section, where we will retrieve predictions from our fixture of interest, Juventus vs. Como.
2.3. Get Predictions by Fixture ID
While not all fixtures contain sufficient data for reliable predictions, you can enrich your applications with our prediction API, which employs machine learning techniques and models for detailed predictions that include scores, over/under, and both teams to score (BTTS).
We shall focus on predictions for scores in this blog. You may visit the documentation page to learn more about our prediction API.
Here is our URL of interest, which you can try out on your browser.
https://api.sportmonks.com/v3/football/predictions/probabilities/fixtures/FixtureID?api_token=API_Token
local http = require("socket.http")
local ltn12 = require("ltn12")
-- Pretty-print function for JSON strings
local function prettyPrintJSON(jsonString, indentSize)
indentSize = indentSize or 2
local indent = string.rep(" ", indentSize) -- Create indentation
local level = 0
local prettyJSON = ""
for i = 1, #jsonString do
local char = jsonString:sub(i, i)
if char == "{" or char == "[" then
prettyJSON = prettyJSON .. char .. "\n" .. string.rep(indent, level + 1)
level = level + 1
elseif char == "}" or char == "]" then
level = level - 1
prettyJSON = prettyJSON .. "\n" .. string.rep(indent, level) .. char
elseif char == "," then
prettyJSON = prettyJSON .. char .. "\n" .. string.rep(indent, level)
else
prettyJSON = prettyJSON .. char
end
end
return prettyJSON
end
-- Function to fetch and pretty-print fixture data
function fetchFixtureData(fixtureId)
local baseUrl = "https://api.sportmonks.com/v3/football/predictions/probabilities/fixtures"
local apiToken = "API_Token"
local apiUrl = string.format("%s/%s?api_token=%s", baseUrl, fixtureId, apiToken)
local response = {}
local _, statusCode = http.request{
url = apiUrl,
sink = ltn12.sink.table(response)
}
if statusCode == 200 then
local rawJson = table.concat(response)
print("Pretty-Printed JSON Response:")
print(prettyPrintJSON(rawJson))
else
print("Failed with status: " .. tostring(statusCode))
end
end
-- Call the function with a specific fixture ID
fetchFixtureData("19155072")
Pretty-Printed JSON Response:
{
"data":[
{
"id":14610512,
"fixture_id":19155072,
"predictions":{
"yes":70.69,
"no":18.78,
"equal":10.54
},
"type_id":1686
},
{
"id":14610513,
"fixture_id":19155072,
"predictions":{
"yes":10.24,
"no":89.76
},
"type_id":1679
},
{
"id":14610514,
"fixture_id":19155072,
"predictions":{
"yes":94.83,
"no":2.07,
"equal":3.1
},
"type_id":1690
},
{
"id":14610516,
"fixture_id":19155072,
"predictions":{
"yes":46.2,
"no":41.38,
"equal":12.42
},
"type_id":1687
},
{
"id":14610517,
"fixture_id":19155072,
"predictions":{
"yes":89.36,
"no":5.17,
"equal":5.46
},
"type_id":1683
},
{
"id":14610518,
"fixture_id":19155072,
"predictions":{
"yes":58.62,
"no":29.31,
"equal":12.07
},
"type_id":1689
},
{
"id":14610519,
"fixture_id":19155072,
"predictions":{
"yes":81.22,
"no":10.64,
"equal":8.14
},
"type_id":1685
},
{
"id":14610520,
"fixture_id":19155072,
"predictions":{
"yes":34.57,
"no":53.8,
"equal":11.63
},
"type_id":1688
},
{
"id":14610521,
"fixture_id":19155072,
"predictions":{
"yes":24.58,
"no":65.43,
"equal":9.99
},
"type_id":1684
},
{
"id":14610522,
"fixture_id":19155072,
"predictions":{
"yes":21.54,
"no":78.46
},
"type_id":332
},
{
"id":14610523,
"fixture_id":19155072,
"predictions":{
"yes":34.57,
"no":65.43,
"equal":null
},
"type_id":1585
},
{
"id":14610524,
"fixture_id":19155072,
"predictions":{
"yes":39.06,
"no":60.94
},
"type_id":331
},
{
"id":14610525,
"fixture_id":19155072,
"predictions":{
"yes":56.75,
"no":43.25
},
"type_id":333
},
{
"id":14610526,
"fixture_id":19155072,
"predictions":{
"yes":15.52,
"no":84.48
},
"type_id":330
},
{
"id":14610527,
"fixture_id":19155072,
"predictions":{
"yes":5.89,
"no":94.11
},
"type_id":328
},
{
"id":14610528,
"fixture_id":19155072,
"predictions":{
"yes":73.39,
"no":26.61
},
"type_id":334
},
{
"id":14610529,
"fixture_id":19155072,
"predictions":{
"yes":1.48,
"no":98.52
},
"type_id":327
},
{
"id":14610530,
"fixture_id":19155072,
"predictions":{
"yes":19.73,
"no":80.27
},
"type_id":236
},
{
"id":14610531,
"fixture_id":19155072,
"predictions":{
"scores":{
"0-0":10.75,
"0-1":9.08,
"0-2":4.24,
"0-3":1.08,
"1-0":14.12,
"1-1":13.11,
"1-2":5.48,
"1-3":1.62,
"2-0":9.33,
"2-1":9.07,
"2-2":3.94,
"2-3":1.2,
"3-0":4,
"3-1":3.95,
"3-2":1.99,
"3-3":0.51,
"Other_1":5.06,
"Other_2":1.47,
"Other_X":0.01
}
},
"type_id":240
},
{
"id":14610532,
"fixture_id":19155072,
"predictions":{
"yes":5.07,
"no":94.93
},
"type_id":326
},
{
"id":14610533,
"fixture_id":19155072,
"predictions":{
"yes":39.37,
"no":60.63
},
"type_id":235
},
{
"id":14610534,
"fixture_id":19155072,
"predictions":{
"yes":66.06,
"no":33.94
},
"type_id":234
},
{
"id":14610535,
"fixture_id":19155072,
"predictions":{
"home":32.22,
"away":22.82,
"draw":44.97
},
"type_id":233
},
{
"id":14610536,
"fixture_id":19155072,
"predictions":{
"home_home":25.67,
"home_away":1.86,
"home_draw":5.43,
"away_home":2.5,
"away_away":14.57,
"away_draw":5.28,
"draw_draw":18.72,
"draw_home":17.19,
"draw_away":8.78
},
"type_id":232
},
{
"id":14610537,
"fixture_id":19155072,
"predictions":{
"draw_home":75.82000000000001,
"draw_away":52.480000000000004,
"home_away":71.7
},
"type_id":239
}
],
"pagination":{
"count":25,
"per_page":25,
"current_page":1,
"next_page":"https:\/\/api.sportmonks.com\/v3\/football\/predictions\/probabilities\/fixtures\/19155072?page=2",
"has_more":true
},
"subscription":[
{
"meta":{
"trial_ends_at":"2024-10-16 14:50:45",
"ends_at":null,
"current_timestamp":1734983903
},
"plans":[
{
"plan":"Enterprise plan (loyal)",
"sport":"Football",
"category":"Advanced"
},
{
"plan":"Enterprise Plan",
"sport":"Cricket",
"category":"Standard"
},
{
"plan":"Formula One",
"sport":"Formula One",
"category":"Standard"
}
],
"add_ons":[
{
"add_on":"All-in News API",
"sport":"Football",
"category":"News"
},
{
"add_on":"pressure index add-on",
"sport":"Football",
"category":"Default"
},
{
"add_on":"Enterprise Plan Predictions",
"sport":"Football",
"category":"Predictions"
},
{
"add_on":"xG Advanced",
"sport":"Football",
"category":"Expected"
}
],
"widgets":[
{
"widget":"Sportmonks Widgets",
"sport":"Football"
}
]
}
],
"rate_limit":{
"resets_in_seconds":2803,
"remaining":2997,
"requested_entity":"Prediction"
},
"timezone":"UTC"
}
A brief explanation of the response can be found on our documentation page.