Flight + hotel finder for one specific trip pattern: flying out of MSY on Tuesdays into JFK or LGA (nonstop, Delta preferred, cheapest refundable fare), and boutique/4-star hotels under $350/night in SoHo, Nolita, Lower East Side, Chelsea, or Greenwich Village.
Built for one person's use, not a general-purpose app.
Earlier drafts of this app tried an embeddable Travelpayouts widget (Aviasales/Hotellook branded search boxes). That's not what this app does now — it uses Travelpayouts' plain JSON APIs as a data source and renders everything in our own UI. Given the budget, a custom flight/hotel pricing engine from full scratch (own scraper, own inventory) still wasn't the right trade — but "our UI, their data" is.
- Flights tab —
flights.tscalls the Aviasales Data API (/v1/prices/calendar), a plain JSON endpoint returning the cheapest cached fare per day for a route. High confidence: single GET request, documented and tested against the real API shape. - Hotels tab —
hotels-live.tscalls the Hotellook engine API (engine.hotellook.com), a two-step MD5-signed search (start, then poll for results). This one is unverified — I built it against Travelpayouts' documented signature spec but couldn't load their full gated help article to triple-check it, and have no token to test against. Treat the first real run as the actual test; if/api/hotels/livereturns an error, paste it back and I'll debug against the real response.
Both fall back cleanly (mock flight data / curated-list-only) when their env vars aren't set — nothing crashes either way.
The hand-curated neighborhood/boutique hotel list (data/hotels.ts) stays
alongside the live hotel search, because Hotellook's citywide NYC results
don't carry "SoHo vs. Nolita vs. boutique aesthetic" — that curation still
isn't something any free API does for you. Each flight row also links out
to a plain Google Flights search (no API, just a pre-filled URL) as a
"verify the real price" check, since Google has better US-domestic fare
coverage than Aviasales.
- Flights tab: real data once
TRAVELPAYOUTS_TOKENis set (falls back to a mock table otherwise). No refundability field exists in this data source — that column shows "Check" and relies on the Google Flights link. - Hotels tab: live NYC search once
HOTELLOOK_TOKEN+HOTELLOOK_MARKERare set (shows a config/error message otherwise, never crashes), plus the curated neighborhood list always.
- Register at travelpayouts.com (free, no minimum traffic). The marketing site is aimed at travel bloggers monetizing content, which reads oddly for "add search to my app" — but the underlying APIs work the same regardless of how they're marketed.
- Find your API token in your Travelpayouts Profile → API token section (this is separate from the widgets/Projects flow — you don't need to create a Project or set up any widget for this).
- 👉 Add it here: https://www.val.town/x/unlikelyarchivist/nyc-flight-hotel-finder/environment-variables?key=TRAVELPAYOUTS_TOKEN
- For hotels, you also need a marker (your partner/affiliate ID, findable in the same account area — it's used for attribution, distinct from the API token): 👉 https://www.val.town/x/unlikelyarchivist/nyc-flight-hotel-finder/environment-variables?key=HOTELLOOK_TOKEN 👉 https://www.val.town/x/unlikelyarchivist/nyc-flight-hotel-finder/environment-variables?key=HOTELLOOK_MARKER
- Reload the app. If the Hotels tab shows an error instead of live prices,
send me the exact error text from the yellow box — that's the real
signal for what to fix in
hotels-live.ts.
Worth showing both rather than picking one:
- LGA is Delta's home domestic hub in NYC — it usually has more Delta departures/day and connects to more of the network, so it's often the cheaper, more frequent nonstop option for domestic city pairs like MSY.
- JFK is Delta's international/long-haul hub — still serves MSY nonstop, but with fewer daily frequencies; can occasionally undercut LGA on price depending on the week.
- Combining flight + hotel dates into one trip cost. Flights and hotels query independently right now (hotels defaults to a generic 30-days-out date range). A v2 could pass the Tuesday she picks in the flight table as the hotel search's check-in date.
- Round trip / return date. Her trip length varies trip to trip (not a
fixed pattern). Not built into the flight data yet —
/v1/prices/calendaras used here is one-way; a round-trip version would need a second call per candidate return date. - Refundability. Not available from the free flight data API. Stays a manual "Verify" click through to Google Flights.
- Matching live Hotellook results to the curated list. Right now the live section and the curated list are two separate blocks, not merged — matching them by name would be fragile without Hotellook's internal hotel IDs, so they're kept apart rather than faked into one list.
- Configurable origin/destination. Currently hardcoded to MSY and JFK/LGA. Fine for v1 (one person, one route).
- Alerts. Not built — the plan is to fold this into a combined morning-brief automation across this app and the client-appointment-tracker app once both exist, rather than building separate notification plumbing here.
index.ts ← Hono backend: serves frontend + /api/flights + /api/hotels + /api/hotels/live
flights.ts ← Aviasales Data API (real once TRAVELPAYOUTS_TOKEN set; mock otherwise)
hotels-live.ts ← Hotellook signed search (untested — see "Architecture" above)
data/hotels.ts ← Curated neighborhood hotel list
frontend/
root.tsx ← HTML shell (+ iOS home-screen meta tags)
index.tsx ← React entrypoint
components/
App.tsx ← Tab layout (Flights / Hotels)
FlightsPanel.tsx ← Flight table + Google Flights verify links
HotelsPanel.tsx ← Live hotel results + curated picks list
Template updates and upgrade paths for existing remixes: CHANGELOG.md