Skip to content

Search then detail

Search results are intentionally thinner than detail rows — they don’t include full reviews, availability calendars, or full descriptions. This recipe shows the standard two-step flow for going from “find candidates” to “compare deeply”.

import httpx
search = httpx.post(
"https://api.stayingapi.com/v1/search",
headers={"Authorization": "Bearer sk_live_..."},
json={"location": "Lisbon, Portugal", "filters": {"minBeds": 2, "priceMax": 250}},
timeout=60,
).json()
candidates = search["data"]
print(f"Found {len(candidates)} candidates")

Step 2 — Detail lookup

import httpx
# Pick the top 5 by guest_satisfaction
top_5 = sorted(
candidates,
key=lambda s: s.get("rating_breakdown", {}).get("guest_satisfaction") or 0,
reverse=True,
)[:5]
details = []
for c in top_5:
r = httpx.get(
f"https://api.stayingapi.com/v1/stays/{c['id']}",
headers={"Authorization": "Bearer sk_live_..."},
timeout=30,
)
if r.status_code == 200:
details.append(r.json()["data"])
for d in details:
print(f"{d['title']}: {d['reviews_count']} reviews, {len(d['amenities'])} amenity groups")

Why the split

  • Cost: a SEARCH page is ~12 credits for 50 results; a DETAIL is 1 credit each. If you do detail-on-all, you’d pay 50 extra credits for stays you’ll probably discard anyway.
  • Latency: search is one upstream call. Detail-on-all is N parallel calls.
  • Repeat-lookup speed: subsequent detail calls for the same listing return in tens of milliseconds.

Batching detail calls

If you have ≤25 ids you want to compare at once, the no-code dashboard’s “multi-listing-comparison” template wraps the loop for you with a CSV download. Programmatically, just parallelise with asyncio.gather or Promise.all.

const ids = ["1135...", "2245...", "3355..."];
const details = await Promise.all(
ids.map((id) =>
fetch(`https://api.stayingapi.com/v1/stays/${id}`, {
headers: { Authorization: "Bearer sk_live_..." },
}).then((r) => r.json())
)
);

Next