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.
Via Homebrew:
brew install evanpurkhiser/personal/resyctlVia Arch Linux AUR:
yay -S resyctlFrom crates.io:
cargo install resyctlFrom source:
cargo install --path .resyctl auth login # prompts for email and password
resyctl auth status# 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
# }- All command output is JSON.
resyctl bookenforces cancellation-fee guardrails by default.- Use
resyctl payment-methodsto inspect available payment method IDs. - Pass
--rawif the normalized fields are insufficient — it includes the full underlying Resy response under a top-levelrawkey.