Compare ADR across your whole portfolio
A portfolio table is easy to print and easy to misread. Twelve ADRs side by side look comparable; they only are when every hotel was priced on the same nights, on the same product, collected the same way. This recipe prints the table and, under it, every reason to distrust a line.

What you'll build
A command that prints one line per hotel — ADR over a window of nights, its distance from the portfolio median, how many nights it is built on and which products — followed by every reason two lines are not comparable, plus a CSV for the spreadsheet.
Set this up first
RequiredThe endpoints don't take free text — they take your identifiers. This recipe assumes the things below already exist on your account; while one of them is missing, the call answers with an error or with less than you expect. Each point links to the recipe that walks it.
- 01
Register the hotel in your dashboard
Veetal resolves the property against Booking.com and assigns it a slug — and that slug, not the hotel name, is what every accommodation endpoint takes.
Guide: Add your hotel and the comp set you price against → - 02
Run one import on the hotel
A Feed dataset only contains what an import has written. Activate this API on the hotel, launch the first run by hand and read the credit estimate before you press — the cost grows with the comp set and, on multi-OTA datasets, with the OTAs too.
The same thing over the API, if you would rather not click:
curl -X POST "https://api.veetal.app/v3/account/accommodation" \
-H "veetal-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ ... }' # see the account reference for the bodyTo see whether an import has already finished, list them:
curl "https://api.veetal.app/v3/account/imports" \
-H "veetal-api-key: YOUR_API_KEY"Feed reads are not billed per request. The credits go on the imports that collect the data, which is why the estimate appears before you launch and not after.
How it works
- 01
Put every hotel on the account
Add every property in Accommodations. A portfolio view missing three hotels is one nobody trusts.
- 02
Import them all the same way
Launch an Accommodation Rates import over the nights you want, with the same visitor type and the same device for every hotel, and put it on a schedule. Two hotels collected differently produce numbers that look identical and mean different things.
- 03
Read one month per hotel
Call /rate/v7/{year}/{month} once per hotel and month. It answers every night of that hotel's latest finished import; keep the hotel's own rates and drop the comp set. Build the window of nights in UTC, or it slides one night back east of UTC.
- 04
Price each night, then the window
Take the cheapest rate of each night with the product it came from, average those into the ADR, and measure every hotel against the portfolio median, not the mean.
- 05
Read the warnings before the ranking
A hotel priced on fewer nights, a hotel mixing products across nights, a hotel collected as Genius or on another device, or a second currency: each one makes its line less comparable, and the recipe lists them under the table.
The call
List the hotels first — the slug is only the key of that object. Then one call per hotel and month: every night of that hotel's latest import, in the same shape for the whole portfolio.
# your hotels, indexed by slug
curl "https://api.veetal.app/v3/account/accommodation" \
-H "veetal-api-key: YOUR_API_KEY"
# every night of one hotel's latest import, for a whole month
curl "https://api.veetal.app/v3/feed/accommodation/YOUR_ACCOMMODATION_SLUG/rate/v7/2026/10" \
-H "veetal-api-key: YOUR_API_KEY"Clone and run
RunnableThe whole recipe is one self-contained folder: Node 20, no build step, and a test suite that runs without a key.
git clone https://github.com/Veetal-Connect/recipes.git
cd recipes/portfolio-monitor
cp .env.example .env # your VEETAL_API_KEY
node --env-file=.env index.mjs YYYY-MM-DD YYYY-MM-DD # put the window: first night, last nightCheck your key first
One call, five seconds. If this answers, the recipe will run.
# your hotels, indexed by slug
curl "https://api.veetal.app/v3/account/accommodation" \
-H "veetal-api-key: YOUR_API_KEY"
# every night of one hotel's latest import, for a whole month
curl "https://api.veetal.app/v3/feed/accommodation/YOUR_ACCOMMODATION_SLUG/rate/v7/2026/10" \
-H "veetal-api-key: YOUR_API_KEY"Questions
Is this ADR the same as my PMS's ADR?
No, and do not present it as if it were. This is the rate published on Booking; your PMS knows what was actually sold, including direct and negotiated business. They answer different questions and the gap between them is itself informative.
Why the median and not the average?
Because one 2,000 EUR property would drag the reference every other hotel is judged by. The median stays put when one line is extreme, so each deviation says something about that hotel, not about the outlier.
Why does a hotel say it is priced on fewer nights?
Because it had no rate on some nights of the window, and those nights are not missing at random: the ones a hotel sells out first are its most expensive. An ADR built on what is left is systematically low, so the recipe tells you how many nights each line stands on.
What does "collected as [anonymous · mobile]" mean?
How that hotel's rates were collected: as an anonymous or a Genius shopper, on desktop or mobile. A Genius price is not a public price and a mobile price is not a desktop price, so when the portfolio mixes them the recipe groups the hotels by fingerprint. Fix the import configuration before trusting the ranking.
What if properties are in different currencies?
The recipe warns that the ADRs are not addable and does not convert them: a conversion you did not choose is worse than none. Set the same currency on every hotel, or convert outside with a rate you can state.
Why is one of my hotels missing from the table?
It had no rates in the window in its latest finished import. Each hotel is read from its own latest import, so a night only an older import covered does not count. Check the Imports tab and the schedule.
Build your own
Start free with 1,000 API credits. No credit card, no sales call.
What do you want to build with hotel rates?
Say it in one line and we hand you back the prompt, the recipe if one already exists, and the APIs it runs on — starting with hotel rates.