Kalshi Settlement Calendar & Order Book Depth
Kalshi markets ranked by when they settle, with the order book depth, spread and settlement source of each one.
datagrit › Data › Football Contract Expiry Radar - Transfermarkt
DataFootball players whose contracts end soon, per league and expiry window, with market value, trend, agent and extension options from Transfermarkt end-of-contract lists.
Football Contract Expiry Radar lists the players whose contracts end soon, league by league, from the Transfermarkt end-of-contract lists. You choose leagues and an expiry window (for example the next six months, or a date range) and get one flat row per player: club, position, age, nationality, contract end date, days until expiry, market value with its latest trend, extension option, fee paid and agency. Export the data as JSON, CSV or Excel, call it through the Apify API, or plug it into n8n, Make and AI agents through MCP.
It is built for scouts, agents, transfer-market analysts, football-manager communities, betting and fantasy researchers who want the free-agent and renewal pipeline of a league without opening hundreds of player profiles.
Every result is one flat record, so it drops straight into a spreadsheet, a database or a CRM.
| Field | Type | Description | Example |
|---|---|---|---|
playerId | string | Transfermarkt player ID. Empty only on the status row. | 433177 |
playerName | string | Player name as written on Transfermarkt. Empty only on the status row. | Bukayo Saka |
playerUrl | string | Transfermarkt profile URL of the player. | https://www.transfermarkt.com/bukayo-saka/profil/spieler/433177 |
position | string | Detailed position such as Centre-Back or Right Winger. | Right Winger |
positionGroup | string | Goalkeeper, Defender, Midfielder or Attacker, derived from the detailed position. Null when the position is not one of the standard ones. | Attacker |
dateOfBirth | string | Date of birth, YYYY-MM-DD. | 2001-09-05 |
age | integer | Age in whole years on the day of the run. | 25 |
ageAtExpiry | integer | Age in whole years on the contract end date. | 25 |
nationality | string | First nationality listed on Transfermarkt. | England |
nationalities | array | All nationalities listed on Transfermarkt; the nationality filter matches any of them. | ["England","Nigeria"] |
clubId | string | Transfermarkt club ID. | 11 |
clubName | string | Club the player is under contract with. | Arsenal FC |
clubUrl | string | Transfermarkt club URL. | https://www.transfermarkt.com/arsenal-fc/startseite/verein/11 |
competitionCode | string | Transfermarkt competition code the player was listed under. On the status row, all requested codes. | GB1 |
competitionName | string | Competition name with country. | Premier League (England) |
contractEndDate | string | Contract end date, YYYY-MM-DD, as listed by Transfermarkt. | 2027-06-30 |
daysUntilExpiry | integer | Calendar days from the day of the run to the contract end date; negative when the date has passed (only with past dates included). | 272 |
monthsUntilExpiry | number | Days until expiry divided by 30.4375, one decimal. | 8.9 |
expiresWithin6Months | boolean | True when the contract ends between today and six months from today. | false |
endDateInPast | boolean | True when the contract end date is before the day of the run (only with past dates included). | false |
contractOption | string | Contract option text from Transfermarkt, for example "Club option for a further year". Null when none is listed. | Club option for a further year |
extensionOptionType | string | none, club, both, performance, unspecified or other, derived from the contract option text. | club |
extensionYears | integer | Length of the option in years when the text states it; null otherwise. | 1 |
marketValueEur | integer | Current Transfermarkt market value in euros. Null when none is listed. | 120000000 |
previousMarketValueEur | integer | Market value before the latest revision, from the trend marker. Null when Transfermarkt shows no previous value. | 110000000 |
marketValueTrend | string | up, down or flat versus the previous value. Null when no marker is shown. | up |
feePaidEur | integer | Fee the current club paid, in euros; 0 for a free transfer. Null when not listed or undisclosed. | 0 |
feeType | string | fee, free, loan or undisclosed. Null when the list shows nothing. | free |
agentName | string | Agency listed for the player. Null when none is listed. | Stellar Group |
agentId | string | Transfermarkt agent ID. | 1061 |
agentUrl | string | Transfermarkt URL of the agency. | https://www.transfermarkt.com/stellar-group/beraterfirma/berater/1061 |
sourceUrl | string | Transfermarkt end-of-contract list page the row was read from. Empty only on the status row. | https://www.transfermarkt.com/x/endendevertraege/wettbewerb/GB1/jahr/2027/plus/1 |
found | boolean | False only for the single status row emitted when nothing matched. | true |
scrapedAt | string | ISO 8601 timestamp of the run. | 2026-10-01T11:10:00.000Z |
{
"playerId": "433177",
"playerName": "Bukayo Saka",
"playerUrl": "https://www.transfermarkt.com/bukayo-saka/profil/spieler/433177",
"position": "Right Winger",
"positionGroup": "Attacker",
"dateOfBirth": "2001-09-05",
"age": 25,
"ageAtExpiry": 25,
"nationality": "England",
"nationalities": [
"England",
"Nigeria"
],
"clubId": "11",
"clubName": "Arsenal FC",
"clubUrl": "https://www.transfermarkt.com/arsenal-fc/startseite/verein/11",
"competitionCode": "GB1",
"competitionName": "Premier League (England)",
"contractEndDate": "2027-06-30",
"daysUntilExpiry": 272,
"monthsUntilExpiry": 8.9,
"expiresWithin6Months": false,
"endDateInPast": false,
"contractOption": "Club option for a further year",
"extensionOptionType": "club",
"extensionYears": 1,
"marketValueEur": 120000000,
"previousMarketValueEur": 110000000,
"marketValueTrend": "up",
"feePaidEur": 0,
"feeType": "free",
"agentName": "Stellar Group",
"agentId": "1061",
"agentUrl": "https://www.transfermarkt.com/stellar-group/beraterfirma/berater/1061",
"sourceUrl": "https://www.transfermarkt.com/x/endendevertraege/wettbewerb/GB1/jahr/2027/plus/1/galerie/0",
"found": true,
"scrapedAt": "2026-10-01T11:10:00.000Z"
}
| Field | Name | Type | What it does |
|---|---|---|---|
competitions | Competitions | array | Competition codes to read, for example GB1 (Premier League), ES1 (LaLiga), IT1 (Serie A), L1 (Bundesliga), FR1 (Ligue 1), NL1, PO1, TR1, SA1, GB2. Supported leagues: GB1 Premier League England; GB2 Championship England; ES1 LaLiga Spain; ES2 LaLiga2 Spain; IT1 Serie A Italy; IT2 Serie B Italy; L1 Bundesliga Germany; L2 2. Bundesliga Germany; FR1 Ligue 1 France; FR2 Ligue 2 France; NL1 Eredivisie Netherlands; PO1 Liga Portugal Portugal; TR1 Super Lig Turkiye; BE1 Jupiler Pro League Belgium; SC1 Scottish Premiership Scotland; RU1 Premier Liga Russia; UKR1 Premier Liga Ukraine; GR1 Super League 1 Greece; DK1 Superliga Denmark; A1 Bundesliga Austria; C1 Super League Switzerland; TS1 Chance Liga Czechia; PL1 Ekstraklasa Poland; RO1 SuperLiga Romania; KR1 HNL Croatia; SER1 Super liga Srbije Serbia; BU1 efbet Liga Bulgaria; UNG1 Nemzeti Bajnoksag Hungary; SLO1 Nike Liga Slovakia; ZYP1 Cyprus League Cyprus; SA1 Saudi Pro League Saudi Arabia; QSL Qatar Stars League Qatar; UAE1 UAE Pro League United Arab Emirates; EGY1 Egyptian Premier League Egypt; JAP1 J1 League Japan; AUS1 A-League Men Australia; ISR1 Ligat ha'Al Israel. Each league and calendar year in the expiry window costs about 3 to 7 page requests. Enter ALL to read every league in the list; with a long window this takes many minutes, so raise Maximum run time. For a league that is not in the list, put its Transfermarkt code in "Other competition codes". |
customCompetitionCodes | Other competition codes | array | Optional. Extra Transfermarkt competition codes, for example BRA1 for the Brazilian Serie A or MLS1 for Major League Soccer. The code is the last part of the competition page URL (transfermarkt.com/premier-league/startseite/wettbewerb/GB1 means GB1). Codes Transfermarkt does not recognise are skipped and listed in the run status. |
expiringWithinMonths | Contract ends within (months from today) | integer | Expiry window counted from today: 6 lists players whose contract ends in the next six months, 12 within a year. Used for the end of the window when "Contract ends until" is empty. |
expiresFrom | Contract ends from (date) | string | Optional. Earliest contract end date, YYYY-MM-DD. Replaces the start of the window (today). A date in the past returns players whose end date has already passed. When set in the future without "Contract ends until", the window runs the months value from that date. |
expiresTo | Contract ends until (date) | string | Optional. Latest contract end date, YYYY-MM-DD. Replaces the end of the window. |
includePastDates | Include end dates already passed this year | boolean | Transfermarkt keeps players on the list after their end date until the club updates the profile. Turn on to include them from 1 January of this year (marked endDateInPast=true); off starts the window today. |
positionGroups | Position groups | array | Optional. Keep only these groups: Goalkeeper, Defender, Midfielder, Attacker (case-insensitive; any other value fails the run). Players whose detailed position does not map to a group are dropped when any group is chosen. |
nationalities | Nationalities | array | Optional. English country names as Transfermarkt writes them, for example Spain or Brazil. A player passes when any of their listed nationalities matches (case-insensitive). |
minMarketValueEur | Minimum market value (EUR) | integer | Skip players with a market value below this amount. Players without a listed market value are skipped as soon as a minimum above 0 is set. 0 keeps everyone. |
minAge | Minimum age | integer | Age today in whole years. 0 means no lower limit. |
maxAge | Maximum age | integer | Age today in whole years, for example 23 for young talents. 0 means no upper limit. |
extensionOption | Extension option | string | any keeps all players; withOption keeps players whose contract lists an extension option (a club can extend, so the contract may not really end); withoutOption keeps players with no option listed. |
onlyNewSinceLastRun | Only players not delivered before | boolean | Skip players delivered by an earlier run with the same competitions, window and filters (Maximum results, sort order and run time do not count as filters). A player comes back when the end date on Transfermarkt changes. Only players you actually received are remembered. |
sortBy | Sort and cut by | string | expiryDate returns the nearest end dates first, marketValue the most valuable players first. Maximum results cuts the sorted list, so the order decides which players you keep. |
maxItems | Maximum results | integer | Stop after this many players in total. Each player is one billed result. |
maxRunSeconds | Maximum run time (seconds) | integer | Hard time budget for reading Transfermarkt (about 0.7 seconds per page request). When reached, the Actor keeps everything read so far and says how many lists it covered in the run status. 0 removes the limit. |
proxyConfiguration | Proxy configuration | object | Optional proxy. Leave disabled unless Transfermarkt blocks datacenter traffic from your run; residential proxy raises the platform cost of the run. |
Run the Actor and get the results in one request. Replace YOUR_APIFY_TOKEN with the token from your Apify account settings.
curl -X POST "https://api.apify.com/v2/acts/datagrit~football-contract-expiry-radar/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"competitions":["GB1","ES1"],"expiringWithinMonths":12,"maxItems":50}'import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('datagrit/football-contract-expiry-radar').call({
"competitions": [
"GB1",
"ES1"
],
"expiringWithinMonths": 12,
"maxItems": 50
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);Install with npm i apify-client.
from apify_client import ApifyClient
import os
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("datagrit/football-contract-expiry-radar").call(run_input={
"competitions": [
"GB1",
"ES1"
],
"expiringWithinMonths": 12,
"maxItems": 50
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(len(items), items[0] if items else None)Install with pip install apify-client.
Kalshi markets ranked by when they settle, with the order book depth, spread and settlement source of each one.
Polymarket markets that pay liquidity rewards, joined with the live order book: reward pool, qualifying depth and estimated payout per market.
Find EU public contracts approaching expiry from TED award notices: incumbent, buyer, value, end date and renewal options.
UK public contracts ending soon with incumbent supplier, buyer, value and contact - recompete leads from Contracts Finder award notices.