Install
openclaw skills install @jdm0830/southwest-seat-monitorSouthwest-specific seat monitor. Watch a specific Southwest segment's seat map (via the tokenized reservation seat flow) for a window/aisle/exit seat becoming available, and alert the agent when one opens. Use when the user asks to monitor Southwest seat availability, watch for a Southwest window seat, or track seat openings on a Southwest booking. Companion to the generic seat-monitor skill (read that first) and the travel-agent skill.
openclaw skills install @jdm0830/southwest-seat-monitorImplementation layer for the generic seat-monitor pattern, specific to Southwest Airlines
(assigned seating, post-2025 model). Read-only. Never submits a seat change.
The only route that loads a real seat map:
https://www.southwest.com/loyalty/myaccount/ — signed-in account page.
Details link → /air/manage-reservation/view?searchToken=…
Upgrade or modify seats →
/air/seat/select-seats?clk=TRIPDETAILS_UPGDSEAT_LINK&searchToken=…
Change or Upgrade Seats → /air/seat/?clk=GFOOTER-AIR-SEATS.
It has no token and renders an empty shell (air-seat-index, no seats). This is THE trap.FLIGHT 2 of 2 MCO to LAS (buttons read
FLIGHT <n> of <total>\n<ORIG>\nto\n<DEST>\n<duration>).Every seat is a <button> with an aria-label like:
Seat 4F $94. (Chargeable, Front cabin, Extra leg room, Window)
Seat 8E Selected for passenger number 2 JUAN MAZO. $38. (Chargeable, Preferred, Over wing, Middle)
Seat 1A $94. (Chargeable, Front cabin, Bulkhead seat, Extra leg room, Window) unavailable
disabled / aria-disabled="true" / class contains
disabled when taken. Available seats are enabled.Window / Middle / Aisle.seat__… occupied__…, seat__… preferred__…, seat__… extraLegRoom__…,
seat__… standard__…, seat__… unavailable__….GET /api/seat-management/v1/seatmaps/selections (arrives only when entered via the tokenized
flow; ~52–66 KB). Shape:
data[0] = {
flight_segment: { marketing_flight_number, origination_airport_code, destination_airport_code,
depart_at, flight_equipment_type_code },
cabins[0]: {
columns[7]: [ {type:"SEAT", column:"A", position:"WINDOW"}, … ] ← the legend
rows[33]: [ { row_number, seats: [ { column, characteristics[], available: true|false,
price:{…} } ] } ]
},
price_summary: { CHARGEABLE, PREFERRED, EXTRA_LEGROOM, EXIT_ROW, STANDARD, … },
original_seats: [ { row, column, characteristics[], passenger_id, … } ] ← the user's seat
}
GET /api/seat-management/v1/reservations?search_token=… and
GET /api/air-manage-reservation/v1/reservations?search_token=….From cabins[0].columns (and the visible header):
A = WINDOW B = MIDDLE C = AISLE | D = AISLE E = MIDDLE F = WINDOW
→ Window seat = column "A" or "F". Always confirm from the map's own columns array; aircraft
type can vary (73H, 7S7, …).
GET /api/loyalty-management/v2/loyalty-management/accounts/self/future-air-reservations-secure
→ trips, segments (segment_identifier 1=outbound, 2=return), and
passengers[0].seats[] = {segment_reference, seat_number, characteristics[]}.GET /api/security/v4/security/userinfo → session validity.page.goto() these JSON endpoints directly — direct endpoint hits get 403 (Akamai).
Navigate the UI and capture passively./usr/bin/google-chrome-stable) with a persistent profile,
driven over CDP, on a VNC/X display. Bundled Chromium is a weaker fingerprint.~/.openclaw/state/southwest/monitor4.mjs — v4, agent-alerting + session health:
--once single check; default = loop with randomized 8–18 min (3–5 min within final 24h).SW_STATE, SW_CDP, SW_TARGET_LABEL, SW_TARGET_AIRPORT,
SW_WINDOW_COLUMNS, SW_DAILY_CAP, SW_WAKE_START/END, SW_MIN_MIN/MAX_MIN,
SW_TIGHT_MIN_MIN/MAX_MIN, SW_FLIGHT_DEP, SW_AGENT_SESSION.monitor.log, alerted-windows.json, counter.json, health.json, monitor-out/latest-seats.json.SW_AGENT_SESSION), which relays to the human as needed.| Symptom | Cause | Fix |
|---|---|---|
| seat page shows no seats | used footer link (no token) | use Details → Upgrade or modify seats |
| no seat link found | SPA hadn't rendered | poll for the link (up to ~15–20 s), don't check once |
| 403 on trips/seat JSON | direct endpoint goto() | navigate the UI, capture passively |
| signed-in check fails | session expired | health alert → human re-login in the profile |
| wrong leg's seats | seat page defaults to outbound | click the FLIGHT n of m <DEST> segment button |
The reference impl is a bare node process — survives session end, not reboot. To survive reboot, wrap in a systemd user unit that also keeps Chrome (CDP 9222) alive with the southwest profile.