In order for SquashLevels to be a fully inclusive system it needs player details and match results from all players. We already have quite a few systems sending us results from events, leagues and boxes and are actively working with others to bring them on line as well.
This document outliines what it takes to get connected and is intended to be passed to the tournament and league system providers so that they can see what's involved and what they need to do to get connected.
There are good reasons to get connected:
It's surprisingly easy to get connected so please ask your webmaster to take a look at the spec below and get in touch with us. We'll have you on board in no time!
The is the first step for being able to pull your results from the system that collects them. That system (such as a league management or internal club boxes system) needs to provide a dedicated web page that has the most recent results (and any that have been updated recently) in CSV format as an API endpoint with a single parameter; days.
We normally pull these results every night (UK time) with the days paramater set to 3 so we have a moving window of three days. This allows for issues, missing feeds or whatever to occur without actually missing any results as we have three attempts at each day. Note the need to include updated results in the feed so, for instance, a match from two weeks ago that was updated yesterday is included in the feed and is therefore not missed.
The days parameter is very useful because it allows us to go back further without needing to contact the provider. reasons for this might be:
SquashLevels reads these provider pages every night and pulls the results in. It's really very straighforward.
For authentication (to prevent access to results from other parties) we recommend either using some undocumented parameters or the use of some authentication fields in the header both of which can be checked by the provider. We don't recommend checking the IP address of our server because that can change.
Here's an example of a results CSV file located at: https://devs.squashlevels.com/cdn/squash/site/example-results.csv
source=badsquash
county=Avon
Date,Time,Player1,ID1,ESM1,Club1,Category1,Sex1,Player2,ID2,ESM2,Club2,Category2,Sex2,Results,Matchtype,FixtureID
2019-11-01,11:10:00,Giles Taylor,10891,,Redland Squash,Senior,Male,Sarah Trevelyan,1565,ES0123456,Redland Squash,Senior,Female,"5-9,9-5,9-7,9-5",Redland Green Boxes,33647770
2019-11-05,14:40:00,Paul Redmore,3769,ES0123456,Bradley Stoke Squash Club,Senior,Male,Ken Guy,2501,,Workout Harbourside,Senior,Male,"3-1",Workout Harbourside Lunch Time Boxes,33648769
2019-11-05,19:40:00,Viri Chauhan,7894,ES0123456,Redland Squash,Senior,Male,Lester Griffiths,9349,ES0123456,Redland Squash,Senior,Male,"11-15,10-15,15-12,8-15",Redland Green Boxes,33648790
2019-11-05,20:30:00,Cez Kocialkowski,11400,,Redland Squash,Senior,Male,Ross Rakauskas,12591,,Redland Squash,Senior,Male,"4-9,3-9,3-9",Redland Green Boxes,33648810
2019-11-05,20:50:00,Mark Woodard,3906,ES0123456,Redland Squash,Senior,Male,Steve Gale,10829,ES0123456,Gordano,Senior,Male,"17-15,16-18,11-15,7-15",Redland Green Boxes,33648830
2019-11-05,21:00:00,Phil Martin,9471,,Workout Harbourside,Senior,Male,Adam Sharpe,12990,,Workout Harbourside,Senior,Male,"17-15,14-16,10-15,15-12,13-15",Workout Harbourside Boxes,33648850
2019-11-05,21:10:00,Ross Rakauskas,12591,,Redland Squash,Senior,Male,Paul Matthews,6155,,Redland Squash,Senior,Male,"7-9,9-4,9-3,9-1",Redland Green Boxes,33648870
2019-11-06,05:50:00,Martin Evans,10647,,Westbury David Lloyd,Senior,Male,Anthony Fairweather,10475,,Westbury David Lloyd,Senior,Male,"1-9,2-9,3-9,9-5",Westbury David Lloyd Boxes,33648890
2019-11-06,08:10:00,Jean Paul Thorogood,12899,,Workout Harbourside,Senior,Male,Andy Chesters,13191,,Workout Harbourside,Senior,Male,"12-15,15-12,7-15,15-13,10-15",Workout Harbourside Boxes,33648910
2019-11-06,19:00:00,Dave Allman,4216,ES0123456,Redland Squash,Senior,Male,Emma Chorley,4624,ES0123456,David Lloyd,Senior,Female,"11-1,11-2,11-5",Mixed Autumn 2019-20,33512650
2019-11-06,19:00:00,Tom Gogarty,11685,ES0123456,Redland Squash,Senior,Male,Simon Hygate,76,ES0123456,David Lloyd,Senior,Male,"8-11,11-9,11-7,11-3",Mixed Autumn 2019-20,33512651
2019-11-06,19:00:00,Mike Nichols,456,ES0123456,Redland Squash,Senior,Male,Jason Mathias,73,ES0123456,David Lloyd,Senior,Male,"11-6,11-5,11-7",Mixed Autumn 2019-20,33512652
2019-11-06,19:00:00,Phil Rea,8668,ES0123456,Redland Squash,Senior,Male,Ross Morrell,608,ES0123456,David Lloyd,Senior,Male,"11-6,13-11,6-11,17-15",Mixed Autumn 2019-20,33512653
Each row represents a single match result between two players. Each column contains the data for each of the players, the result and the type of match. If data about a player (such as their club) is received then that player's information on the system can be updated. That way, player data can be maintained by the source system without individual players having to maintain it themselves.
We can receive and use a lot of data about the match, the players and the result with all the available fields listed below. Most of the fields are optional but the more data that is provided the better the player's experience will be. A fiew fields are mandatory and these are marked with a '*' below. For GDPR compliance, please don't send us data that we can't use.
The players are numbered 1 or 2 for singles or _A1, _A2, _B1, _B2 for doubles. E.g. the club heading for the first player would
be Club1 for singles or Club_A1 for doubles. In the list below we are showing
The column headers are case insensitive. They are shown here capitalised for readability.
We can also receive federation membership numbers and IDs. These are discussed and agreed with the federations.
Scoring systems - based on the supported sport, we can auto-recognise the scoring system used. We like to go down one level of detail as this really improves the dynamic accuracy of the level calculations. E.g. for squash, "11-7, 11-9, 13-11" is much better than "3-1". For Padel/Tennis, "6-4, 3-6, 5-7" is much better than "1-2" though we can use these higher level scores if that is all that is available.
Geography - We use three tiers of geography if available; country, region and club for the player's club. This effectively tells us where the player is playing and allows us to cut the rankings by these fields so the use of region is country speific. We support counties, districts, states, principalities, etc., etc. Note this is different to the player's country as that is personal to the player.
Match types - We use the match type to determine the weighting of the match; club matches are weighted less than tournaments for instance. We also use match types to group players into pools for the calibration. I.e. players in the box leagues at a club would in one pool whereas everyone in a regional tournament would be in another. With this in mind we like to set the match type at that sort of resolution. Examples are:
These are two low or two high resolution for a match type:
Ideally the source system can provide a good deal of this information but SquashLevels will assume players are senior, males with no club, region or country. MatchtypeID and FixtureID are also optional but very useful for connecting our respective systems. The absolute minimum fields are; Date, PlayerX, IDX, Results, Matchtype but that does leave it to the player to fill out and maintain the rest manually on the system.
The source system IDs are mapped to their SquashLevels ID and these mappings are maintained for all source systems. This is done automatically if they have the same name and the same region otherwise they are left as separate players to be merged later. If the federation membership number is included in the player results then that will be used to match up possible duplicate players. All source systems are allocated a name when they link up.
Note matches can also be posted asychronously using the SquashLevels API. This allows for results to be processed immediately and updated levels returned but please be aware we can only do a sub-set of the processing on a single result and the levels will almost certainly be updated (a little) during the nightly processing. Matches from events are also often received out of order which will also affect levels. Only after the nightly processing can we really say what a player's level is.
Please see the section below for details on this API endpoint call.
SquashLevels is predominently all about receiving match results and calculating levels based on those. We also support tournament based rankings where the information we need is focused on the final position that a player reached in each event. We pull the results in the same way (see results upload above) but in this case we need the following fields in the returned CSV.
So that the systems form a community for the players (and not just a set of isolated systems) there should be two way links between the source systems and SquashLevels. This is part of the requirements of getting connected.
Links from SquashLevels to the source systems
These links provide single click access back to the source systems allowing the players fast access to the pages that are of most interest and specific to them. If you have a page you'd like us to link to then please let us know.
By default, players are referenced by their source system ID so it is easy to create links from the source system.
If you have a logo URL we would like to use it!
Links from the source systems to SquashLevels
These links provide single click access to SquashLevels pages of most interest to the players such as rankings and player history. Note that any links can be used but page content will depend on whether the player has previously logged on to SquashLevels. If so then then full page content will be available otherwise it will be slightly reduced. This feature relies on the player using cookies.
These links work well from the source system home page.
https://app.devs.squashlevels.com
.https://app.devs.squashlevels.com/players?all&source=<source name>&list=county
.
Click here
for example.Please use our full logo (https://devs.squashlevels.com/cdn/squash/site/logo-combi-black.png
) with your links.
If you're short of space you can use just our logo icon (https://devs.squashlevels.com/cdn/squash/site/logo-icon
).
These links work well from the source system player detail page.
https://app.devs.squashlevels.com/player_detail?player=<source player ID>&source=<source name>
.https://app.devs.squashlevels.com/match_detail?match=<source match ID>&source=<source name>
.https://app.devs.squashlevels.com/players?all&player=<source player ID>&source=<source name>&list=club
.https://app.devs.squashlevels.com/players?all&player=<source player ID>&source=<source name>&list=county
.https://app.devs.squashlevels.com/player_detail?source=<source name>&player=<source player ID&h2hid=<source opponent ID>&show=last24m
. Note this is a feature of SquashLevels premium members.Many of the user readable web pages on SquashLevels can be returned in JSON format for system consumption by adding
the parameter format=json
. All parameters are passed in using the GET method - which is the equivalent of
typing in the URL on your browser.
E.g. https://app.devs.squashlevels.com/players?all&source=<source name>&list=county&format=json
.
Click here
for an example.
The data is returned as a JSON list with value:ID pairs for each piece of data. This allows source systems to include the SquashLevels ranking lists directly on their own pages.
SL-client parameter
If you want to make use of these endpoints from your server (which is the expected usage model) then you'll need to add the SL-clent parameter. This allows you to get through our crawler filter and also we can track your use of the API. Please ask and we can provide you with a SL client ID.
JSON structure
All returned JSON structures use the following format:
{"status":"<good/bad/warn>",
"message":"<Text message explaining result or failure>",
"user_message":"<Text message for the user - generic news or telling them that they need to be a member>",
"data":{<returned data>}}
The message text is mainly to use if something goes wrong - it will tell you what. The user text message is to show the user. This might be generic news such as system downtime planned (not that we ever take it down) or, more likely, that the feature they're asking for needs them to be logged on as a member. Mostly, this user message will be blank. The data that was requested will be returned in the 'data' field.
Player listings (rankings)
The players page is used for player listings for both the web page and JSON output. The listings are controlled using the following parameters:
The defaults are set to list all players for the last 12 months with no other restrictions but they can be overridden by cookies which are set to the filters used for the last player listings selected. This allows users to set up the player listings that they want to see and then that's what they'll always see if they don't change it.
Access to club and county IDs
It may help to be able to list the full set of club and county IDs used by the system. They are dynamically added to but once defined, not normally changed (unless duplicated clubs are merged). Use the following page for JSON output:
https://https://app.devs.squashlevels.com/api?action=list_clubs&format=json
Finding out processing state and results upload history
If you intend to cache any data locally to your own system, you should be aware that SquashLevels reprocesses its levels over night and may have made changes during that process. You can use the URL below to return a JSON structure that will tell you what the processing state currently is and when it last changed state. The state is shown as 'completed' at the end of processing. You can use this to determine when to refresh your cached data.
https://https://app.devs.squashlevels.com/api?action=process_summary&format=json
This URL also returns a summary of the uploaded results for the last 7 days. You will find a structure showing the upload count for each source/matchtype/date combination for the last 7 days. You should be able to find out how many results SquashLevels has received from your system using this structure.
This section is available to approved users only. You should only be able to see it if you have logged on with the provided credentials but please note that all accesses are tracked and unapproved access and/or usage of this imformation will be followed up.
Locks, keys and app IDs
Some of the data is restricted and needs a key to access it. This is a time based key to prevent web spiders or other forms of mal-intent from accessing private data or functionality that can modify the system data. Please do not forward this information on to unapproved parties!
The time-based key takes the form key=xxxxx where xxxxx is a numeric key. It is derived by taking the unix time now, multiplying by 100, square rooting that and subtracting 100. I.e.
key = sqrt(time() * 100) - 100
Round to the nearest integer. This has the advantage of not looking like anything familiar (such as a unix time stamp) and it also gives a range of a couple hours either side so that if the clocks are mis-aligned the key will still work.
You can check your key using the following URL.
https://app.devs.squashlevels.com/api?action=test_comms&key=380455
All privilaged users - such as the apps - need to use an app ID to identify themselves. This helps track usage, stops the system thinking you're a web spider and also allows the system to behave differently for the different apps and even different app versions. We will agree an app ID to use for your app such as 'SL1.6'. For this example, please append every URL call with a parameter of the form appid=SL1.6.
There is also a generic client equivalent for those clients that are not apps. Please use a parameter of the form SL-client=XYZ1.0. Again, we will need to agree an appropriate client ID.
If the key is needed and not provided or invalid, the request will return the 'invalid comms key' error.
Logging in
The system recognises a logged on user from their session data and, if that doesn't exist, then from their BADSQUASH_PERSIST cookie. The following URL will log a user on and return their BADSQUASH_PERSIST cookie value:
https://app.devs.squashlevels.com/api?action=login&email=<email address>&md5password=<MD5 of the password>&stay_logged_in=1&format=json
Find out which systems are supported by this code base
A single code base supports a number of league systems and the main ranking system so to find out what is supported and get a list use the following URL for any of the systems - they will all return the same data.
https://app.devs.squashlevels.com/api?action=supported_systems&format=json
Data returned includes the name of the system, the URL to reference it by, the type of system (league or ranking) and the location of a logo that can be used for that system.
Access to player history
The same information that is available in HTML is pretty much also available in JSON but using the format=json parameter.
https://app.devs.squashlevels.com/player_detail?player=591&format=json
Note that the data returned is split into the same main sections as for the web version:
Setting a player's device ID
This associates a player with a particular device which is useful for locking functionality such as scoring a match to a particular device. E.g. to add the deviceid 20013feab6bcc730d to your log-on use the following:
https://https://app.devs.squashlevels.com/api?action=set_player_deviceid&deviceid=20013feab6bcc730d
The user does need to be logged on so that the system knows who the device ID needs to be associated with. If the functionality is not concerned about device ID then this will have no effect but if it does, it will allow that functionality to be used once the device ID has been set.
This is used in conjunction with posting match results to the staging area which is explained below.
Looking up players
This allows you to dynamically enter a player's name and have suggestions dynamically offered which is what happens with the 'Find' page on the main site. Use the following URL:
https://app.devs.squashlevels.com/api?action=find&name=j+smith&key=380455&format=json
This will give a list of player names that match the text entered along with the player attributes (player ID, club, county, country, gender, age groups etc.). A maximum of 50 names are returned.
Full set of parameters and options
Endpoint: https://app.devs.squashlevels.com/api
Parameters:
How to use
Use mindateint and withheld as additional filters. Please check with us before using withheld=1 as these players have specifically asked to be buried.
Adding a player using source player ID
If you can't find the player you're looking for then you can add them. We only need their name and source ID to at least create a player profile for them. We may inclue more player attributes in future though the player can either update those directly on SquashLevels themselves or they will be updated as results come in for them.
Endpoint: https://app.devs.squashlevels.com/api
Parameters:
You'll get back:
If we already have a player mapped to your source/source_playerid then we return good, the player ID and name we have for them. We won't add a new player in this case so you should check if it's the same name... We can't have two players mapped to the same source ID.
Adding a source player ID link
We use a mapping from the player ID on the source system to our own player ID to know who the players are when the results come in. We also use source player mappings for things like membership numbers for the various federations.
You can use an API call to add a mapping from your source player ID to our player ID for a source.
Endpoint: https://app.devs.squashlevels.com/api
Parameters:
Removing a source player ID link
We use a mapping from the player ID on the source system to our own player ID to know who the players are when the results come in. We also use source player mappings for things like membership numbers for the various federations.
You can use an API call to remove such a mapping from your source player ID to our player ID for a source.
Endpoint: https://app.devs.squashlevels.com/api
Parameters:
You don't need to provide our player ID as we can look it up. We will let you know if we actually found the player to unlink in the response.
Viewing extended ranking lists without being logged in
This is intended for access by external systems such as the apps. If you want to pull a large number of players at once then you can use the key rather than being logged in. E.g. Use the following URL:
https://app.devs.squashlevels.com/players?all&perpage=1000&key=381761&format=json
This will give the rankings of 1000 players from a single call.
Getting the list of fixtures
The league process is centered around fixtures and using the following URL you can get hold of the complete set of seasons, leagues, divisions, clubs and teams along with IDs and match dates for the current leagues. It returns a lot of data (around 90 KB) but it's very useful to have all this to hand.
badsquash.co.uk/info?action=list_fixtures&key=380455
Getting the fixtures and results for a specific team
This is a way of getting the data returned from the table in the top left of the team page. Includes captain's details, the list of fixtures, opponents, results, availability etc. It returns the data for the most recent division that the team is playing in. Use the normal team page but add 'format=json' to the URL.
badsquash.co.uk/team?team=109&key=380455&format=json
Posting match results to the staging area
This is specific to the league system and is for staging the results as they come in which allows external viewing of the results as the match is progressing and also both captains can see the results before agreeing on them and sending them off to the system as the official record. The official record is where the results go when entered manually.
The following URL shows how to post a single result from string 2 for a specific match ID. Note that it includes the device ID referred to above to ensure that no-one else can post a result for the same match.
badsquash.co.uk/info?action=post_single_match&key=380455&matchid=12345&string_2_result=homeplayer:John%20Smith,awayplayerid:591,scores:9-3|9-4|9-5&deviceid=20013feab6bcc730d
Use player ID if you can but you can add a new player using the name as shown in the example. Note the format of the scores. This is how they are stored and you can post at any time so you can post the results for a match that's currently in progress.
You can include the results from multiple strings by including them in the URL. Results are additive so if you post a string 1 result and there's a string 2 result already recorded then both will be preent in the staging area.
Accessing match results from the staging area
To show intermediate results or to show the captains the results from the staging area use the following URL:
badsquash.co.uk/info?action=retrieve_match_data&key=380455&matchid=12345
Posting a single match straight in to the DB
A match can be sent to us via a POST to https://app.devs.squashlevels.com/api with the following example parameters. This example is just a sub-set of the available parameters - it's good if you can include club and region information as well - but you can get away with the list below. See the definition of the CSV format above for the full set of parameters that we can receive.
Note (see the examples below) that player spcific values can be passed in using fieldX (e.g. club_A1=xxxxx) or you can pass them in as a value to be used for all players (e.g. club=xxxx). This applies to club, region and country only.
We accept the same fields as per the CSV format input above
Note that you can also use GET. POST is preferred as the parameters are not so visible but you can use GET to get it working and then switch to POST afterwards.
action=add_result // the action parameter to use with the info URL
key=380455 // this is the time based key check (see above)
datetime=2015-03-09 19:00:00
nameX=James Barlow // Details for the players
idX=1394 // This is the source ID, not the SquashLevels ID
clubX=Redland // This is the club for the specific player
.. Values for the other player(s) here
country=ENG // Club/region/country like this applies to all players in this match
scores=6-4|7-5|6-3 // Pairs of numbers is all that's needed
matchtype=Redland Open 2024 // Use an existing match type or a request a new one to be auto-added
fixtureid=4386 // A unique integer ID to identify the source match
source_name=mysource // We need a source name to map the IDs to. Please agree with us first.
process // Force the levels to be calculated now. Leave parameter out otherwise.
SL-client=myclient1.0 // The agreed Client ID
Here's an example of what comes back. This example is singles, doubles results will return with four player updates. Note the use of homeplayer, awayplayer (and then homeplayer2 and awayplayer2 for doubles). This is somewhat historic and we might update to support player_A1 etc., in future.
{
"action":"Updated[P]",
"matchid":"3929434",
"timing":"Look up\/add players: 0.06 Look up match: 0.005 Process match: 0.003 Recalculate levels: 0.006 Initial levels: 0.001 Add match total: 0.077 ",
"issues":"",
"homeplayerid":"591",
"awayplayerid":"210879",
"valid":1,
"title":"Richard Bickers v Nev Saunders (Mon 09 Mar 2015)",
"duplicates":[
],
"homeplayer_levels":{
"playerid":"591",
"matchid":"3929434",
"matchtypeid":"7085",
"clubid":"1497",
"levelbefore":"1034",
"levelafter":"997",
"dampedlevel":"-1",
"position":"-1",
"leaguetypeid":"0",
"opponentid":"210879",
"ratio":"0.72",
"confidence":"-0.133",
"dateint":"1425927600",
"stale":"0",
"backfill_order":"292"
},
"awayplayer_levels":{
"playerid":"210879",
"matchid":"3929434",
"matchtypeid":"7085",
"clubid":"1497",
"levelbefore":"1106",
"levelafter":"1150",
"dampedlevel":"-1",
"position":"-1",
"leaguetypeid":"0",
"opponentid":"591",
"ratio":"1.4",
"confidence":"-0.15",
"dateint":"1425927600",
"stale":"0",
"backfill_order":"88"
}
}
}
Uploading a photo for a player
The photos are displayed at the top of the player's history page (not implemented yet). Use the following URL to upload a photo to the system. Note there is no processing done on the photo such as resizing so avoid large photo file sizes or it will take too long to render on the browser (and consume file space).
It's done via a POST to info with the following example parameters:
action=upload_photo // the action parameter to use with the info URL
key=380455 // this is the time based key check
playerid=591 // this is the player who's photo it is
@filename // this is the filename that contains the photo. Note the '@' for file transfer.
The file will come over with information including the filename so the system can extract the .png or .jpg postfix from it. Octet streams are fine to get the binary data across so no need to say it's image/png for instance.
You'll get a response along these lines:
{"status":"good",
"message":"Photo uploaded",
"data":{"name":"Richard.jpg",
"type":"application\/octet-stream",
"error":0,
"size":116293,
"location":"photos\/spa_playerid_591.jpg",
"player_name":"Richard Bickers"},
"user_message":""}
You'll see the filename returned along with its size but also the location where it's being stored on the system. You can also work out the filename from the playerid fairly easily instead if you prefer. See photo download section below.
The player info from player_detail also includes the location of the photo so if you pull that you'll know if there's a photo or not for any player.
Extracting a photo for a player
Extraction is as simple as accessing the photo directly from the website e.g.
https://app.devs.squashlevels.com/photos/spa_playerid_591.jpg
If there isn't a photo you'll get 'page not found' or if you check the player info (see above) first to get the file location then you can see if there's a photo or not.