Resy Hunter
Monitor restaurant reservations across Resy, OpenTable, and Tock. Detect open tables and alert the user via Telegram.
When to Use
- - User asks to check if a restaurant has availability
- User wants to find open tables at a specific restaurant on a date
- User wants to monitor a restaurant for cancellations or new openings
- User wants to manage their restaurant watchlist (add, remove, list)
- User asks to set up background monitoring or alerts
Platforms Supported
| Platform | Script | Identifier | Auth Required | Notes |
|---|
| Resy | INLINECODE0 | INLINECODE1 (integer) | Yes — RESY_API_KEY + RESY_EMAIL + INLINECODE4 | Auto-login via API, token cached 12h |
| OpenTable |
opentable-check.js |
restaurant_id (integer) | Yes — manual login via
opentable-login.js | One-time visible browser login, session persisted |
| Tock |
tock-check.js |
slug (URL slug) | No | Playwright bypasses Cloudflare |
Parsing Natural Language Requests
Users speak casually. Extract these fields from every request:
| Field | How to parse | Default |
|---|
| Restaurant | Name mentioned, or "my list" / "my watchlist" → sweep all watchlist entries | — |
| Party size |
"for 2", "party of 4", "2 people", "two" | Ask if missing |
|
Date(s) | "March 9" →
2026-03-09. "this Saturday" → resolve to YYYY-MM-DD. "next 30 days" → generate array of dates. "this weekend" → upcoming Sat + Sun. "any Friday in April" → all Fridays in April. | Ask if missing |
|
Time window | "6-9pm" →
earliest: "18:00", latest: "21:00". "7:30p" →
earliest: "19:00", latest: "20:00" (±30min). "dinner" / "prime time" →
earliest: "18:00", latest: "21:00". "lunch" →
earliest: "11:30", latest: "14:00". "tonight" →
earliest: "18:00", latest: "22:00" | All times |
|
Fallback | "if nothing, check my list" → on zero results, sweep watchlist with same date/party/time constraints | None |
|
Action | "book me" / "find me a res" / "get me a table" → find availability and present booking links (skill is read-only, never books). "monitor" / "alert me" / "watch for" → set up cron. "add to my list" → watchlist add. | Check availability |
"Book" always means "find availability." This skill never books. Always present results with a direct booking link so the user can book themselves.
Example Requests → Execution Plans
"Book me a res at Tatiana by Kwame sometime in the next 30 days between 6-9pm for 2 people"
Parsed:
- - Restaurant: Tatiana by Kwame → run
resy-search-venue.sh "Tatiana by Kwame" to get venue_id - Dates: next 30 days → generate INLINECODE17
- Time: 6-9pm → INLINECODE18
- Party size: 2
Execute:
- 1.
bash scripts/resy-search-venue.sh "Tatiana by Kwame" → get venue_id - Loop through each date: INLINECODE20
- Filter returned slots to only those between 18:00-21:00
- Present all dates that have matching slots, with booking links
- If zero results across all 30 days, offer to add to watchlist for monitoring
"Find me a res from my list of restaurants for 3 people this Sat between 6-7:30p, alert me with which ones are available and I will pick one"
Parsed:
- - Restaurant: "from my list" → sweep entire watchlist
- Date: "this Sat" → resolve to upcoming Saturday YYYY-MM-DD
- Time: 6-7:30p → INLINECODE21
- Party size: 3 (override each entry's party_size for this check)
Execute:
- 1.
bash scripts/watchlist.sh list → get all entries - For each entry, run the platform check script with the resolved Saturday date and party_size=3
- Filter slots to 18:00-19:30 window
- Present results grouped by restaurant, with booking links
- Let the user pick — do not choose for them
"Book me at Carbone for 2 on March 9 5-9pm, if no availability find something else from my list"
Parsed:
- - Restaurant: Carbone → search venue_id
- Date: March 9 → INLINECODE23
- Time: 5-9pm → INLINECODE24
- Party size: 2
- Fallback: sweep watchlist
Execute:
- 1.
bash scripts/resy-search-venue.sh "Carbone" → get venueid - INLINECODE26
- Filter slots to 17:00-21:00
- If slots found → present with booking link, done
- If no slots →
bash scripts/watchlist.sh list, then check each entry for 2026-03-09 partysize=2 with 17:00-21:00 filter - Present any alternatives found from the watchlist
"Any openings at Don Angie tonight for 4?"
Parsed:
- - Restaurant: Don Angie → search venue_id
- Date: tonight → today's date
- Time: (tonight implies dinner) → INLINECODE28
- Party size: 4
Execute:
- 1.
bash scripts/resy-search-venue.sh "Don Angie" → get venue_id - INLINECODE30
- Filter to 18:00-22:00, present results
"Set up alerts for Atomix, party of 2, any Friday or Saturday in April between 7-9"
Parsed:
- - Restaurant: Atomix → search venue_id
- Dates: every Fri + Sat in April 2026 → INLINECODE31
- Time: 7-9 → INLINECODE32
- Party size: 2
- Action: set up monitoring
Execute:
- 1.
bash scripts/resy-search-venue.sh "Atomix" → get venue_id - INLINECODE34
- Set up cron if not already running:
openclaw cron add --name "resy-hunter-sweep" --every "15m" --session isolated --message "Run resy-hunter monitor..." --announce
- 4. Confirm to user: "Monitoring Atomix for Friday/Saturday openings in April, 7-9 PM, party of 2. I'll alert you on Telegram when something opens."
"What's available this weekend from my list?"
Parsed:
- - Restaurant: "from my list" → sweep watchlist
- Date: "this weekend" → upcoming Saturday + Sunday
- Time: not specified → all times
- Party size: not specified → use each entry's configured party_size
Execute:
- 1.
bash scripts/watchlist.sh list → get all entries - For each entry, check both Saturday and Sunday dates using the entry's own party_size
- Present all results grouped by restaurant and date
"Check everything on my list for tomorrow night"
Parsed:
- - Restaurant: "everything on my list" → sweep watchlist
- Date: tomorrow → resolve to YYYY-MM-DD
- Time: "night" → INLINECODE36
- Party size: use each entry's configured party_size
Execute: same as watchlist sweep pattern above
"Monitor Torrisi for cancellations, party of 4, March 15, prime time"
Parsed:
- - Restaurant: Torrisi → search venue_id
- Date: March 15 → INLINECODE37
- Time: "prime time" → INLINECODE38
- Party size: 4
- Action: "monitor for cancellations" → add to watchlist + set up cron
Execute:
- 1. Search venue_id, add to watchlist, set up cron
- Confirm monitoring is active
"Add Lilia to my watchlist, 2 people, next three Saturdays, dinner time"
Parsed:
- - Restaurant: Lilia → search venue_id
- Dates: next 3 Saturdays → resolve to specific YYYY-MM-DD values
- Time: "dinner time" → INLINECODE39
- Party size: 2
- Action: watchlist add only (no cron unless asked)
Execute:
- 1.
bash scripts/resy-search-venue.sh "Lilia" → get venue_id - INLINECODE41
"Is there anything at 4 Charles or Via Carota for 2 this Thursday?"
Parsed:
- - Restaurants: two separate — "4 Charles" and "Via Carota"
- Date: this Thursday → resolve
- Party size: 2
Execute:
- 1. Search venueids for both restaurants
- Check both for the resolved Thursday date with partysize=2
- Present results side by side
"Cancel monitoring for Carbone"
Parsed:
- - Action: remove from watchlist
Execute:
- 1.
bash scripts/watchlist.sh list → find Carbone's id - INLINECODE43
- If watchlist is now empty, suggest removing the cron job too
How to Run Checks
- 1. Determine the platform (ask the user if unclear)
- Get the restaurant identifier:
-
Resy: If the user doesn't know the
venue_id, run
scripts/resy-search-venue.sh "<name>" [lat] [long] to find it
-
OpenTable: The
restaurant_id is in the OpenTable URL (e.g.,
opentable.com/r/restaurant-name-city?rid=123456 → rid is
123456)
-
Tock: The slug is in the URL (e.g.,
exploretock.com/alinea → slug is
alinea)
- 3. Run the appropriate check script:
- Resy:
bash ~/.openclaw/skills/resy-hunter/scripts/resy-check.sh <venue_id> <date> <party_size>
- OpenTable:
node ~/.openclaw/skills/resy-hunter/scripts/opentable-check.js <restaurant_id> <date> <party_size>
- Tock:
node ~/.openclaw/skills/resy-hunter/scripts/tock-check.js <slug> <date> <party_size>
- 4. Parse the JSON output and present available slots in a clean table format:
Restaurant | Date | Time | Type | Platform
- 5. If no slots found, offer to add to the watchlist for background monitoring
Watchlist Management
The watchlist lives at ~/.openclaw/data/resy-hunter/watchlist.json (separate from the skill directory so reinstalls don't wipe user data).
- - List: INLINECODE55
- Add: INLINECODE56
- JSON must include:
name,
platform (resy/opentable/tock), platform identifier (
venue_id/
restaurant_id/
slug),
party_size,
dates array
- Optional:
preferred_times object with
earliest and
latest in HH:MM format
- - Remove: INLINECODE67
- Set Priority: INLINECODE68
Priority Levels
- - high — Telegram alerts fire immediately when new slots appear
- low — Slots are tracked (dedup works) but Telegram alerts only when the user explicitly asks for a sweep
Default priority is low when adding entries. Set it to high for restaurants the user actively wants alerts on. The JSON report from monitor.sh always includes all priorities.
Default Time Window
All entries default to a 6:00 PM – 10:00 PM time window. Slots outside this window are filtered out. Override per restaurant via preferred_times when adding:
Example add:
CODEBLOCK2
Background Monitoring
The monitor runs checks in parallel and staggers platforms by frequency:
- - Resy (curl): checked every sweep, up to 8 concurrent
- Tock (Playwright): checked once per hour, up to 2 concurrent
- OpenTable (Playwright): checked once per hour, up to 2 concurrent
To set up cron monitoring, run:
CODEBLOCK3
The 15-minute cron means Resy is checked every 15 minutes while Tock and OpenTable are automatically checked once per hour (the monitor tracks timestamps and skips platforms checked less than 60 minutes ago).
For high-frequency sniping on a specific date (e.g., when reservations drop):
CODEBLOCK4
To stop monitoring: INLINECODE73
Manual Monitor Sweep
To run a one-time sweep of the entire watchlist:
CODEBLOCK5
To check only a specific platform (bypasses the hourly interval timer):
CODEBLOCK6
Multiple platforms can be combined:
CODEBLOCK7
Interpret the output JSON:
- -
new_availability array: newly detected slots since last sweep - INLINECODE75 : number of restaurant+date combinations checked
- INLINECODE76 : how many had open slots
Sending Notifications Manually
CODEBLOCK8
This sends a Telegram message. The bot token is pulled from OpenClaw's Telegram channel config (channels.telegram.botToken). Falls back to TELEGRAM_BOT_TOKEN env var if config not found.
Booking Links
When reporting availability, always include a direct booking link:
- - Resy: INLINECODE79
- OpenTable: INLINECODE80
- Tock: INLINECODE81
Error Handling
- - If a Resy request returns HTTP 419, the script automatically clears the cached token and re-authenticates. No manual action needed.
- If Resy login fails (HTTP 401/403), check
RESY_EMAIL and RESY_PASSWORD. - If OpenTable returns
session_expired: true, run node ~/.openclaw/skills/resy-hunter/scripts/opentable-login.js to re-authenticate manually. The monitor will send a Telegram alert when this happens. - If Tock returns
blocked: true in output, Cloudflare blocked even the Playwright browser. Return the URL for the user to check manually. This is rare — retrying usually works.
Credential Setup
Resy (auto-login via API):
- 1.
RESY_API_KEY — one-time extraction from browser DevTools (static, never expires):
- Log into resy.com → DevTools → Network tab
- Find any request to
api.resy.com
-
Authorization header → value after
ResyAPI api_key= is the API key
- 2.
RESY_EMAIL — your Resy account email - INLINECODE92 — your Resy account password
- Auth tokens are fetched and cached automatically (12-hour TTL). No manual token extraction needed.
OpenTable (manual login via Playwright):
- 1. Run once: INLINECODE93
- A visible browser opens to OpenTable's login page
- Log in with your email + OTP code manually
- The script detects login and saves session cookies to INLINECODE94
- Future runs use the saved session headlessly. If it expires, the monitor sends a Telegram alert telling you to re-run
opentable-login.js.
Tock (no credentials):
No credentials needed. Playwright uses a real browser that passes Cloudflare Turnstile challenges automatically.
First-Time Setup
After installing the skill, run once to install dependencies:
CODEBLOCK9
Important
- - This skill is read-only. Never attempt to book a reservation. The user books manually.
- Respect rate limits. Do not run checks more frequently than every 2 minutes.
- Dates in the past should be skipped automatically by the monitor script.
Resy Hunter
监控Resy、OpenTable和Tock上的餐厅预订情况。检测空位并通过Telegram提醒用户。
使用场景
- - 用户询问某餐厅是否有空位
- 用户想在特定日期查找某餐厅的空位
- 用户想监控某餐厅的取消或新开放预订
- 用户想管理其餐厅监控列表(添加、删除、查看)
- 用户要求设置后台监控或提醒
支持的平台
| 平台 | 脚本 | 标识符 | 需要认证 | 备注 |
|---|
| Resy | resy-check.sh | venueid(整数) | 是 — RESYAPIKEY + RESYEMAIL + RESYPASSWORD | 通过API自动登录,令牌缓存12小时 |
| OpenTable |
opentable-check.js | restaurantid(整数) | 是 — 通过opentable-login.js手动登录 | 一次性可见浏览器登录,会话持久化 |
| Tock | tock-check.js | slug(URL片段) | 否 | Playwright绕过Cloudflare |
解析自然语言请求
用户会随意表达。从每个请求中提取以下字段:
| 字段 | 解析方式 | 默认值 |
|---|
| 餐厅 | 提及的名称,或我的列表/我的监控列表 → 扫描所有监控列表条目 | — |
| 人数 |
2位、4人、2个人、两位 | 如果缺失则询问 |
|
日期 | 3月9日 → 2026-03-09。这周六 → 解析为YYYY-MM-DD。未来30天 → 生成日期数组。这周末 → 即将到来的周六+周日。四月的任何周五 → 四月所有周五。 | 如果缺失则询问 |
|
时间窗口 | 晚上6-9点 → earliest: 18:00, latest: 21:00。7:30p → earliest: 19:00, latest: 20:00(±30分钟)。晚餐/黄金时段 → earliest: 18:00, latest: 21:00。午餐 → earliest: 11:30, latest: 14:00。今晚 → earliest: 18:00, latest: 22:00 | 所有时间 |
|
后备方案 | 如果没有,查看我的列表 → 零结果时,使用相同日期/人数/时间约束扫描监控列表 | 无 |
|
操作 | 帮我订/帮我找位/给我找个桌子 → 查找空位并提供预订链接(技能为只读,从不实际预订)。监控/提醒我/关注 → 设置定时任务。添加到我的列表 → 添加到监控列表。 | 检查空位 |
预订始终表示查找空位。 此技能从不实际预订。始终提供直接预订链接的结果,让用户自行预订。
示例请求 → 执行计划
帮我订Tatiana by Kwame未来30天内的位子,晚上6-9点,2位
解析结果:
- - 餐厅:Tatiana by Kwame → 运行resy-search-venue.sh Tatiana by Kwame获取venue_id
- 日期:未来30天 → 生成[2026-03-06, 2026-03-07, ..., 2026-04-04]
- 时间:晚上6-9点 → earliest: 18:00, latest: 21:00
- 人数:2位
执行:
- 1. bash scripts/resy-search-venue.sh Tatiana by Kwame → 获取venueid
- 遍历每个日期:bash scripts/resy-check.sh id> 2
- 筛选返回的时间段,仅保留18:00-21:00之间的
- 展示所有有匹配时间段的日期,附带预订链接
- 如果30天内均无结果,提供添加到监控列表的选项
从我的餐厅列表中找位子,3位,这周六晚上6-7:30,提醒我有哪些可选的,我来选一个
解析结果:
- - 餐厅:从我的列表 → 扫描整个监控列表
- 日期:这周六 → 解析为即将到来的周六YYYY-MM-DD
- 时间:晚上6-7:30 → earliest: 18:00, latest: 19:30
- 人数:3位(本次检查覆盖每个条目的party_size)
执行:
- 1. bash scripts/watchlist.sh list → 获取所有条目
- 对每个条目,使用解析出的周六日期和party_size=3运行平台检查脚本
- 筛选时间段至18:00-19:30
- 按餐厅分组展示结果,附带预订链接
- 让用户选择 — 不要替他们做决定
帮我订Carbone,2位,3月9日下午5-9点,如果没有空位就从我的列表里找别的
解析结果:
- - 餐厅:Carbone → 搜索venue_id
- 日期:3月9日 → 2026-03-09
- 时间:下午5-9点 → earliest: 17:00, latest: 21:00
- 人数:2位
- 后备方案:扫描监控列表
执行:
- 1. bash scripts/resy-search-venue.sh Carbone → 获取venueid
- bash scripts/resy-check.sh id> 2026-03-09 2
- 筛选时间段至17:00-21:00
- 如果找到时间段 → 展示预订链接,完成
- 如果没有时间段 → bash scripts/watchlist.sh list,然后检查每个条目在2026-03-09、party_size=2、17:00-21:00筛选条件下的情况
- 展示从监控列表中找到的任何替代选项
Don Angie今晚有4位的空位吗?
解析结果:
- - 餐厅:Don Angie → 搜索venue_id
- 日期:今晚 → 今天的日期
- 时间:(今晚暗示晚餐)→ earliest: 18:00, latest: 22:00
- 人数:4位
执行:
- 1. bash scripts/resy-search-venue.sh Don Angie → 获取venueid
- bash scripts/resy-check.sh id> 4
- 筛选至18:00-22:00,展示结果
设置Atomix的提醒,2位,四月任何周五或周六晚上7-9点
解析结果:
- - 餐厅:Atomix → 搜索venue_id
- 日期:2026年4月每个周五+周六 → [2026-04-03, 2026-04-04, 2026-04-10, 2026-04-11, ...]
- 时间:晚上7-9点 → earliest: 19:00, latest: 21:00
- 人数:2位
- 操作:设置监控
执行:
- 1. bash scripts/resy-search-venue.sh Atomix → 获取venueid
- bash scripts/watchlist.sh add {name:Atomix,platform:resy,venueid:,partysize:2,dates:[2026-04-03,2026-04-04,...],preferredtimes:{earliest:19:00,latest:21:00}}
- 如果尚未运行,设置定时任务:
bash
openclaw cron add --name resy-hunter-sweep --every 15m --session isolated --message Run resy-hunter monitor... --announce
- 4. 向用户确认:正在监控Atomix四月的周五/周六空位,晚上7-9点,2位。有空位时会通过Telegram提醒您。
这周末我的列表里有什么可选的?
解析结果:
- - 餐厅:从我的列表 → 扫描监控列表
- 日期:这周末 → 即将到来的周六+周日
- 时间:未指定 → 所有时间
- 人数:未指定 → 使用每个条目配置的party_size
执行:
- 1. bash scripts/watchlist.sh list → 获取所有条目
- 对每个条目,使用条目自身的party_size检查周六和周日两个日期
- 按餐厅和日期分组展示所有结果
检查我列表里所有餐厅明晚的情况
解析结果:
- - 餐厅:我列表里的所有餐厅 → 扫描监控列表
- 日期:明天 → 解析为YYYY-MM-DD
- 时间:晚上 → earliest: 18