Install
openclaw skills install @chrischall/setlist-fpxQuery and update setlist.fm from a shell without running the setlist-mcp server — search/read concert setlists, artists, venues, cities, and users via plain curl against the public REST API (an x-api-key header), and toggle "I was there" attendance on a setlist via the authenticated website, using an fpx-captured session cookie. Use when you want setlist.fm data or want to mark/unmark attendance without the MCP, in a script, or on a machine where the MCP isn't installed.
openclaw skills install @chrischall/setlist-fpxsetlist.fm is hybrid: reads and writes use two different surfaces.
api.setlist.fm/rest) keyed by
an x-api-key header. Plain curl, no browser, no fpx.www.setlist.fm, server-rendered Apache Wicket), not the REST API. There's
no login form to script — the credential is your browser's session cookie.
fpx lifts that cookie out of your signed-in tab once; every actual
request afterward is plain curl carrying it. No bridge round-trip per call.This is the same data/actions the setlist_* MCP tools expose, reached with
curl instead of a running server.
Apply for a free key at https://www.setlist.fm/settings/api, non-commercial use only (see API terms below), then:
export SETLIST_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
curl -s 'https://api.setlist.fm/rest/1.0/search/artists?artistName=Radiohead' \
-H "x-api-key: $SETLIST_API_KEY" -H 'Accept: application/json' \
| jq '.artist[] | {name, mbid, url}'
Accept: application/json is required — the API serves XML otherwise.
Optional Accept-Language: en|es|fr|de|pt|tr|it|pl localizes city/country
names. Standard tier is ~2 req/sec, 1440/day — a 429 means slow down.
Dates are dd-MM-yyyy on the wire (NOT ISO) for date search params and
lastUpdated (yyyyMMddHHmmss); eventDate comes back the same way in
responses — convert both directions yourself (the MCP does this for you via
dmyToIso/isoToDmy; a shell one-liner: date -j -f '%Y-%m-%d' '+%d-%m-%Y'
on macOS).
The full request catalog (all 15 read endpoints, params, and jq projections)
is in references/rest-api.md.
Every entity is keyed by an id you get from a search: artists by mbid
(MusicBrainz id), setlists by setlistId, venues by venueId,
cities by geoId. Search first, then feed the id into the matching
get/setlists endpoint. Got a setlist.fm URL instead of an id? The id is
the trailing hex token before .html, e.g.
.../setlist/.../...-4ba8a766.html → 4ba8a766 — no fetch needed.
The API terms require a followable link to setlist.fm wherever this data
is shown. Every artist/setlist/venue object has a url — surface it as a
clickable link (no nofollow) when you present the data. Also: no
persistent caching (fetch live each time, don't build a local store) and
non-commercial use only on the free key.
There is no API for this — it's the logged-in website's Wicket AJAX
control, so you need your own www.setlist.fm session cookie.
npm install -g @fetchproxy/cli # provides `fpx`
fpx profile add setlist --domain setlist.fm # apex scope
fpx pair -p setlist # prints a pair code → approve in Transporter
Requirements: the Transporter extension installed, an open, signed-in
www.setlist.fm tab, and Chrome Site access allowing setlist.fm.
Pairing persists after the first approval.
The session cookie (JSESSIONID) is HttpOnly — only fpx cookies
(which uses chrome.cookies.get, not page JS) can read it:
COOKIE=$(fpx cookies -p setlist --domain www.setlist.fm \
| jq -r '[.JSESSIONID, .RememberMeCookie, .["aws-waf-token"]]
| map(select(. != null)) | join("; ")')
JSESSIONID (Wicket session) or RememberMeCookie (remembered login) must
be present — if both are empty you're not signed in on that tab. COOKIE is
now a ready-to-send Cookie: header value; every curl below reuses it. A
browser-like User-Agent is required too — the bare curl default trips the
site's bot heuristics:
UA='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36'
Full walkthrough (resolve the setlist URL, fetch the page, parse the toggle
control, replay it, verify) is in references/attendance-write.md — it's
several steps, not a one-liner, because the control is a per-render Wicket
AJAX anchor you must parse out of the page HTML first.
Always dry-run first: read the page, check the control's current state, and only send the AJAX toggle if it doesn't already match what you want. Never trust the toggle's response status as proof — always re-fetch the page afterward and re-check the control's state.
api.setlist.fm is a normal HTTP
error — 403 on a valid-looking key usually means a bad/revoked key, not
"no key" (that's a 401).fpx cookies exit codes — 2 bridge unavailable
(extension not connected / not paired → fpx pair -p setlist), 3 bot
wall, 4 upstream non-2xx. Once you have COOKIE, subsequent curl
failures are yours to diagnose (see "session expired" below) — fpx is
out of the loop.href="/signin" or /login link instead of the
attendance control) — re-run the cookie capture (re-approve in Transporter
if needed) and retry.SETLIST_API_KEY and the fpx cookie
capture on completely separate paths, same as the MCP does.fpx health -p setlist shows bridge connection state if the cookie
capture fails outright.