Use two POST requests: first estimate the property's base price, then pass that price and its returned currency into Calendar Prices. If you already have a base price, call Calendar Prices directly.
Keep the read-only recommendation steps separate from decisions and channel writes.
Send property inputs, base price, settings, and current calendar. Read prices, explanations, and warnings.
Check business limits, skipped rules, changed availability, and which dates are approved.
Send only approved updates through your channel integration. Reconcile per-date acknowledgments.
AIRROI_API_KEY. Both endpoints use the X-API-KEY header and JSON request bodies. Never place the key in a browser bundle or public repository.The example below uses Python 3's standard library. Set the environment variable using your local secret-management workflow, save the code as recommend_prices.py, and run python3 recommend_prices.py. It makes two API requests subject to your account's usage and billing terms.
import json
import os
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
API_URL = "https://api.airroi.com"
API_KEY = os.environ["AIRROI_API_KEY"] # server-side secret; never bundle in a browser
def post_json(path, payload):
request = Request(
API_URL + path,
data=json.dumps(payload).encode("utf-8"),
headers={
"X-API-KEY": API_KEY,
"Content-Type": "application/json",
"Accept": "application/json",
},
method="POST",
)
try:
with urlopen(request, timeout=35) as response:
result = json.load(response)
request_id = response.headers.get("X-Request-ID")
return result, request_id
except HTTPError as error:
request_id = error.headers.get("X-Request-ID")
body = error.read().decode("utf-8", errors="replace")
# Log only to protected server logs; error bodies may contain input details.
raise RuntimeError(
f"AirROI HTTP {error.code}; request_id={request_id}; body={body}"
) from error
except URLError as error:
raise RuntimeError("AirROI request failed before a response was received") from error
location = {"latitude": 25.7907, "longitude": -80.13}
base, base_request_id = post_json(
"/price-recommendation/base-price",
{
"location": location,
"property": {"bedrooms": 3, "baths": 2.5, "guests": 6},
"currency": "USD",
},
)
calendar, calendar_request_id = post_json(
"/price-recommendation/calendar-prices",
{
"location": location,
"currency": base["currency"],
"base_price": base["recommended_base_price"],
},
)
# Preview only: no rates are published by this code or these API calls.
print("Currency:", calendar["currency"])
print("Request ID:", calendar_request_id)
for warning in calendar["warnings"]:
print("Warning:", warning["code"], warning["message"])
for day in calendar["recommendations"][:3]:
print(day["date"], day["price"], day["explanation"])
This is a runnable preview, not a production scheduler. It has a timeout and reports HTTP failures, but deliberately does not publish rates or implement automatic retries.
Base Price returns recommended_base_price, currency, alternatives, and an explanation. Calendar Prices returns location, currency, warnings, and recommendations.
Each daily row has a date, a price, and explanation lines. With no custom stay rules, do not expect minimum-stay or check-in/out fields. The first date is today in the property's timezone unless you set start_date. Omit start_date and end_date or send null for the full calendar, one to two years of dates. Set either inclusive boundary to return fewer rows; the same day in both returns one.
The printed three rows are only a preview of the full array. Actual prices depend on the property and current model; the example is not expected to return a fixed set of numbers.
Add an optional top-level start_date and/or end_date to the Calendar Prices
request. Both use YYYY-MM-DD and include that date. For example,
"start_date": "2026-12-01", "end_date": "2026-12-31" returns just December 2026,
which is what a channel manager syncing one month at a time needs; use future
dates when running the example.
| Input | Result |
|---|---|
Both omitted or null | Full available calendar, one to two years from today |
end_date only | Today through that date, inclusive |
start_date only | That date through the end of the available calendar |
| Same day in both | One recommendation |
end_date beyond available coverage | Available dates; coverage.end_date shows where the response stops |
start_date beyond available coverage | HTTP 422 with START_DATE_BEYOND_AVAILABLE_HORIZON |
start_date after end_date | HTTP 422 with INVALID_DATE_RANGE |
| Either date before today | HTTP 422 with START_DATE_IN_PAST or END_DATE_IN_PAST in validation details |
| Empty, malformed, impossible date, or wrong type | HTTP 422 |
coverage contains calculation_date (today in the property's timezone),
start_date, end_date, recommendation_count, and
timezone. Use the actual returned dates when planning publication. The
calculation still uses the full available calendar from today: last-minute and
far-future lead times count from calculation_date, not from start_date, and
prices, evidence, warnings and per-request billing are unchanged. Warning counts
can include dates outside the selected window. Continue supplying surrounding
availability evidence, including nights before start_date, even when
requesting a short response.
To add a balanced last-minute preset, include this top-level object in the second request:
{
"pricing_rules": {
"last_minute": {
"mode": "balanced"
}
}
}
last_minute_rule contribution and any subsequent price limit. For calendar-dependent rules, first supply current availability evidence. Do not copy historical sample dates and expect them to describe your current calendar.Check warnings even on HTTP 200, preserve request IDs, use decimal-safe money handling, and store the full settings you send. Recommendations are stateless and are not published anywhere.
airroi_recommend_base_price accepts the Base Price request shown above.airroi_recommend_calendar_prices accepts the Calendar Prices request shown above.Ask your AI to pass recommended_base_price and the returned uppercase currency
from the first tool into the second, then summarize the dates you need and all
warnings. The MCP calendar tool returns the complete response inline, including
nightly recommendations, explanations, stay restrictions, coverage, and warnings.
It forwards the same optional, nullable start_date and end_date to the API;
omitted or null boundaries return the full one- to two-year calendar. Its calendar input supplies availability evidence,
not a requested date range. Each call uses the same paid credits as the
corresponding REST endpoint. No property settings are changed or rates published.
Your separate integration owns publishing and stay-rule enforcement.
Stay ahead of the curve
Join our newsletter for exclusive insights and updates. No spam ever.