Everything the app does to a villa, a booking or a customer is reachable over HTTP. A script — or
an agent — works on the same data as the interface, under the same rules, without a browser
session.
This page is the map: authentication, the shape of every answer, and every endpoint with the page
that details it. Each endpoint has its own page: one call, its parameters, its answers and what it
refuses.
Authentication
Every /api/v1 request carries an API key in the x-api-key header. A key is created from
Account → API Keys and belongs to one organization: that organization is the entire scope
of the key.
Not in the body, not in the URL, not in a header. It comes from the key and from nothing else. A
resource belonging to another organization answers 404, exactly like an id that does not exist.
The key acts as the person who created it
A key is not a second identity with its own powers. It carries the rights of the member who
created it, in the organization it was created for. Nothing is possible through the API that the
same person could not do in the interface — and nothing is refused that they could.
A key stops working when its bearer leaves the organization. No orphan access survives a
departure: the key answers 401 from that moment, exactly as if it had been revoked. Revoking the
key of someone who left is therefore housekeeping, not a security fix.
Two questions decide every call, and both have to pass:
Question
Decided by
Answer when it fails
Is the bearer still a member, and with which role?
The key's bearer and their role
401 / 403
Does the resource belong to the key's organization?
The key's organization
404
Who can do what
Operation
Minimum role in the organization
Reading anything
member
Creating and correcting customers, creating and managing bookings
member
Creating, renaming, archiving a villa, its photo, its hours, its rates
admin
Changing the booking settings of the organization
admin
That split is not an API decision: it is the product's own permission matrix. A member is often the
one with the customer on the phone, and the product reserves villa configuration to the owner and
the organization admins.
Missing or invalid key, or a key whose bearer left the organization
403
The bearer is a legitimate member, but their role is too low
404
Unknown resource, or a resource of another organization
409
State conflict — a slot taken, a status that moved, a plan limit reached
413
A batch over its bound; the message names the limit
422
Invalid parameters or body — details lists the offending fields
429
Rate limit of the key exceeded (120 requests per minute)
500
Unexpected server error
A resource of another organization answers 404, never 403. A 403 would confirm that the
id exists. The same response for an unknown id and for an id you are not allowed to read — you
cannot tell them apart, and that is the point. The 403 is reserved for the other question: you
are in the right organization, your role is too low.
Units and conventions
Amounts are integers in the minor unit of the organization currency. 1500000 in IDR is
15 000 rupiah; 4500 in EUR is 45,00 €. Never divide by 100 without knowing the currency.
Instants are ISO 8601 in UTC (startAt, endAt, createdAt).
Days and times are local to the organization: a booking is created with date (YYYY-MM-DD)
and startMinute (minutes from local midnight). Read settings.timezone from GET /api/v1/me.
Opening hours are weekly local minutes, dayOfWeek following 0 Sunday … 6 Saturday.
The limit is carried by the key, not by the IP: 120 requests per minute. A key over its limit
answers 429 on every endpoint. Back off and retry — nothing was done.
Where to start
Call GET /api/v1/me first: it turns a bare key into a
context — the organization it opens, the role it carries, the timezone and currency every other
call depends on, and how much room the plan leaves.
Then the usual path: find or create the customer, ask the availability of a villa, and
create the booking. The whole sequence, with its refusals, is walked in
Create a booking.