
Contents
Understanding referees in football
Referees are the primary enforcers of the rules in a football match. They are responsible for ensuring the game is played fairly, safely, and within the official laws of the sport. While they often go unnoticed when everything runs smoothly, referees are central to match integrity and discipline.
Who are referees?
A football referee is a licensed official appointed to supervise a game. They undergo rigorous training and certification, often progressing through local leagues to national and international levels. Some referees even officiate in prestigious tournaments like the FIFA World Cup and UEFA Champions League.
Core responsibilities of a referee
The main duties of a referee include:
– Enforcing the rules: Interpreting and applying the Laws of the Game.
– Controlling the match: Managing player behaviour, handling timekeeping, and maintaining order.
– Making decisions: Awarding free kicks, penalties, goals, and issuing disciplinary cards (yellow/red).
– Collaborating with assistants: Working closely with assistant referees (linesmen), the fourth official, and video assistant referees (VAR) to ensure accurate decisions.
– Ensuring player safety: Halting play for injuries, dangerous conduct, or poor weather conditions.
Types of officials in a match
While the “referee” refers to the central figure on the pitch, they are part of a larger officiating team that may include:
– Assistant referees (2): Responsible for offsides and boundary decisions.
– Fourth official: Handles substitutions and technical area management.
– VAR team: Reviews major incidents using video replay.
– Additional assistant referees (used in some competitions): Positioned behind goals to monitor incidents in the penalty area.
Why referee data matters
Understanding a referee’s history and officiating style can be crucial for:
– Match previews and analysis: Some referees give more cards, allow physical play, or are stricter with dissent.
– Betting and odds models: Referee trends influence game flow and outcomes.
– Team strategy: Coaches may adapt tactics based on how a referee typically handles fouls or penalties.
With Sportmonks’ API, you can access detailed referee data, from biography to match statistics which opens the door to richer match analysis and smarter applications.
What is Clojure?
Clojure is a modern, functional, and expressive programming language that runs on the Java Virtual Machine (JVM). It’s a dialect of Lisp, one of the oldest families of programming languages, but reimagined for today’s performance demands and software practices.
Key features of Clojure
Clojure combines the simplicity of Lisp with the power of Java, resulting in a language that’s both elegant and practical. Some of its defining features include:
– Functional-first: Clojure promotes immutability and pure functions by default, reducing side effects and making code easier to test and reason about.
– Immutable data structures: Instead of changing data in place, Clojure encourages creating new versions of data, which helps prevent bugs and race conditions.
– REPL-driven development: The interactive Read-Eval-Print Loop (REPL) enables live coding and experimentation. You can send code directly from your editor and see results instantly, perfect for quick prototyping and debugging.
– Concise syntax: Clojure’s syntax is minimal and uniform. It uses prefix notation (also known as S-expressions) which is extremely powerful for manipulating code as data.
– Full JVM interoperability: Clojure can call any Java method or use Java libraries, making it highly versatile for web development, data processing, or API integration.
Where Clojure is used
Clojure is widely used in industries that demand robustness, scalability, and reliability. Common use cases include:
– Backend services and web APIs
– Data pipelines and analytics
– Concurrency-heavy applications
– Domain-specific languages (DSLs)
– Financial systems and startups that value fast iteration with strong stability
Why use Clojure for API integrations?
– Powerful data handling: Clojure’s data literals (maps, vectors, sets) match JSON responses almost 1-to-1, making it easy to parse and transform API responses.
– Concise and expressive: You can write fewer lines of code while maintaining clarity, especially when chaining HTTP calls and data transformations.
– Rich ecosystem: Libraries like clj-http, cheshire, and compojure provide mature tools for making HTTP requests, handling JSON, and building web apps.
Chapter 1. Setting up your environment
Before diving into referee data with Clojure and the Sportmonks Football API, we need to set up a development environment that supports Clojure’s tooling and workflow. This chapter covers installing the language, creating a basic project, and preparing it to make HTTP requests and handle JSON.
1. Install Clojure
To write and run Clojure code, you’ll need:
– Java (JDK 11 or higher): Download here or install via your OS package manager.
– Clojure CLI tools: Follow the official installation guide: clojure.org/guides/install_clojure
To verify your setup:
clojure -Sdescribe
If installed correctly, it should print toolchain and JVM details.
2. Set up a project using deps.edn
Instead of using Leiningen (which is still valid), we’ll use the Clojure CLI with a deps.edn project structure. Create a folder:
mkdir sportmonks-clojure cd sportmonks-clojure
Create a deps.edn file with the following content:
{:deps {org.clojure/clojure {:mvn/version "1.11.1"} clj-http/clj-http {:mvn/version "3.12.3"} cheshire/cheshire {:mvn/version "5.11.0"}}}
This sets up three dependencies:
– clojure: The language itself
– clj-http: For making HTTP requests
– cheshire: For parsing JSON into Clojure maps
3. Add a source directory
Create a simple source file:
mkdir -p src/sportmonks touch src/sportmonks/core.clj
Open src/sportmonks/core.clj and add:
(ns sportmonks.core (:require [clj-http.client :as client] [cheshire.core :as json])) (defn -main [] (println "Sportmonks Referee API with Clojure!"))
Run it using:
clojure -M -m sportmonks.core
It should print:
Sportmonks Referee API with Clojure!
4. Get your Sportmonks API token
To authenticate your API calls:
– Log into my.sportmonks.com
– Navigate to the “API Tokens” section
– Copy your personal token
You’ll need this token in upcoming code snippets. For security, you can pass it as an environment variable or store it in a .env file (with a library like environ if you prefer).
5. Setting up environment variables
Instead of hardcoding the API token in your code, store it securely as an environment variable.
a) Define it in your terminal session:
export SPORTMONKS_API_TOKEN=your_token_here
To make this persistent, add it to your shell config (e.g., ~/.bashrc or ~/.zshrc).
b) Access it in Clojure:
(def api-token (System/getenv "SPORTMONKS_API_TOKEN"))
6. Choosing an IDE for Clojure development
For this project, we’d be using VScode
– Open the Extensions panel (Ctrl+Shift+X)
– Search and install Calva
Features include:
– Inline evaluation
– Autocompletion
– Syntax highlighting
– Integrated REPL experience
Chapter 2. Retrieving referee data using Clojure
Now that your environment is ready, it’s time to connect to Sportmonks’ Football API and fetch detailed data about a referee. We’ll use the endpoint to retrieve personal details, nationality, seasonal statistics, and information about the referee’s most recent fixture, all in a single response.
1. API endpoint overview
To get comprehensive referee information, we use:
GET https://api.sportmonks.com/v3/football/referees/{referee_id}
We’ll include additional data by appending parameters:
– country: Referee’s nationality
– statistics.details.type: Breakdown of actions like cards or penalties
– statistics.season.league: League context for the season stats
– latest.fixture.*: Details of the latest match officiated (scores, teams, statistics)
We’ll also add a filter to specify which season’s statistics we want:
&filters=refereeStatisticSeasons:{season_id}
Example full request:
https://api.sportmonks.com/v3/football/referees/15273 ?include=country;statistics.details.type;statistics.season.league;latest.fixture.statistics;latest.fixture.participants;latest.fixture.league;latest.fixture.scores &filters=refereeStatisticSeasons:23614
For this example, we’re getting information about referee Michael Oliver.
2. Writing the function in Clojure
In your src/sportmonks/core.clj, let’s add a function that fetches the referee data:
(ns sportmonks.core (:require [clj-http.client :as client] [cheshire.core :as json])) (def api-token (System/getenv "SPORTMONKS_API_TOKEN")) (def base-url "https://api.sportmonks.com/v3/football/referees") (defn get-referee-data [referee-id season-id] (let [includes (str "country;" "statistics.details.type;" "statistics.season.league;" "latest.fixture.statistics;" "latest.fixture.participants;" "latest.fixture.league;" "latest.fixture.scores") url (str base-url "/" referee-id "?api_token=" api-token "&include=" includes "&filters=refereeStatisticSeasons:" season-id) response (client/get url {:as :json})] (:body response))) (def referee-id 15273) (def season-id 23614) (def referee-data (get-referee-data referee-id season-id)) ;; Helper to extract nested count by type_id (defn get-count-by-type-id [details type-id] (some (fn [d] (when (= (:type_id d) type-id) (get-in d [ :value :all :count]))) details)) (defn print-referee-summary [ref-data] (let [ref (:data ref-data) name (:name ref) country (get-in ref [:country :name]) statistics (:statistics ref) stat-details (get-in statistics [0 :details]) total-matches (get-count-by-type-id stat-details 188) ; Matches yellow-cards (get-count-by-type-id stat-details 83) red-cards (get-count-by-type-id stat-details 84) penalties (get-count-by-type-id stat-details 47) league-name (get-in statistics [0 :season :league :name]) season-name (get-in statistics [0 :season :name]) last-fixture (first (:latest ref)) last-match-name (get-in last-fixture [:fixture :name]) home-team (get-in last-fixture [:fixture :participants 0 :name]) away-team (get-in last-fixture [:fixture :participants 1 :name])] (println "Name:" (or name "N/A")) (println "Country:" (or country "N/A")) (println "League:" (or league-name "N/A")) (println "Season:" (or season-name "N/A")) (println "Matches officiated this season:" (or total-matches "N/A")) (println "Yellow cards given:" (or yellow-cards "N/A")) (println "Red cards given:" (or red-cards "N/A")) (println "Penalties awarded:" (or penalties "N/A")) (println "Latest match:" (or last-match-name "N/A")) (println "Participants:" (str (or home-team "N/A") " vs " (or away-team "N/A"))))) (print-referee-summary referee-data)
What’s in the response?
You’ll receive a nested map with sections like:
– :name: Full name of the referee
– :country: A map with name, id, and image
– :statistics: Includes total matches, yellow/red cards, penalties, etc.
– :statistics.details: A breakdown by type (e.g. foul, penalty, yellow card)
– :statistics.season.league: League and season names
– :latest.fixture: The most recent game the referee officiated
Analyse referee trends with Sportmonks and clojure
Referee decisions shape every football match and now you can explore their patterns with precision. By combining Sportmonks’ football API with Clojure’s expressive tooling, you can retrieve rich referee profiles, match stats, and disciplinary trends to power smarter predictions and match previews.
Whether you’re building analytics tools, enhancing betting models, or adding depth to sports content, this integration helps you make data-driven decisions effortlessly.
Start your free trial today and bring referee intelligence into your Clojure applications.