Catalogue
Projects and units — the full shape, what a PUT clears, and the one rule about status.
The catalogue is projects, and units inside them. A project is a development — a name, a city, a developer — and a unit is one thing for sale in it. Both are yours to create, replace, patch and delete; the API reference has every field and its constraints.
Identity
| Thing | Addressed by | Rule |
|---|---|---|
| Project | slug | 2–100 characters: a-z, 0-9, single dashes. Becomes part of the storefront URL |
| Unit | project slug + unit code | 1–50 characters, unique within its project. Anything your system uses |
You never store a Maalam id. Every response includes one, but nothing asks for it back.
PUT replaces, PATCH changes
A PUT is the whole thing. Optional fields you leave out are cleared: send a unit without
description and its description is gone. That is what makes a full re-sync from your system
correct rather than cumulative.
A PATCH is only what it names. Send { "priceSar": 990000 } and nothing else moves.
Two exceptions to "PUT clears", both deliberate:
depositPercent— left out, a new unit takes your workspace's default; an existing unit keeps what it has. The deposit is a commercial setting, not a listing fact.status— left out, it is left alone. See below.
The rule about status
A unit's status is one of available, unavailable, held, reserved, sold.
You may set the first two. The last three are derived: they follow the bookings, and only Maalam writes them. The API refuses to let a request override one:
{
"error": {
"code": "conflict",
"message": "A held unit follows its booking; it cannot be set by hand",
"details": { "field": "status", "status": "held" }
}
}Leave status out of a re-sync
A nightly job that pushes every unit with "status": "available" will be refused on every unit
a buyer happens to be mid-way through. Leave status out of a PUT unless you mean to take a
unit off sale (unavailable) or put one back (available). Everything else about the unit
still updates.
What is frozen mid-booking
While a unit is held or reserved, a buyer has been quoted a price. priceSar,
depositPercent, vatRate and vatIncluded cannot change until the booking resolves:
{
"error": {
"code": "conflict",
"message": "The price of a reserved unit cannot change",
"details": { "field": "priceSar", "status": "reserved" }
}
}Every other field can. A PUT that repeats the current price is fine — only a change is refused.
Photographs and documents
images is a list of URLs; files is a list of { name, url }. Maalam does not copy them: the
links are shown as they are, so they must be public and stable.
When either list is present in a PUT, it replaces the unit's linked media of that kind.
When both are absent, the unit's media is left alone. Photographs uploaded through the Maalam
back office are never touched by this API.
Deleting a unit
DELETE /v1/integration/projects/alasala/units/A-101A unit nobody has ever held or booked is deleted: { "outcome": "deleted" }.
A unit with history is not. The bookings behind it are records — a signed agreement, a paid
deposit — so the unit is taken off sale instead: { "outcome": "archived" }, and its status
becomes unavailable. Sending it again with a PUT puts it back.
Projects cannot be deleted through the API. A project empties out as its units are archived.
Batches
POST /v1/integration/units/batchUp to 100 units in one request, each with its project and code, each handled exactly
like a single PUT. It is not a transaction: one bad unit does not undo the others, and each
item reports its own outcome:
{
"results": [
{ "project": "alasala", "code": "A-101", "outcome": "created" },
{ "project": "alasala", "code": "A-102", "outcome": "updated" },
{
"project": "north",
"code": "V-1",
"outcome": "error",
"error": { "code": "not_found", "message": "Project \"north\" was not found" }
}
]
}The response is always 200; look at each outcome.
Money
priceSar is a whole number of riyals. vatIncluded says whether it already contains VAT at
vatRate (0.15 = 15%). What a buyer sees is worked out from these on Maalam's side, so a
storefront card and the booking page can never disagree.