> For the complete documentation index, see [llms.txt](https://docs.okup.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.okup.ai/okupai-api/pricing.md).

# Pricing

Retrieve nightly prices, availability, and stay rules for your units.

## 💰 Pricing

Retrieve the **rate calendar** for your units: nightly price, availability, and minimum/maximum stay rules per date. Results are scoped to your permitted units and ordered by unit, then date.

* **Method:** GET
* **Endpoint:** `https://api.okup.ai/data/pricing`
* **Auth:** header `X-API-Key: YOUR_API_KEY` (required)

### 🔍 Query parameters

| Parameter            | Type              | Description                                                                                      |
| -------------------- | ----------------- | ------------------------------------------------------------------------------------------------ |
| `from`               | string, optional  | Start date (`YYYY-MM-DD`). **Default: today**                                                    |
| `to`                 | string, optional  | End date (`YYYY-MM-DD`). **Default: today + 365 days**                                           |
| `unit`               | string, optional  | Case-insensitive substring match on the unit's `friendly_name`                                   |
| `okupai_property_id` | string, optional  | Filter to a single unit by its UUID (same ID as in the Bookings endpoint)                        |
| `changed_since`      | string, optional  | ISO-8601 timestamp; return only rows changed **after** this moment — ideal for incremental syncs |
| `limit`              | integer, optional | Page size; default 1000, max 5000                                                                |
| `offset`             | integer, optional | Items to skip; default 0                                                                         |

{% hint style="warning" %}
The maximum date window is **550 days** per request. For longer horizons, split into multiple requests.
{% endhint %}

### 📦 Pricing item fields

One item per unit per date:

| Field                | Type    | Description                                                             |
| -------------------- | ------- | ----------------------------------------------------------------------- |
| `okupai_property_id` | string  | UUID of the unit in OkupAI                                              |
| `friendly_name`      | string  | Human-readable unit name                                                |
| `date`               | string  | The night this row applies to (ISO date)                                |
| `price`              | number  | Nightly price for that date                                             |
| `available`          | boolean | Whether the night is open for sale                                      |
| `min_nights`         | number  | Minimum nights for arrival on this date                                 |
| `max_nights`         | number  | Maximum stay length; `null` when unlimited                              |
| `changed_at`         | string  | Last change timestamp — **only included when you pass `changed_since`** |

The top-level response also includes `"currency": "EUR"` — all prices are returned in EUR.

### 🏨 Multi-room listings (parent & child units)

For multi-room setups (e.g. a building with several bookable rooms), pricing data lives on the **parent object only**:

* The **parent object** carries the pricing rows — it is the only one with availability values (`>= 0`)
* **Child objects return no pricing data** — they inherit price, availability, and stay rules from their parent

When querying by `okupai_property_id`, always use the **parent's UUID** to get the rate calendar. If a unit returns no pricing rows, it is most likely a child unit — resolve its parent and query that instead.

### ⚡ Basic example

{% tabs %}
{% tab title="JavaScript" %}

```js
// Server-side (Node 18+). Don't expose API keys in the browser.
const BASE_URL = 'https://api.okup.ai';
const API_KEY = process.env.OKUPAI_API_KEY;

const res = await fetch(`${BASE_URL}/data/pricing?from=2026-07-01&to=2026-07-31`, {
  headers: { 'X-API-Key': API_KEY },
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
const data = await res.json();
console.log(data);
```

{% endtab %}

{% tab title="Python" %}

```python
import os, requests

BASE_URL = "https://api.okup.ai"
API_KEY = os.environ["OKUPAI_API_KEY"]

r = requests.get(
    f"{BASE_URL}/data/pricing",
    headers={"X-API-Key": API_KEY},
    params={"from": "2026-07-01", "to": "2026-07-31"},
    timeout=30,
)
r.raise_for_status()
print(r.json())
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -sS \
  -H "X-API-Key: $OKUPAI_API_KEY" \
  "https://api.okup.ai/data/pricing?from=2026-07-01&to=2026-07-31"
```

{% endtab %}
{% endtabs %}

Example response (truncated):

```json
{
  "total": 62,
  "limit": 1000,
  "offset": 0,
  "currency": "EUR",
  "items": [
    {
      "okupai_property_id": "123e4567-e89b-12d3-a456-426614174000",
      "friendly_name": "Main Apartment",
      "date": "2026-07-01",
      "price": 129.0,
      "available": true,
      "min_nights": 2,
      "max_nights": null
    }
  ]
}
```

### 🔁 Incremental sync with `changed_since`

Poll only for changes instead of re-downloading the full calendar. When `changed_since` is set, each item additionally includes `changed_at`:

```bash
curl -sS \
  -H "X-API-Key: $OKUPAI_API_KEY" \
  "https://api.okup.ai/data/pricing?changed_since=2026-07-01T00:00:00Z"
```

Store the highest `changed_at` you receive and use it as the next `changed_since` value.

### ❌ Error codes

* **400 Bad Request** — invalid parameter (bad date format, invalid UUID, window over 550 days, `to` before `from`)
* **401 Unauthorized** — missing `X-API-Key` header
* **403 Forbidden** — invalid key or verification failed
