restaurant-booking
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRestaurant Booking
餐厅预订
Setup
设置
Read your credentials from ~/.gooseworks/credentials.json:
bash
export GOOSEWORKS_API_KEY=$(python3 -c "import json;print(json.load(open('$HOME/.gooseworks/credentials.json'))['api_key'])")
export GOOSEWORKS_API_BASE=$(python3 -c "import json;print(json.load(open('$HOME/.gooseworks/credentials.json')).get('api_base','https://api.gooseworks.ai'))")If ~/.gooseworks/credentials.json does not exist, tell the user to run:
npx gooseworks loginAll endpoints use Bearer auth:
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"Book reservations using Notte browser automation via Orthogonal.
从~/.gooseworks/credentials.json读取您的凭证:
bash
export GOOSEWORKS_API_KEY=$(python3 -c "import json;print(json.load(open('$HOME/.gooseworks/credentials.json'))['api_key'])")
export GOOSEWORKS_API_BASE=$(python3 -c "import json;print(json.load(open('$HOME/.gooseworks/credentials.json')).get('api_base','https://api.gooseworks.ai'))")如果~/.gooseworks/credentials.json不存在,请告知用户运行:
npx gooseworks login所有端点均使用Bearer认证:
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"通过Orthogonal的Notte浏览器自动化工具预订座位。
Requirements
要求
- Orthogonal CLI () or API key
npm install -g @orth/cli - Guest info: name, email, phone
- Orthogonal CLI()或API密钥
npm install -g @orth/cli - 宾客信息:姓名、邮箱、电话
Quick Flow
快速流程
- Start Notte session
- Navigate to booking site (OpenTable preferred)
- Select date/time/party size
- Fill contact form
- Submit and confirm
- 启动Notte会话
- 导航至预订网站(优先选择OpenTable)
- 选择日期/时间/用餐人数
- 填写联系表单
- 提交并确认
CLI Method (Recommended)
CLI方法(推荐)
1. Start a Notte Session
1. 启动Notte会话
bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/start"}'
--body '{"browser_type":"chromium","headless":true,"solve_captchas":true,"idle_timeout_minutes":10}'Save the from the response.
session_idbash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/start"}'
--body '{"browser_type":"chromium","headless":true,"solve_captchas":true,"idle_timeout_minutes":10}'保存响应中的。
session_id2. Navigate to OpenTable
2. 导航至OpenTable
bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"goto","url":"https://www.opentable.com/r/{restaurant}?datetime=2026-02-17T19:00&covers=2"}'bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"goto","url":"https://www.opentable.com/r/{restaurant}?datetime=2026-02-17T19:00&covers=2"}'3. Click Time Slot
3. 点击时间段
bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"click","selector":"button:has-text(\"7:00 PM\")"}'bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"click","selector":"button:has-text(\"7:00 PM\")"}'4. Select Seating (if prompted)
4. 选择座位(如有提示)
bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"click","selector":"button:has-text(\"Select\")"}'bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"click","selector":"button:has-text(\"Select\")"}'5. Fill the Form
5. 填写表单
bash
undefinedbash
undefinedFirst name
名字
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#firstName","value":"John"}'
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#firstName","value":"John"}'
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#firstName","value":"John"}'
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#firstName","value":"John"}'
Last name
姓氏
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#lastName","value":"Doe"}'
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#lastName","value":"Doe"}'
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#lastName","value":"Doe"}'
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#lastName","value":"Doe"}'
邮箱
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#email","value":"john@example.com"}'
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#email","value":"john@example.com"}'
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#email","value":"john@example.com"}'
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#email","value":"john@example.com"}'
Phone
电话
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#phoneNumber","value":"4155551234"}'
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#phoneNumber","value":"4155551234"}'
undefinedcurl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#phoneNumber","value":"4155551234"}'
-H "Authorization: Bearer $GOOSEWORKS_API_KEY"
-H "Content-Type: application/json"
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}' --body '{"type":"fill","selector":"input#phoneNumber","value":"4155551234"}'
undefined6. Accept Terms
6. 接受条款
bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"click","selector":"text=I agree to the restaurant"}'bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"click","selector":"text=I agree to the restaurant"}'7. Submit Reservation
7. 提交预订
bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"click","selector":"button:has-text(\"Complete reservation\")"}'bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/execute"}'
--body '{"type":"click","selector":"button:has-text(\"Complete reservation\")"}'8. Verify Confirmation
8. 验证确认信息
bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/scrape"}'
--body '{"only_main_content":true}'Look for "confirmed" in the response.
bash
curl -s -X POST $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run \
-H "Authorization: Bearer $GOOSEWORKS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api":"notte","path":"/sessions/{session_id}/page/scrape"}'
--body '{"only_main_content":true}'在响应中查找“confirmed”字样。
API Method (curl)
API方法(curl)
bash
undefinedbash
undefinedStart session
启动会话
curl -X POST "https://api.orth.sh/v1/run" \
-H "Content-Type: application/json"
-d '{ "api": "notte", "path": "/sessions/start", "body": { "browser_type": "chromium", "headless": true, "solve_captchas": true, "idle_timeout_minutes": 10 } }'
-d '{ "api": "notte", "path": "/sessions/start", "body": { "browser_type": "chromium", "headless": true, "solve_captchas": true, "idle_timeout_minutes": 10 } }'
curl -X POST "https://api.orth.sh/v1/run" \
-H "Content-Type: application/json"
-d '{ "api": "notte", "path": "/sessions/start", "body": { "browser_type": "chromium", "headless": true, "solve_captchas": true, "idle_timeout_minutes": 10 } }'
-d '{ "api": "notte", "path": "/sessions/start", "body": { "browser_type": "chromium", "headless": true, "solve_captchas": true, "idle_timeout_minutes": 10 } }'
Execute actions (same pattern)
执行操作(相同模式)
curl -X POST "https://api.orth.sh/v1/run" \
-H "Content-Type: application/json"
-d '{ "api": "notte", "path": "/sessions/{session_id}/page/execute", "body": {"type":"goto","url":"https://www.opentable.com/..."} }'
-d '{ "api": "notte", "path": "/sessions/{session_id}/page/execute", "body": {"type":"goto","url":"https://www.opentable.com/..."} }'
undefinedcurl -X POST "https://api.orth.sh/v1/run" \
-H "Content-Type: application/json"
-d '{ "api": "notte", "path": "/sessions/{session_id}/page/execute", "body": {"type":"goto","url":"https://www.opentable.com/..."} }'
-d '{ "api": "notte", "path": "/sessions/{session_id}/page/execute", "body": {"type":"goto","url":"https://www.opentable.com/..."} }'
undefinedKey Selectors (OpenTable)
关键选择器(OpenTable)
| Field | Selector |
|---|---|
| First name | |
| Last name | |
| |
| Phone | |
| Terms checkbox | |
| Submit | |
| Time slots | |
| Seating select | |
| 字段 | 选择器 |
|---|---|
| 名字 | |
| 姓氏 | |
| 邮箱 | |
| 电话 | |
| 条款复选框 | |
| 提交 | |
| 时间段 | |
| 座位选择 | |
Finding Restaurant IDs
查找餐厅ID
Search OpenTable and extract from URL:
- → Foreign Cinema
restref=1906 - Restaurant slug in URL path
Example URL format:
https://www.opentable.com/r/{restaurant-slug}?restref={id}&datetime={YYYY-MM-DDTHH:MM}&covers={n}搜索OpenTable并从URL中提取:
- → Foreign Cinema
restref=1906 - URL路径中的餐厅别名
示例URL格式:
https://www.opentable.com/r/{restaurant-slug}?restref={id}&datetime={YYYY-MM-DDTHH:MM}&covers={n}Tips
提示
- OpenTable holds table for 5 minutes - move fast
- Use action with
fillparam (notvaluewithtype)text - Click terms via label text, not checkbox directly
- No credit card needed - reservations are free
- Confirmation email sent automatically
- OpenTable会为您保留座位5分钟,请尽快操作
- 使用带参数的
value操作(而非带fill的text操作)type - 通过标签文本点击条款,而非直接点击复选框
- 无需信用卡预订,免费预约
- 确认邮件会自动发送
Resy Alternative
Resy替代方案
If restaurant uses Resy:
https://resy.com/cities/{city}/venues/{restaurant}?date={YYYY-MM-DD}&seats={n}Similar flow but different selectors. Scrape page first to identify form fields.
如果餐厅使用Resy:
https://resy.com/cities/{city}/venues/{restaurant}?date={YYYY-MM-DD}&seats={n}流程类似但选择器不同。先抓取页面以识别表单字段。
After Booking
预订后操作
- Create calendar event with
gog calendar create - Add attendees and location
- Include confirmation number in description
- 使用创建日历事件
gog calendar create - 添加参会者和地点
- 在描述中包含确认号码