Skip to content

evanpurkhiser/resyctl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 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.

Caution

Using resyctl puts your account at risk of violating the Resy Terms of Service! Use this at your own risk. It is not unheard of for accounts to be permanently terminated when using 3rd party booking tools!

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