Add your hotel and the comp set you price against
Every recipe that puts you against the market reads two things from your account: your hotel, and the hotels you compete with. The first one everybody does. The second is the one nobody gets told about, and it is why a rate report arrives looking suspiciously like your own price list. Ten minutes, once, and every other recipe starts answering properly.

What you'll build
A hotel registered on your account with its slug and its OTA profiles detected, up to ten competitors attached to it, and the free call that reads the set back — which is where the comparison recipes get the slugs they loop over.
How it works
- 01Why the comp set is not optional
- 02Add the hotel
- 03Read the profiles it found
- 04The slug is not the name
- 05Attach up to ten competitors
- 06Read the set back from the API
- 07What happens next
Step by step
By the end you will have a hotel on your account with its slug, its OTA profiles detected and its competitors attached — the setup every comparison endpoint in Veetal quietly assumes you already did.
What you need: an account with the Account API active. Nothing else.
What it costs: nothing. Creating the hotel, resolving it against Booking and attaching competitors are all free. The comp set does change what an import costs later, and that part is worth reading before you launch one.
Why the comp set is not optional
Veetal's comparison endpoints do not take a list of rivals as a parameter. They read the set configured on the hotel. So the size of your comp set decides the shape of the answer:
- Rates come back as
{ report: { [slug]: [rate, ...] } }— your hotel and every competitor in the same payload. With an empty set, that object has one key: yours. - Parity is a score against the set. With nothing to compare against, there is no score to compute.
- Reputation and reviews carry a
competitorsblock, which arrives empty when the set is empty. The reviews endpoint even defaultsinclude_competitorstotrue, so an empty set is the difference between a benchmark and a solo reading. - The live rate grid is one call per property in the set. No set, no grid.
This is also the part of Veetal that a plain scraping API does not have. The comp set is stored configuration, not a query parameter you rebuild on every call.
1. Add the hotel
On Accommodations, Add accommodations. The wizard opens on three routes:
- Search Booking accommodation — the usual one.
- I have accommodation Booking URL — for when the search is ambiguous and you already have the listing open.
- Import accommodations from .csv/.xls file — the bulk route, and the sane way to load a portfolio.
Search by name. Results carry the hotel photo and city, and they come tagged:
- It's yours — already one of your accommodations. Greyed out, which saves you the duplicate.
- Is competitor — already a competitor of one of your hotels.
- Is existing — the listing is already in Veetal's database because someone else tracks it. It gets reused rather than created again, which is why it resolves instantly.
If nothing matches, use fewer words: the search matches Booking approximately, not your exact string.
2. Read the profiles it found
Pick one and Continue. Veetal resolves the listing for real and shows you what it found — stars, guest score, review count, address — plus Profiles Found: the OTAs this hotel actually has a listing on.
That block is a forecast. An OTA with no profile has nothing to import, and the reputation feed will only return the ones with a green tick. Repeat search profiles runs the detection again if you think it missed one, and View Profile opens the matched listing so you can confirm it is the right property before it lands on your account.
Once added, the row's SETUP column keeps showing that profile map, one badge per OTA.
3. The slug is not the name
The slug Veetal assigns comes from the Booking URL, not from the display name. "Ohla Barcelona" became ohla.
Every endpoint takes the slug, so copy it from the row instead of guessing it from the hotel's name. Half the "the endpoint returns nothing" tickets are a slug someone typed from memory.
4. Attach up to ten competitors
Open the hotel from the list and add competitors from its detail, with the same finder you used for the hotel — which is why search results already know how to tell you a property Is competitor.
Two things decide whether this step is useful:
Who belongs in the set. A guest choosing your hotel is not choosing between every hotel in the city. They are choosing between the handful in your district, in your band, for their dates. A comp set of ten hotels that a guest genuinely compares beats a comp set of ten hotels that share your star rating and nothing else.
What each one costs. The cap is ten, and it is a cap for a reason: every competitor multiplies the cost of every import. A hotel with 5 competitors across 3 OTAs is 18 listings per run, not 3. The dashboard shows the credit estimate before you launch an import — read it there, not in the invoice.

5. Read the set back from the API
GET /v2/account/accommodation/{accommodation}/competitors
Free, like the rest of the Account API. It returns the competitors configured for that hotel, each with the identifier the data endpoints take — which is exactly what a rate grid loops over: one call to get the set, then one rate call per property.
GET /v2/account/accommodation does the same for your own hotels, and is where the slugs come from in the first place.
What happens next
The hotel and its set are configuration, not data: on their own they fetch nothing. From here the path forks — a Real Time endpoint answers about them immediately, one request at a time, and a Feed dataset needs an import to have run first.
Two more things worth knowing about the list: every row has activate, deactivate and delete, and the checkboxes give you the same three in bulk. A deactivated entity stops being imported without losing its history — which is the right move for a hotel you stopped managing, and much better than deleting it.
Questions
How many competitors can I add?
Ten per hotel. The cap is deliberate: each competitor multiplies the cost of every import, and a set of thirty hotels is not a comp set — it is the city.
Do competitors consume credits on their own?
No. Creating them and resolving them against Booking is free, like the whole Account API. What they change is the size of every later job: an import covers the hotel plus its set across every OTA with a profile, and a live rate grid is one call per property.
My rate report only contains my own hotel. What is wrong?
The comp set is empty. The rates payload is keyed by slug and includes every competitor configured on the hotel, so with no set it comes back with a single key — yours.
Can I build the comp set over the API?
Yes. The whole set has endpoints: `GET`, `POST` and `DELETE` on `/v2/account/accommodation/{accommodation_id}/competitors`. The POST takes a `booking_urls` array of Booking.com hotel URLs — up to ten, the same cap as the dashboard — and resolves each one for you. ```bash curl -X POST "https://api.veetal.app/v2/account/accommodation/YOUR_ACCOMMODATION_ID/competitors" \ -H "veetal-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "booking_urls": ["https://www.booking.com/hotel/es/YOUR_COMPETITOR.html"] }' ``` Two things to know. It wants the **internal id**, not the slug — the one `/account/accommodation` returns inside each entry, while the slug is the key. And it only takes Booking URLs: there is no search endpoint, so a name you have not resolved yet is a dashboard job. That is the honest split — the dashboard finder is better for putting a set together, the API is better for keeping it in sync with your own system.
The hotel I want is already in Veetal because another customer tracks it. Is that a problem?
No. The search marks it **Is existing** and reuses the listing instead of creating a duplicate. You get your own entity pointing at data that is already resolved; other customers see nothing of yours.
Should I delete a hotel I stopped managing?
Deactivate it. A deactivated entity stops being imported — so it stops costing credits — but keeps its history, which you will want the day someone asks what happened last season.
Build your own
Start free with 100 API credits. No credit card, no sales call.