Clarion Inn Elmhurst · direct public per night vs cheapest OTA
2026-11-10Expedia 97 · 18.28 % under2026-11-16
Parity monitor
One /parity call per hotel per date; filter cheaper = channel for every undercut, rank by max_undercut_pct.
Parity docs →Brand-direct hotel pricing API
11 chains and 5 OTAs, read from each chain's own booking system at the moment you ask: every rate plan, the member rate, the night in points, and Booking.com, Expedia, Hotels.com, Trip.com and Agoda for the same property — one JSON response, priced per shop.
X-Credits-Charged on every response · errors are free · no key needed to read the docs
11 hotel chains, brand-direct
5 OTAs beside them
8 of 11 chains with award points
98.4 % mean 30-day uptime, 16 sources status
Status snapshot generated 2026-10-11T09:30:32.663ZSame room, four prices
A real night at a Choice hotel in Chicago, read from Choice's own booking system and from the five OTAs at the same moment.
what the chain's site quotes anyone · OTA scrapers: no · directrate: yes
the loyalty price, quoted to an anonymous visitor · OTA scrapers: no · directrate: yes
cents-per-point against the after-tax cash rate · OTA scrapers: no · directrate: yes
the reseller's public price for the same night · OTA scrapers: yes · directrate: yes
Clarion Inn Elmhurst - Oak Brook near I-88, I-290, I-294 · check-in 2026-11-10 · 1 night · after tax · shopped 2026-10-11 09:27Z · verdict ota_undercuts, max undercut 18.28 %
A hotel sells the same night at four prices. An OTA scraper sees the top and the bottom of the stack: the public rate the chain's site shows anyone, and the reseller's price. It never sees the two in the middle — the member rate the chain quotes a logged-out visitor, and the award night in points — because they do not exist on an OTA page.
directrate reads the chain's own booking system, so the whole stack comes back in one response: lowest.bar, lowest.member, lowest_points with cpp, and on /parity each OTA's public price beside them with the gap stated per channel. Every row says which tax basis it is in, so the comparison is apples to apples.
Six modes, one key
Real responses, trimmed. The billing line under each tab is the endpoint's own, as the OpenAPI description states it.
Request
curl -s https://api.directrate.dev/v1/shop \
-H "x-api-key: $DIRECTRATE_API_KEY" \
-H "content-type: application/json" \
-d '{"chain":"hyatt","hotel_code":"CHIZP","checkin":"2026-11-10","los":1,"occupancy":{"adults":2}}'Response · X-Credits-Charged: 1
{
"chain": "hyatt",
"hotel": {
"code": "CHIZP",
"name": "Hyatt Place Chicago/Downtown-The Loop",
"currency": "USD"
},
"checkin": "2026-11-10",
"los": 1,
"status": "available",
"rates": [
{
"room_name": "View 2 Queens (with sofa bed)",
"rate_name": "Standard Rate",
"rate_type": "bar",
"member_only": false,
"refundable": null,
"price_per_night": 666.06,
"price_per_night_after_tax": 666.06,
"price_total": 666.06,
"tax_included": true,
… 54 more lines
}Billing. Billed the chain's shop weight per live shop; cache hits 0.25×; errors free. shopped 2026-10-11 09:26Z · hyatt CHIZP
Request
curl -s https://api.directrate.dev/v1/award \
-H "x-api-key: $DIRECTRATE_API_KEY" \
-H "content-type: application/json" \
-d '{"chain":"marriott","hotel_code":"CHIRL","checkin":"2026-11-10","los":1,"occupancy":{"adults":2}}'Response · X-Credits-Charged: 1
{
"chain": "marriott",
"hotel": {
"code": "CHIRL",
"currency": "USD",
"name": "Residence Inn by Marriott Chicago Downtown/Loop",
"brand": "Residence Inn"
},
"checkin": "2026-11-10",
"los": 1,
"status": "available",
"award_rates": [
{
"room_name": "Superior",
"rate_name": "Redemption with Points Upgrade",
"award_type": "standard",
"points_per_night": 60000,
"points_total": 60000,
"cash_copay": null,
"taxes_fees": 3.78,
"currency": "USD"
… 49 more lines
}Billing. Billed like /shop (shop weight live, 0.25× cached). shopped 2026-10-11 09:28Z · marriott CHIRL
Request
curl -s https://api.directrate.dev/v1/parity \
-H "x-api-key: $DIRECTRATE_API_KEY" \
-H "content-type: application/json" \
-d '{"chain":"choice","hotel_code":"IL263","checkin":"2026-11-10","los":1,"occupancy":{"adults":2}}'Response · X-Credits-Charged: 5.25
{
"chain": "choice",
"hotel": {
"code": "IL263",
"currency": "USD",
"name": "Clarion Inn Elmhurst - Oak Brook near I-88, I-290, I-294",
"brand": "Clarion"
},
"checkin": "2026-11-10",
"los": 1,
"currency": "USD",
"direct": {
"status": "available",
"public": {
"per_night": 118.7,
"total": 118.7,
"currency": "USD",
"basis": "after_tax",
"rate_name": "SAPR2",
"refundable": false
},
… 114 more lines
}Billing. Billed as the shops it made (each chain's weight, cached 0.25×) plus 1 credit when ids were resolved live. shopped 2026-10-11 09:27Z · choice IL263
Request
curl -s https://api.directrate.dev/v1/calendar \
-H "x-api-key: $DIRECTRATE_API_KEY" \
-H "content-type: application/json" \
-d '{"chain":"choice","hotel_code":"IL263","start":"2026-11-10","days":7,"los":1,"occupancy":{"adults":2}}'Response · X-Credits-Charged: 0.7
{
"chain": "choice",
"hotel": {
"code": "IL263",
"currency": "USD",
"name": "Clarion Inn Elmhurst - Oak Brook near I-88, I-290, I-294",
"brand": "Clarion"
},
"start": "2026-11-10",
"days": 7,
"los": 1,
"currency": "USD",
"nights": [
{
"date": "2026-11-10",
"status": "available",
"min_los": null,
"lowest": {
"bar": 126.95,
"bar_after_tax": 139.65,
"member": 120.6
… 80 more lines
}Billing. Billed per night: 0.1 credit on native-calendar chains; the shop weight per live night elsewhere; cached nights 0.25×. shopped 2026-10-11 09:27Z · choice IL263
Request
curl -s https://api.directrate.dev/v1/compset \
-H "x-api-key: $DIRECTRATE_API_KEY" \
-H "content-type: application/json" \
-d '{"chain":"choice","hotel_codes":["IL263"],"checkin":"2026-11-10","los":1,"occupancy":{"adults":2}}'Response · X-Credits-Charged: 1
{
"chain": "choice",
"checkin": "2026-11-10",
"los": 1,
"hotels": [
{
"code": "IL263",
"name": "Clarion Inn Elmhurst - Oak Brook near I-88, I-290, I-294",
"status": "available",
"lowest": {
"bar": 107.91,
"member": 97.12,
"bar_after_tax": 118.7,
"member_after_tax": 106.83
},
"lowest_points": 20000,
"currency": "USD"
}
],
"shopped_at": "2026-10-11T09:27:53.075Z",
"source": "live",
… 2 more lines
}Billing. Billed per hotel returned at the chain's compset rate (hotels served from cache 0.25×; error/not_found free), minimum 1 credit per call. shopped 2026-10-11 09:27Z · choice IL263
Request
curl -s https://api.directrate.dev/v1/stay \
-H "x-api-key: $DIRECTRATE_API_KEY" \
-H "content-type: application/json" \
-d '{"chain":"choice","hotel_code":"IL263","checkin":"2026-11-10","los":3,"occupancy":{"adults":2}}'Response · X-Credits-Charged: 1.3
{
"chain": "choice",
"hotel": {
"code": "IL263",
"currency": "USD",
"name": "Clarion Inn Elmhurst - Oak Brook near I-88, I-290, I-294",
"brand": "Clarion"
},
"checkin": "2026-11-10",
"checkout": "2026-11-13",
"los": 3,
"currency": "USD",
"stay": {
"status": "available",
"lowest": {
"bar": 105.68,
"member": 95.11,
"bar_after_tax": 116.25,
"member_after_tax": 104.62
},
"lowest_points": 17333.33,
… 59 more lines
}Billing. Billed as the two calls would be: the shop weight (cached 0.25×) plus the calendar nights, under one usage line `stay`. shopped 2026-10-11 09:27Z · choice IL263
Coverage
Capability flags and credit weights come from the same table the gateway bills with, so this matrix cannot drift from the invoice.
| Source | Program | Public | Member | Points | Native calendar | Comp set batch | Credits / shop |
|---|---|---|---|---|---|---|---|
| Marriott | Marriott Bonvoy | ✓ | ✓ | ✓ | ✓ | ✓ | 1 |
| Hilton | Hilton Honors | ✓ | ✓ | ✓ | ✓ | – | 1 |
| Hyatt | World of Hyatt | ✓ | ✓ | ✓ | ✓2 | – | 1 |
| IHG | IHG One Rewards | ✓ | ✓ | ✓ | ✓ | – | 1 |
| Choice | Choice Privileges | ✓ | ✓ | ✓ | ✓ | ✓ | 1 |
| Radisson | Radisson Rewards | ✓ | ✓ | ✓ | ✓ | ✓ | 3 |
| I Prefer | I Prefer (Preferred Hotels) | ✓ | ✓ | ✓ | ✓ | – | 1 |
| Wyndham | Wyndham Rewards | ✓ | ✓ | –1 | ✓ | ✓ | 6 |
| Meliá | Meliá Rewards | ✓ | ✓ | –1 | ✓2 | ✓ | 1 |
| Best Western | Best Western Rewards | ✓ | ✓ | ✓ | ✓ | ✓ | 5 |
| Premier Inn | — | ✓ | n/a | n/a | ✓ | – | 1 |
| Booking.com OTA | Genius (reported apart) | ✓ | ✓ | – | – | – | 1 |
| Expedia OTA | Member Price (reported apart) | ✓ | ✓ | – | – | – | 1 |
| Hotels.com OTA | Member Price (reported apart) | ✓ | ✓ | – | – | – | 1 |
| Trip.com OTA | — | ✓ | – | – | – | – | 1 |
| Agoda OTA | Member deal (reported apart) | ✓ | ✓ | – | – | – | 1 |
1 Points are login-gated at the source on Meliá and Wyndham; the column comes back empty rather than estimated. Premier Inn is cash-only. 2 Hyatt's calendar carries availability and points, Meliá's availability only — /calendar shops the open nights on those two.
Credits per shop are the default weights; a /compset hotel row is 0.25 (0.5 on Radisson, Best Western, Wyndham) and a native-calendar night 0.1 (0.25 on Wyndham). Full weight table.
Six of these chains are available self-serve nowhere else: Hyatt, Choice, Best Western, Meliá, Premier Inn, I Prefer.
Build, buy, or directrate
| Build it yourself | Buy enterprise data | directrate | |
|---|---|---|---|
| Time to first call | weeks — one scraper per chain, then the OTAs | a contract, a sales cycle | ~5 minutes: sign in, create a key, curl |
| Cost to evaluate | engineering time | $$ before you see a response | $0 — 250 credits a month, no card |
| Maintenance | 11 chain surfaces + 5 OTAs that change without notice | the vendor's | none — the status page shows what broke and when |
| Member rates & points | if you reverse-engineer each app | rarely, and never cents-per-point | member rate on 10 chains, points on 8, cpp and certificates |
| Who maintains it | you, forever | a vendor on their roadmap | us, measured every 15 minutes |
What people build
Each mockup is drawn from the snapshot on this page, not from a design file.
Clarion Inn Elmhurst · direct public per night vs cheapest OTA
2026-11-10Expedia 97 · 18.28 % under2026-11-16
One /parity call per hotel per date; filter cheaper = channel for every undercut, rank by max_undercut_pct.
Parity docs →Hyatt CHIZP · points per night, 7 nights · lowest 12,000
2026-11-102 nights at 12,000 pts2026-11-16
Points per night across a window with cpp against the cash rate — the nights worth redeeming on, in gold.
Award docs →Marriott CHIRL · award calendar, 7 nights · 47,000–56,000 pts
darker = cheaper · one row per hotel in a comp set
Up to 25 hotels per call, one row per hotel, native batch where the chain has one; a heatmap by night from /calendar.
Comp set docs →Choice IL263 · 3 nights from 2026-11-10 · split bookable
stay as one$317.04
nights alone$373
cheaper: stay · saving -17.65 % on the public rate
A 3-night stay as one against each night alone, and whether a split booking is even allowed.
Stay docs →Billing honesty
Illustration · a Free month
182 / 250 credits
Illustrative mix; every line is priced by the rules on the right. 429 quota_exceeded at 250.
Eight of the eleven chains always cost 1 credit a shop — Marriott, Hilton, Hyatt, IHG, Choice, Meliá, Premier Inn, I Prefer — and so do the five OTAs. Radisson is 3, Best Western 5, Wyndham 6, and those four values are the only ones there are.
A result served from a recent cache bills 0.25× the live price; max_age: 0 forces a live shop at full price.
Errors, a hotel code the chain does not know (not_found), upstream timeouts and an OTA with no listing for the hotel cost nothing.
The quota is checked before a call is made, so a request that would exceed it is refused (429 quota_exceeded) rather than half-billed.
Rate limits are an abuse guard per key, not a sold feature: 429 rate_limited comes with Retry-After.
Every response states its own price in X-Credits-Charged — the number written to your usage.
Pricing
Free
$0 /month
Try every endpoint on every chain. No card.
GrowthMost picked
$99 /month
A product with users: a parity monitor, an award tool, an agent.
Scale
$349 /month
Daily comp sets across a portfolio, or a calendar store of your own.
See all plans — Starter $29, Enterprise from $1,000, annual = two months free. Paid tiers are switched by hand today: email us and we flip the plan.
Operational honesty
Each source is probed with a real shop on a schedule; the ratio below is what the probes got back over the window. Rates are read from each chain's own booking system; we are not affiliated with any chain or OTA.
| Source | Uptime (30 days) | Avg latency |
|---|---|---|
| Agoda | 100 % | 1,408 ms |
| Best Western | 90.31 % | 3,316 ms |
| Booking.com | 100 % | 1,539 ms |
| Choice | 100 % | 2,027 ms |
| Trip.com | 100 % | 1,844 ms |
| Expedia | 100 % | 1,390 ms |
| Hilton | 99.83 % | 1,281 ms |
| Hotels.com | 100 % | 1,372 ms |
| Hyatt | 97.35 % | 9,908 ms |
| IHG | 98.29 % | 2,676 ms |
| I Prefer | 100 % | 751 ms |
| Marriott | 97.60 % | 1,363 ms |
| Meliá | 99.83 % | 1,036 ms |
| Premier Inn | 99.06 % | 2,942 ms |
| Radisson | 97.69 % | 3,764 ms |
| Wyndham | 94.52 % | 4,365 ms |
generated 2026-10-11 09:30Z · build-time snapshot; refreshes from the API when the page can read it · uptime = the share of 15-minute probes the source answered coherently; our own probe errors are left out.
FAQ
No. There is no partnership with any chain or OTA. The data is read from each chain's and each OTA's own publicly reachable pricing surfaces — the same numbers their app and website quote an anonymous visitor. No account credentials are used and no bookings are placed.
Yes, where the chain quotes them to an anonymous visitor — which most do. They arrive as their own rows with member_only: true and under lowest.member, never folded into the public rate. An OTA's Genius or Member Price is reported the same way and never enters the parity gap.
Yes, on 8 of the 11 chains, with points_per_night, any cash_copay, cpp — cents per point — computed per night against the after-tax cash rate for the same stay, and the free-night certificates that would cover the night on Marriott, Hilton and IHG. Points are login-gated at the source on Meliá and Wyndham, and Premier Inn is cash-only; those columns come back empty rather than estimated.
Live at request time, or from a cache a few minutes old — every response says which, in source and cache_age_sec. There is no nightly crawl behind this: the numbers are fetched when you call, so a points price that moved an hour ago has already moved here. max_age: 0 forces a live shop.
GET /hotels?chain=…&q=<city or address> returns the chain's own property codes around a place, nearest first, for one credit (Best Western 5, Wyndham 6). The codes are the chain's internal identifiers (Marriott calls them MARSHA codes), so they are not guessable and not shared between chains. An OTA's code is its own hotel id, which a /parity call returns in channel id.
The chain does not recognise that property code. Those responses are never charged. sold_out, closed and restricted_los are real answers — the hotel exists, it just isn't selling that stay. In /parity, a channel with skipped set had no listing matched for the hotel (or answered with an error) and is never charged either.
Those return OTA inventory and OTA prices, and nothing else. This returns what the chain itself quotes — every rate plan, the loyalty member rate, the award night in points, cents-per-point and certificates — with the OTA price beside it when you ask for it, and the tax basis stated per row.
Rate parity is the hotel's promise — to its guests and in its OTA contracts — that its own site is never undercut. It breaks all the time: wholesale rates resold through an OTA, an OTA funding a discount from its own commission, a member price the hotel forgot to match. /parity finds those cases in one call per hotel per date.
Not legal advice, just the facts about where the data comes from: no account credentials, no logins, no bookings, nothing behind a paywall. The rates are what each chain and each OTA quotes an anonymous visitor on its own public booking surface. No chain or OTA trademark, logo or creative asset is used or resold — their names appear here because they are what the data is about. What you do with the data is yours to square with your own obligations.
Not yet. Chains and OTAs change their systems without notice and a source can degrade for hours. The status page shows the measured 30-day uptime and latency per source, and source and cache_age_sec on every response say what you got. A live single-hotel lookup typically takes 1–10 seconds; a 25-hotel comp set or a five-channel parity call is paced on purpose and can take tens of seconds.
Two ways to start
Start free
curl one of the quickstart requests and read X-Credits-Charged on the response.Email us
A paid plan, an Enterprise contract, a chain you need that is not listed, or a question before you commit. No demo calendar yet — a reply within a working day.
hello@directrate.dev