Price Recommendation API Quickstart

Jun Zhou, Founder at AirROI
by Jun ZhouFounder at AirROI
Published: September 4, 2026
Updated: September 7, 2026

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.

Before you start

Calculation is one stage—not the whole publishing workflow

Keep the read-only recommendation steps separate from decisions and channel writes.

  1. 01 · Calculate

    Send property inputs, base price, settings, and current calendar. Read prices, explanations, and warnings.

  2. 02 · Review

    Check business limits, skipped rules, changed availability, and which dates are approved.

  3. 03 · Publish separately

    Send only approved updates through your channel integration. Reconcile per-date acknowledgments.

This is an integration pattern, not a set of additional AirROI API endpoints. Publishing requires your own authorized channel integration.
Get an API key from the developer portal. Store it in a server-side environment variable named 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.

Make both requests

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.

Know what to expect

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.

Limit the returned calendar

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.

InputResult
Both omitted or nullFull available calendar, one to two years from today
end_date onlyToday through that date, inclusive
start_date onlyThat date through the end of the available calendar
Same day in bothOne recommendation
end_date beyond available coverageAvailable dates; coverage.end_date shows where the response stops
start_date beyond available coverageHTTP 422 with START_DATE_BEYOND_AVAILABLE_HORIZON
start_date after end_dateHTTP 422 with INVALID_DATE_RANGE
Either date before todayHTTP 422 with START_DATE_IN_PAST or END_DATE_IN_PAST in validation details
Empty, malformed, impossible date, or wrong typeHTTP 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.

Add your first policy

To add a balanced last-minute preset, include this top-level object in the second request:

{
  "pricing_rules": {
    "last_minute": {
      "mode": "balanced"
    }
  }
}
Start with a single policy and inspect the 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.

Before production

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.

Continue with errors and warnings and the automation checklist. Exact constraints remain in the API reference.

Use the same workflow through MCP

Connect your AI client using the AirROI MCP setup guide. The same server and API key expose both pricing tools:
  • 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.

See the MCP pricing tools and workflow for example prompts and the full tool catalog.