Skip to content

Core concepts

A few conventions apply to every operation in the Catalogue API. Knowing them up front saves surprises when you parse responses or build filters.

Every response, except the unauthenticated healthcheck at /, is wrapped in one of two envelopes:

{ "status": "success", "data": { } }
{ "status": "error", "message": "invalid api key" }

The shape of data depends on the operation. Error messages are human-readable strings; see Troubleshooting for the ones you are likely to meet.

Each key has a price_vector: a markup (positive) or discount (negative) in percent. Its multiplier form is reported by GET /whoIAm as price_factor = 1 + price_vector / 100. The vector is applied to every price in every response — price_from in project lists, unit_price in project costs, price on units and in application results.

It also works in reverse on filters. Price bounds such as price_min, price_max, price_per_ft2_* and price_per_m2_* are expressed in the prices the client sees, with the vector already applied; the service converts them back to base prices before querying. As a result, filtering and displayed prices are always consistent, and two keys with different vectors see different numbers for the same unit.

The service does not serve files; it only returns links. A file url is STATIC_BASE_URL followed by the full stored path, and it is served by an external host (a static server, a CDN or the main backend) without a key. Use the URLs as they are — do not send your API key to them.

Field names are in snake_case, with one exception: GET /units/{id} returns the underlying data model as is. In that response the nested project.company and project.author objects use PascalCase keys (CompanyName, Email, …), as do the project’s own CreatedAt and UpdatedAt. The reference schemas reflect the response exactly, so map these fields explicitly in your client.