Skip to content

Availability

GET /public/sites/{slug}/rooms/{roomId}/availability

Section titled “GET /public/sites/{slug}/rooms/{roomId}/availability”
Terminal window
curl -s "https://api.mrcharles.app/api/v1/public/sites/studio-uno-madrid/rooms/d9a36c09-…/availability?from=2026-10-08&to=2026-10-10"
Authnone
Cacheno-store — always fetch fresh
Rate limit120 req/min per IP
ParameterRequiredDefaultNotes
fromnotodayYYYY-MM-DD in the studio’s time zone
tonofromInclusive. A window longer than 31 days is clipped
{
"roomId": "d9a36c09-d151-5d4a-a077-296293b07be4",
"timezone": "Europe/Madrid",
"hourlyCents": 2500,
"currency": "EUR",
"minMinutes": 60,
"maxMinutes": 240,
"stepMinutes": 60,
"minNoticeMin": 60,
"maxAdvanceDays": 90,
"days": [
{ "date": "2026-10-08", "free": [{ "start": "09:00", "end": "22:00" }] },
{ "date": "2026-10-09", "free": [{ "start": "09:00", "end": "13:00" }, { "start": "15:30", "end": "23:00" }] },
{ "date": "2026-10-10", "free": [] }
]
}
FieldMeaning
free[]Continuous open spans, not slots. end is exclusive
minNoticeMinA booking must start at least this many minutes from now
maxAdvanceDaysNothing can be booked beyond this horizon
stepMinutesThe grid start times sit on, and the increment between durations

Spans already exclude: confirmed bookings, live holds, the studio’s own calendar, buffers between bookings, the minimum notice and the horizon. A day the room is closed comes back with "free": [].

const toMin = (t) => +t.slice(0, 2) * 60 + +t.slice(3, 5);
const toHHMM = (m) => `${String(Math.floor(m / 60)).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`;
function startTimes(free, duration, step) {
const out = [];
for (const { start, end } of free) {
const s = toMin(start), e = toMin(end);
for (let t = Math.ceil(s / step) * step; t + duration <= e; t += step) out.push(toHHMM(t));
}
return out;
}
startTimes([{ start: '09:00', end: '13:00' }], 120, 60);
// ['09:00', '10:00', '11:00']

And the durations that still fit from a chosen start:

function durations(free, start, { minMinutes, maxMinutes, stepMinutes }) {
const s = toMin(start);
const span = free.find((f) => toMin(f.start) <= s && s < toMin(f.end));
if (!span) return [];
const room = toMin(span.end) - s;
const out = [];
for (let d = minMinutes; d <= maxMinutes && d <= room; d += stepMinutes) out.push(d);
return out;
}
StatusCodeCause
404RESOURCE_NOT_FOUNDUnknown slug or room
404SITE_NOT_LIVEThe studio’s site is not published
409ROOM_NOT_BOOKABLEThe room does not take online bookings