Sports & Fitness — entry 027 of 33
Squiggle
Squiggle is a free JSON API for AFL fixtures, results, ladders, and its signature aggregated margin predictions pooled from multiple tipping models. Its own docs require setting a descriptive `User-Agent` containing a contact email rather than an API key, and since v1.11.0 the API actively refuses requests carrying common scraper user-agent strings, so `auth: None -> User-Agent` is corrected. A live Origin-header probe of the real host returned an explicit `{"error":"forbidden_origin"}` rejection for a cross-origin browser request -- reachable directly, but not CORS-open to arbitrary origins -- correcting `cors: yes -> no`.
Squiggle is a single-endpoint JSON API for AFL fixtures, results, ladders, and its signature aggregated margin predictions: every call hits the same root path with a q= parameter selecting the resource (teams, games, tips, ladder, and more). No API key is required, but the API actively rejects requests that don't self-identify with a descriptive User-Agent, and it refuses cross-origin browser calls outright regardless of UA.
GreatAPIs Score
Auth quickstart
- No API key or signup, but every request must carry a descriptive
User-Agentnaming your app and a contact method. A live GET this run with the defaultcurl/7.88.1UA still returned HTTP 403, and the response body nests the rejection inside the requested resource's own key:{"teams":[{"api_version":"1.13.2","your_user_agent":"curl/7.88.1","error":"bad_UA","warning":"Your UserAgent has not been set correctly. To avoid bans, please see https://api.squiggle.com.au/#section_bots"}]}— swapping in a UA likegreatapis.com quickstart (contact: hello@greatapis.com)returns the real data instead, confirmed live this run.
Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.
List AFL teams
GEThttps://api.squiggle.com.au/?q=teams
User-Agent: greatapis.com quickstart (contact: hello@greatapis.com)
{"teams":[{"retirement":9999,"logo":"/wp-content/themes/squiggle/assets/images/Adelaide.png","abbrev":"ADE","id":1,"debut":1991,"name":"Adelaide"},{"retirement":9999,"logo":"/wp-content/themes/squiggle/assets/images/Brisbane.png","abbrev":"BRI","id":2,"debut":1987,"name":"Brisbane Lions"},{"...":"16 more teams, same shape"}]}Try it
Developer reference
https://api.squiggle.com.au- GET/?q=teams
- GET/?q=games&year={year}&round={round}
- GET/?q=tips&year={year}&round={round}
Gotchas & limits
- A rejected request due to a bad User-Agent is HTTP 403, but the error payload is nested inside the requested resource's own array key (
teams/games/etc.), not a top-levelerrorfield — see the authSteps transcript above; a naive client that only checksresponse.okbefore readingdata.teams[0].namewill silently render the error object as if it were a team. - Cross-origin browser calls are refused outright, independent of the User-Agent check: a live GET with a correct UA plus
Origin: https://greatapis.comthis run still returned HTTP 403 with{"teams":[{"api_version":"1.13.2","message":"Cross-origin browser access from this origin is not allowed.","error":"forbidden_origin"}]}— server-side or same-origin calls only, no CORS workaround exists client-side. q=tipsreturns one row per tipster source per game, not one row per game: a liveGET /?q=tips&year=2024&round=1this run returned multiple entries sharing the samegameid(e.g.35704), each from a differentsource("Squiggle","Matter of Stats","Punters", ...) with its ownmargin/confidence— summing or averaging without grouping bygameiddouble-counts games.- The documented query syntax uses semicolons between parameters (
?q=games;year=2024;round=1), but a live test this run confirmed standard&-separated query strings (?q=games&year=2024&round=1) return byte-identical results — either separator works against the real host.