Skip to content

evanpurkhiser/resyctl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

resyctl

Build Status

A Rust command-line client for Resy focused on automation-friendly, JSON-only output. It is designed for agents and scripts to drive booking workflows and other reservation automations.

Note

See my resy-booking skill for an example of how to drive resyctl from an agent.

Install

Via Homebrew:

brew install evanpurkhiser/personal/resyctl

Via Arch Linux AUR:

yay -S resyctl

From crates.io:

cargo install resyctl

From source:

cargo install --path .

Configure auth

resyctl auth login   # prompts for email and password
resyctl auth status

Example Usage

# 1) Search for a restaurant.
resyctl search "ishq" --limit 2 \
  | jq -r '.venues[:2][] | "\(.id): \(.name) [\(.locality // "?")]"'

# 84214: Ishq [New York]
# 66703: Ishi Omakase & Premium Sake [New York]

# Use the first result for the rest of the flow.
VENUE_ID=84214

# 2) Look up venue details (address, phone, website, Resy/Maps URLs, about).
resyctl venue "$VENUE_ID" \
  | jq '.venue | {name, neighborhood, address, phone, website, resy_url, google_maps_url}'

# {
#   "name": "Ishq",
#   "neighborhood": "Chelsea",
#   "address": "240 5th Ave, New York, NY 10001",
#   "phone": "+12125551234",
#   "website": "https://ishq.com/",
#   "resy_url": "https://resy.com/cities/new-york-ny/venues/ishq",
#   "google_maps_url": "https://www.google.com/maps/search/?api=1&query=Ishq+240+5th+Ave%2C+New+York%2C+NY+10001"
# }

# 3) Check availability for party size 2 on a specific date.
resyctl availability "$VENUE_ID" --date 2026-05-23 --party-size 2 \
  | jq -r '.slots[:4][] | "\(.slot_id[0:12])[…] | \(.start) | \(.type // "?")"'

# eyJjb25maWdfa[…] | 2026-05-23 12:15:00 | Bar Seat
# eyJjb25maWdfa[…] | 2026-05-23 12:15:00 | Dining Room
# eyJjb25maWdfa[…] | 2026-05-23 12:30:00 | Bar Seat
# eyJjb25maWdfa[…] | 2026-05-23 12:30:00 | Dining Room

# Save a slot id to quote/book.
SLOT_ID=$(resyctl availability "$VENUE_ID" --date 2026-05-23 --party-size 2 \
  | jq -r '.slots[] | select(.start=="2026-05-23 13:30:00" and .type=="Dining Room") | .slot_id' \
  | head -n1)
echo "${SLOT_ID:0:12}[…]"

# eyJjb25maWdfa[…]

# 4) Quote details for the slot (cancellation fee/cutoff/payment summary).
resyctl quote "$SLOT_ID" \
  | jq '{
      cancellation_fee_amount: .quote.cancellation_fee_amount,
      cancellation_fee_cutoff: .quote.cancellation_fee_cutoff,
      payment_type: .quote.payment_type
    }'

# {
#   "cancellation_fee_amount": 25,
#   "cancellation_fee_cutoff": "2026-05-22T17:30:00Z",
#   "payment_type": "free"
# }

# 5) Book the slot.
# If this slot has a cancellation fee, pass --allow-cancellation-fee.
# Use --max-cancellation-fee to cap the fee amount.
# "cancellation fee cutoff" is the timestamp after which canceling can incur a fee.
# Before the cutoff: cancel is free. After: the fee may be charged.
# Use --max-cutoff-hours to require at least N hours remaining until the cutoff.
# Example: --max-cutoff-hours 12 means "do not book if cutoff is within 12 hours".
resyctl book "$SLOT_ID" --allow-cancellation-fee --yes \
  | jq -r '"reservation=\(.reservation_id) token=\(.resy_token[0:12])[…] cancellation_fee_amount=\(.quote.cancellation_fee_amount) cancellation_fee_cutoff=\(.quote.cancellation_fee_cutoff)"'

# reservation=867457046 token=Ys7435rTmPAu[…] cancellation_fee_amount=25 cancellation_fee_cutoff=2026-05-22T17:30:00Z

# 6) List upcoming reservations.
resyctl reservations --upcoming \
  | jq -r '.reservations
    | sort_by(.day, .time_slot)
    | .[:2]
    | .[]
    | "\(.reservation_id) | \(.day) \(.time_slot) | \(.venue.name // "?") | \(.resy_token[0:12])[…]"'

# 867250480 | 2026-04-29 18:00:00 | MOKYO | 4hRnr95|mdVS[…]
# 867248247 | 2026-05-01 18:30:00 | Antidote | A1xdLzgBrOOT[…]

# 7) Cancel the older upcoming reservation.
CANCEL_TOKEN=$(resyctl reservations --upcoming \
  | jq -r '.reservations | sort_by(.day, .time_slot) | .[0].resy_token')
resyctl cancel "$CANCEL_TOKEN" --yes \
  | jq '{canceled, refund: .result.payment.transaction.refund}'

# {
#   "canceled": true,
#   "refund": 1
# }

Notes

  • All command output is JSON.
  • resyctl book enforces cancellation-fee guardrails by default.
  • Use resyctl payment-methods to inspect available payment method IDs.
  • Pass --raw if the normalized fields are insufficient — it includes the full underlying Resy response under a top-level raw key.

About

A Resy CLI focused on automation and agent use

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages