Skip to content

Repository files navigation

StayAPI CLI — hotel, vacation-rental & restaurant data from your shell

Live prices, availability, and guest reviews from Booking.com, Airbnb, Google Hotels, TripAdvisor and 15+ more platforms — one npx command, clean JSON on stdout. Built for AI agents, scripts, and data pipelines.

License: MIT npm version Powered by StayAPI

stayapi wraps the StayAPI REST API — one command per endpoint, generated from the live OpenAPI spec. StayAPI handles proxies, bot-detection, and page rendering server-side, so you get structured JSON instead of HTML. No SDK to learn, no scraping to maintain: if you can run a shell command, you can pull live travel data. Sign up for 50 free requests for testing the API.

Quickstart (60 seconds)

# 1. Get an API key (50 free requests for testing the API): https://stayapi.com/users/sign_up
npx stayapi@latest auth login          # saves to ~/.stayapi/credentials.json (chmod 600)

# ...or skip the login entirely and just export it:
export STAYAPI_API_KEY="your-key"

# 2. Ask for data. JSON to stdout, nothing else.
npx stayapi@latest booking hotel-reviews --hotel-id 1302021 --per-page 3

Output (truncated):

{
  "success": true,
  "hotel_id": "1302021",
  "data": {
    "reviews_returned": 3,
    "reviews": [
      { "id": "5320000000", "score": 10, "reviewed_date": "2026-08-05 04:38:27", "...": "..." }
    ]
  }
}

Already have an MCP client wired up? The same data is available as MCP tools — see stayapi.com/docs/mcp; use this CLI when you're in a plain shell, a cron job, or an agent without MCP.

What you get

Every command prints the API response verbatim (pretty-printed, 2-space). Here's stayapi booking hotel-reviews:

Field-accurate example (identity values altered):

{
  "success": true,
  "hotel_id": "1302021",
  "data": {
    "reviews_returned": 1,
    "reviews": [
      {
        "id": "5320000000",
        "score": 10,
        "reviewed_date": "2026-08-05 04:38:27",
        "hotelier_name": "Baan Coconut",
        "is_incentivised": false,
        "guest": {
          "name": "Anna",
          "user_id": 610000000,
          "avatar": "https://lh3.googleusercontent.com/a-/…",
          "nr_reviews": 4,
          "country": "DE",
          "country_code": "de",
          "traveler_type": "Solo traveler",
          "anonymous": false
        },
        "stay_details": {
          "room_type": "Small Double Room",
          "nights": 5,
          "room_photo": "https://cf.bstatic.com/xdata/images/hotel/max500/…jpg?k=…&o="
        },
        "review": {
          "title": "Exceptional",
          "positive": "Quiet room, great breakfast, easy walk to the beach.",
          "negative": null,
          "language": "en"
        },
        "helpful_votes": 0,
        "has_photos": false,
        "photos": [],
        "partner_reply": null,
        "travel_purpose": "leisure"
      }
    ],
    "pagination": {
      "current_page": 1,
      "per_page": 1,
      "has_next_page": true,
      "has_previous_page": false
    }
  },
  "message": "Success",
  "retrieved_at": "2026-08-10T17:42:32Z"
}

Same deal for prices, rooms, photos, facilities, restaurant menus and availability — the shape is whatever the endpoint returns, unmodified.

Recipes

# Newest-first review backfill — paginate until reviewed_date passes your cutoff
stayapi booking hotel-reviews --hotel-id 1302021 --sort recent_desc --per-page 25 --page 1

# Live hotel prices for a city and date range
stayapi google-hotels search --location "Barcelona" --check-in 2026-09-12 --check-out 2026-09-15 --adults 2

# Airbnb listing straight from its URL — no ID lookup needed
stayapi airbnb listing-details-from-url --url "https://www.airbnb.com/rooms/20669368" --check-in 2026-09-12 --check-out 2026-09-15

# Restaurant availability for a party of four
stayapi opentable restaurants-availability --restaurant-id 1234 --date 2026-09-12 --time 19:00 --party-size 4

# How many credits are left (this call is free — it never bills)
stayapi quota

# Escape hatch: any REST path directly, handy when your installed CLI predates a new endpoint
stayapi api GET /v1/expedia/hotel/reviews --query property_id=12345 --query sort=recent_desc

Booking review sort options: most_relevant (default), recent_desc, recent_asc, score_desc, score_asc. Use recent_desc for anything date-bounded.

Full worked scripts live in examples/: review backfill, a city hotel report, and an ID-resolver tour.

For AI agents

Discovery first — don't guess command names. stayapi tools prints the whole catalog as JSON on stdout; pass a platform to narrow it:

stayapi tools                          # every command
stayapi tools booking                  # one platform
stayapi booking hotel-reviews --help   # flags, types, enums, which are required

Each entry describes one command and all of its flags (abridged below — the real payload also carries generated_at, source, and the platforms list):

{
  "cli": "stayapi",
  "version": "0.1.1",
  "count": 112,
  "commands": [
    {
      "command": "stayapi booking hotel-reviews",
      "platform": "booking",
      "action": "hotel-reviews",
      "method": "GET",
      "path": "/v1/booking/hotel/reviews",
      "summary": "Get reviews for a Booking.com hotel by hotel ID.",
      "billable": true,
      "params": [
        {
          "flag": "--hotel-id",
          "name": "hotel_id",
          "in": "query",
          "required": true,
          "type": "string",
          "items": null,
          "enum": null,
          "default": null,
          "description": "Booking.com hotel ID (numeric). Use /hotel/url-to-id to convert URLs."
        }
      ]
    }
  ]
}

Output contract, so you can branch on it without parsing prose:

Exit Meaning Where
0 Success — API response body, pretty-printed JSON stdout
1 API error — the RFC 7807 problem+json body, verbatim stdout
1 Transport failure (timeout, DNS, refused, unexpected redirect) — stdout stays empty; a single JSON error line explains it stderr
2 Usage error — missing subcommand, unknown command/flag, missing required flag, missing key; single-line JSON stderr

Nothing else is ever written to stdout: no banners, no spinners, no colors. Two documented enrichments, both only when the upstream forces it: on rate-limited responses, if the API sends a Retry-After header and the body has no retry_after field, the CLI injects "retry_after_seconds": <n>; and if an error body is not valid JSON (some CDN-masked 502s), the CLI wraps it in a problem-shaped object (title, status, detail = the raw body) so stdout is always parseable.

Install the Claude skill so an agent knows when and how to reach for this (the npm package ships it too, under node_modules/stayapi/skills/):

git clone https://github.com/stayapi/stayapi-agent.git
mkdir -p ~/.claude/skills
cp -r stayapi-agent/skills/stayapi-cli ~/.claude/skills/

Quota etiquette. Every successful data call bills 1 credit. stayapi quota is free and never billed — check it before a long backfill, and stop immediately if a call comes back with a quota-exhausted error instead of retrying. Prefer one call with --per-page 25 over five calls with --per-page 5.

Getting IDs

Most endpoints want a platform ID. Resolve one first, then fetch:

# Booking.com — from a hotel URL (drives a real browser; expect 5–40s)
stayapi booking hotel-url-to-id --url "https://www.booking.com/hotel/gb/the-savoy.html"

# Booking.com — by name; a HOTEL-type result's dest_id is the hotel ID
stayapi booking destinations-lookup --query "The Savoy London"

# Airbnb — from a listing URL (or skip it: the *-from-url commands take the URL directly)
stayapi airbnb listing-extract-id --url "https://www.airbnb.com/rooms/20669368"

# OpenTable — from a restaurant URL
stayapi opentable restaurant-url-to-id --url "https://www.opentable.com/r/gary-danko-san-francisco"

# Coordinates for geo-based searches
stayapi meta coordinates-lookup --term "Barcelona" --limit 1

Every resolver bills 1 credit, so cache the IDs you resolve.

Configuration

Setting How
API key --api-key <key>STAYAPI_API_KEY~/.stayapi/credentials.json (in that order)
Base URL --base-url <url> or STAYAPI_BASE_URL (default https://api.stayapi.com)
Timeout --timeout <seconds> (default 120 — some endpoints drive real browsers)
Retries one retry on 429/502/503/504 honoring Retry-After; disable with --no-retry

The key is never printed back — stayapi auth status masks it and tells you which source it came from. Node 18+ required.

Related

License

MIT. The data returned by the API belongs to the platforms and the authors who wrote it; use it responsibly and respect applicable laws and terms.

About

StayAPI CLI for AI agents & scripts — live hotel, vacation-rental & restaurant data (Booking.com, Airbnb, Google Hotels, TripAdvisor + more) as clean JSON. Powered by StayAPI (stayapi.com)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages