Applied AI · Automation· Resy Control · personal tool

Reservation Automation

Personal tool, private
The Problem

Tables at the restaurants worth booking (Carbone, 4 Charles, Lilia) don’t trickle out. They open on a fixed release schedule and are gone in seconds, so winning one means refreshing a page at the exact right moment, every time, for weeks. No person should have to do that. A server can do it continuously, with a phone as the remote.

What I Did

I built a two-part system: an always-on bot that watches release windows and books automatically, and an iOS app to control it from my phone. The bot polls Resy’s booking API with a TLS fingerprint that matches a real browser rather than a Python client, the biggest detection signal these systems trip on. Early versions raced a reservation with 15 to 25 concurrent threads per venue; I rebuilt that into a single focused “hot-path” poller that only spins up in the ~75 seconds around a known release moment, cutting request volume by an order of magnitude while booking faster, with a per-target lock so it can never double-book.

On top sits a natural-language layer: a Discord bot where I can type “add Carbone Friday 7 to 9pm for 4” or ask for a recommendation in plain English. Free-text requests go through a small pipeline: Claude Haiku parses the query into a structured filter, Resy’s search API returns candidates with live availability, and Claude Sonnet ranks the shortlist and explains its reasoning. I later extended it to multiple users: friends get their own account, watchlist, and notification routing, sharing one poller underneath.

The iOS app, Resy Control, is a deliberately thin client: a dashboard, a watchlist editor, and settings. It talks to the droplet over a Caddy reverse proxy that tags every public request with a header the Flask app checks against an API key; the guard fails closed, so the phone can reach the bot over the open internet without opening it to anyone else. Automating reservations sits in a gray area of Resy’s terms of service, so this stays a personal tool rather than something public-facing.

Resy Control dashboard: bot status and poll cycle Resy Control watchlist editor Resy natural-language search results
Stack
curl_cffi (TLS impersonation)
Matches a real Chrome/Safari fingerprint at the handshake level so polling traffic doesn’t read as a bot.
Claude API (Haiku + Sonnet)
Parses natural-language commands and recommendation queries into structured filters; ranks candidates with plain-English reasoning.
Flask
Polling loop, REST control API, and Discord listener backend; runs as a systemd service on a DigitalOcean droplet.
discord.py
Natural-language and slash-command interface: add/remove watchlist entries, check status, get recommendations, book on demand.
Caddy
Reverse proxy terminating TLS in front of Flask; tags edge traffic so the auth guard fails closed for the public internet while exempting trusted on-box callers.
Expo / React Native
iOS control panel: dashboard, watchlist, and settings, with connection credentials stored in the device keychain via expo-secure-store.
← All work