Brokeys · Developers
A read-only REST API for villa owners and the agencies they work with: show villas, photos, availability and prices on a website, compute quotes, and sync bookings with your tools. All responses are JSON.
x-api-key header of every request to https://brokeys.app/api/v1.GET /villas to get your villa ids, then use them with the other endpoints.curl -H "x-api-key: bk_pub_..." https://brokeys.app/api/v1/villasconst res = await fetch('https://brokeys.app/api/v1/rates?villa=VILLA_ID&from=2027-07-01&to=2027-07-31', {
headers: { 'x-api-key': 'bk_pub_...' },
});
const { data } = await res.json(); // [{ date, available, price_eur, min_nights, checkin_allowed }, ...]| Type | Prefix | Where | Can read |
|---|---|---|---|
| Publishable | bk_pub_ | Website code, browser, apps | Villas, photos, availability, rates, quotes. No guest data. |
| Secret | bk_sec_ | Your server only | Everything above, plus bookings with guest names and totals. |
Secret keys are rejected when the request comes from a browser (it carries an Origin header), so a leaked front-end key can never expose guest data. A key sees only the villas the owner chose when creating it: all their villas (villas added later included) or a selection. Each agency gets its own key, limited to the villas it may sell; to change the villas, the owner revokes the key and creates a new one. A revoked key stops working immediately.
For publishable keys, villa coordinates are approximate (about 1 km), so a public website never reveals the exact address. Secret keys get the exact position.
data. Errors return { "error": { "code", "message" } }.YYYY-MM-DD, in the villa's local time (Europe/Madrid). from and to are inclusive.check_in up to the night before check_out: the check-out day is free for the next arrival. Busy ranges use the same rule (end = first free day).EUR), exactly as configured in Brokeys./bookings.| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_parameter, missing_parameter, range_too_large | Check the query parameters. |
| 401 | missing_api_key, invalid_api_key | Key missing, mistyped or revoked. |
| 402 | subscription_inactive | The Brokeys subscription of the villa owner who issued the key is not active. |
| 403 | secret_key_required | The endpoint needs a secret key (bookings). |
| 403 | secret_key_in_browser | A secret key was sent from a browser (Origin header). Use a publishable key there. |
| 403 | account_not_allowed | The key does not belong to a Brokeys villa owner account. Keys are issued only by villa owners. |
| 404 | villa_not_found, not_found | Villa id unknown or not shared with this key (the owner chooses which villas each key sees), or unknown endpoint. |
| 405 | method_not_allowed | The API is read-only: only GET. |
| 429 | rate_limited | Too many requests: wait for the Retry-After seconds. |
Each key allows 600 requests per minute. Every response carriesX-RateLimit-Limit and X-RateLimit-Remaining. Data changes a few times a day at most: cache responses on your side (5–15 minutes is plenty) instead of calling the API on every page view.
Every villa the key can see, with the essentials for a listing card. price_from_night_eur is the lowest nightly price in the next 12 months (null when no price is set).
curl -H "x-api-key: bk_pub_..." https://brokeys.app/api/v1/villasResponse
{
"data": [
{
"id": "3f2a9c1e-5b7d-4e8a-9c0f-1a2b3c4d5e6f",
"name": "Can Sol",
"tagline": "Sunset views over Es Vedrà",
"type": "villa",
"license": "ETV-1234-E",
"bedrooms": 5,
"bathrooms": 5,
"max_guests": 10,
"location": { "area": "Sant Josep", "district": null, "destination": "Ibiza", "country": "Spain",
"lat": 38.92, "lng": 1.29, "approximate": true },
"cover_photo": "https://.../cover.jpg",
"price_from_night_eur": 1320,
"min_nights": 7,
"checkin_days": "saturday"
}
]
}One villa with everything for its page: description, amenities, ordered photo gallery, check-in/out times, fees and the tourist tax configuration.
curl -H "x-api-key: bk_pub_..." https://brokeys.app/api/v1/villas/3f2a9c1e-5b7d-4e8a-9c0f-1a2b3c4d5e6fResponse
{
"data": {
"id": "3f2a9c1e-...", "name": "Can Sol", "...": "same fields as /villas, plus:",
"description": "A restored finca with ...",
"amenities": ["Air Conditioning", "Swimming Pool", "Wifi", "Sea View"],
"photos": [
{ "url": "https://.../1.jpg", "thumbnail_url": "https://.../1_t.jpg", "caption": "Pool", "room": "exterior" }
],
"check_in_time": "16:00",
"check_out_time": "10:00",
"cleaning_service": "3 Cleanings per week",
"fees": { "cleaning_eur": 0, "security_deposit_eur": 3000 },
"tourist_tax": { "per_adult_night_eur": 2, "exempt_under_age": 16, "half_rate_after_nights": 8 }
}
}Busy ranges per villa (confirmed bookings, owner blocks and imported calendars), merged. end is the first free day.
| Parameter | Required | Description |
|---|---|---|
villa | no | Villa id. Omit to get every villa of the key. |
from | no | First day. Default: today. |
to | no | Last day. Default: from + 18 months. Max range: 2 years. |
curl -H "x-api-key: bk_pub_..." "https://brokeys.app/api/v1/availability?from=2027-07-01&to=2027-08-31"Response
{
"from": "2027-07-01",
"to": "2027-08-31",
"data": {
"3f2a9c1e-...": [
{ "start": "2027-07-03", "end": "2027-07-17" },
{ "start": "2027-08-07", "end": "2027-08-14" }
]
}
}A day-by-day calendar for one villa: whether the night is free, its price, the minimum stay and whether a check-in is allowed that day. Everything a booking calendar widget needs in one call.
| Parameter | Required | Description |
|---|---|---|
villa | yes | Villa id. |
from | no | First day. Default: today. |
to | no | Last day. Default: from + 364 days. Max range: 550 days. |
price_eur is null when the night has no price (price on request). Some villas price shorter stays differently: use /quote for the exact total of a stay.
curl -H "x-api-key: bk_pub_..." "https://brokeys.app/api/v1/rates?villa=3f2a9c1e-...&from=2027-07-01&to=2027-07-31"Response
{
"villa": "3f2a9c1e-...",
"currency": "EUR",
"data": [
{ "date": "2027-07-03", "available": true, "price_eur": 2515, "min_nights": 7, "checkin_allowed": true },
{ "date": "2027-07-04", "available": true, "price_eur": 2515, "min_nights": 7, "checkin_allowed": false },
{ "date": "2027-07-05", "available": false, "price_eur": 2515, "min_nights": 7, "checkin_allowed": false }
]
}The price of a stay and whether it can be booked as requested: availability, minimum stay, check-in/out days and capacity.
| Parameter | Required | Description |
|---|---|---|
villa | yes | Villa id. |
check_in | yes | Arrival day. |
check_out | yes | Departure day (1–365 nights after check_in). |
adults | no | Adults. When given, the tourist tax is computed and included in total_eur. |
children | no | Guests under the tourist tax exempt age. Default 0. |
bookable is true only when issues is empty. Possible issues: unavailable, min_nights, checkin_day and checkout_day (Saturday-to-Saturday villas), max_guests, no_rate (some nights have no price: amounts are null) and past_dates. The security deposit is refundable and not part of the total.
curl -H "x-api-key: bk_pub_..." "https://brokeys.app/api/v1/quote?villa=3f2a9c1e-...&check_in=2027-07-03&check_out=2027-07-10&adults=6&children=2"Response
{
"data": {
"villa": "3f2a9c1e-...",
"check_in": "2027-07-03", "check_out": "2027-07-10", "adults": 6, "children": 2,
"nights": 7,
"min_nights": 7,
"available": true,
"bookable": true,
"issues": [],
"currency": "EUR",
"accommodation_eur": 17605,
"cleaning_fee_eur": 0,
"tourist_tax_eur": 84,
"total_eur": 17689,
"security_deposit_eur": 3000,
"nightly": [{ "date": "2027-07-03", "price_eur": 2515 }, "..."]
}
}Confirmed stays managed in Brokeys, oldest arrival first. For server-side syncs (CRM, accounting, your own back office).
| Parameter | Required | Description |
|---|---|---|
villa | no | Villa id. Omit for every villa of the key. |
from | no | Stays still running on or after this day. Default: today. |
to | no | Stays starting on or before this day. Default: no limit. |
status | no | Comma-separated: booked, completed, cancelled. Default: all except cancelled. |
limit | no | 1–500, default 100. |
offset | no | For paging: pass the next_offset of the previous response. |
curl -H "x-api-key: bk_sec_..." "https://brokeys.app/api/v1/bookings?from=2027-01-01&limit=100"Response
{
"data": [
{
"id": "8d1e...", "villa": "3f2a9c1e-...",
"check_in": "2027-07-03", "check_out": "2027-07-10", "nights": 7,
"status": "booked", "total_eur": 17605,
"guest_name": "Ana López", "adults": 6, "children": 2,
"direct": true, "created_at": "2026-11-02T10:14:00+00:00"
}
],
"next_offset": null
}Runs in the browser with a publishable key. It marks free days, shows the nightly price and lets guests pick only allowed check-in days.
<div id="brokeys-calendar"></div>
<script>
const KEY = 'bk_pub_...';
const VILLA = '3f2a9c1e-...';
fetch('https://brokeys.app/api/v1/rates?villa=' + VILLA, { headers: { 'x-api-key': KEY } })
.then((r) => r.json())
.then(({ data }) => {
const el = document.getElementById('brokeys-calendar');
el.innerHTML = data.slice(0, 60).map((d) =>
'<div class="day ' + (d.available ? 'free' : 'busy') + '">' + d.date +
(d.available && d.price_eur ? ' · €' + d.price_eur : '') +
(d.available && d.checkin_allowed ? ' · check-in ok' : '') + '</div>'
).join('');
});
</script>When a guest picks dates, call /quote to show the exact total before sending them to your booking or contact form.
Questions or a higher rate limit? Villa owners: open a ticket from Support in Brokeys. Agencies: ask the villa owner who issued your key.