# baseray API reference

> The same building records you see in the app, as JSON: buildings in an area ranked by size, one building’s full record, the businesses registered at its address, and the buildings at a point.

Base URL: https://api.baseray.ai/v1 · Version 1.0.0 · OpenAPI document: https://baseray.ai/docs/api/openapi.json

## Authentication

Every request needs a workspace API key. Create one in the app under **Settings → API keys**; the key is shown once, so store it in your secret manager.

Send the key in the `Authorization` header as a bearer token. Keys belong to the workspace: anyone in the workspace can create one, and the creator or a workspace owner can revoke it. A key stops working when it is revoked, when it expires, or when its creator leaves the workspace.

## Rate limits and quotas

Each key can make 60 requests a minute. Each workspace can make 5,000 requests a day, counted per UTC day across all its keys.

Every response tells you where you stand: `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` for the minute, `X-Daily-Quota-Limit` and `X-Daily-Quota-Remaining` for the day. Over a limit you get `429` with a `Retry-After` header; wait that many seconds before retrying.

## Errors

Errors use the HTTP status and one JSON shape, so you can branch on `error.code`:

| Status | Code | Meaning |
|---|---|---|
| 400 | `invalid_parameter` | A parameter is missing or invalid. `error.parameter` names it. |
| 401 | `missing_api_key` | No `Authorization: Bearer` header was sent. |
| 401 | `invalid_api_key` | The key does not exist. |
| 401 | `revoked_api_key` | The key was revoked. |
| 401 | `expired_api_key` | The key has expired. Create a new one. |
| 403 | `insufficient_scope` | The key may not call this endpoint. |
| 403 | `workspace_access_revoked` | The key’s creator no longer belongs to the workspace. |
| 404 | `not_found` | No building has this id. |
| 429 | `rate_limited` | Over 60 requests this minute for this key. Retry after `Retry-After` seconds. |
| 429 | `quota_exceeded` | The workspace used its daily requests. The quota resets at midnight UTC. |
| 503 | `upstream_unavailable` | The data service is temporarily unavailable. Retry with exponential backoff. |

## Pagination

List endpoints take `limit` and `offset` and return `meta.total` with `links.next`, the URL of the next page or `null` on the last one. `offset + limit` may not exceed 10,000.

Counting stops at 10,000 buildings. When `meta.total_is_capped` is `true`, the area holds more than that: narrow the box or add filters rather than paging further.

## Buildings in an area, ranked

`GET /buildings` · https://baseray.ai/docs/api/list-buildings

One ranked page of the buildings inside `bbox` that pass every filter given. Filters of different names combine with AND; the values of one list filter combine with OR.

Parameters:

- `bbox` (query, string, required): The area to search: `minLon,minLat,maxLon,maxLat` in WGS84 degrees. Each side may span at most 3 degrees; search a county, city or district.
- `sort` (query, volume | area | height | registered_business_turnover | registered_business_employees, default "volume"): Ranking, largest first: `volume` (m³), `area` (footprint, m²), `height` (m), `registered_business_turnover` (the largest latest turnover of a business registered at the address) or `registered_business_employees` (the largest stated size; a band ranks where it starts, so 10–19 ranks as 10).
- `limit` (query, integer, 1–100, default 25): Buildings per page, 1 to 100.
- `offset` (query, integer, 0–10000, default 0): Buildings to skip, for the next page. `offset + limit` must be at most 10,000; past that, narrow `bbox`.
- `category` (query, array of residential_house | apartment_block | commercial | industrial | public | agricultural | ancillary | unknown): Keep buildings of any of these categories. Repeat the parameter or give a comma list: `category=commercial,industrial`. `ancillary` is an annex or outbuilding.
- `building_type` (query, array of string): Keep buildings of any of these granular types, combined with `category` by OR: e.g. `office`, `warehouse`, `school`, `apartments`, `garage`. Repeatable or a comma list.
- `roof_shape` (query, array of gabled | hipped | flat | pyramidal | skillion | round | mansard | half_hipped | gambrel | dome): Keep buildings with any of these roof shapes. Repeatable or a comma list.
- `min_floors` (query, integer, 0–500): At least this many floors above ground. Buildings where this value is unknown are left out.
- `max_floors` (query, integer, 0–500): At most this many floors above ground. Buildings where this value is unknown are left out.
- `min_dwellings` (query, integer, 0–1000000): At least this many dwellings, where known. Buildings where this value is unknown are left out.
- `max_dwellings` (query, integer, 0–1000000): At most this many dwellings, where known. Buildings where this value is unknown are left out.
- `min_entrances` (query, integer, 1–1000000): At least this many entrances (each listed address of the building counts as one). Buildings where this value is unknown are left out.
- `max_entrances` (query, integer, 1–1000000): At most this many entrances. Buildings where this value is unknown are left out.
- `address_corroboration` (query, array of corroborated | single_source | conflicting): Keep buildings whose shown address is graded any of: `corroborated` (an independent record gives the same house number), `single_source` (only one record), `conflicting` (another record gives another number). Buildings shown without a house number match none.
- `min_area_m2` (query, number, 0–1000000000): Minimum ground footprint, in square metres.
- `max_area_m2` (query, number, 0–1000000000): Maximum ground footprint, in square metres.
- `min_height_m` (query, number, 0–1000): Minimum height, in metres. Buildings where this value is unknown are left out.
- `max_height_m` (query, number, 0–1000): Maximum height, in metres. Buildings where this value is unknown are left out.
- `min_volume_m3` (query, number, 0–1000000000): Minimum volume, in cubic metres. Buildings where this value is unknown are left out.
- `max_volume_m3` (query, number, 0–1000000000): Maximum volume, in cubic metres. Buildings where this value is unknown are left out.
- `measured_height_only` (query, boolean, default false): Keep only buildings whose height is measured, not estimated.
- `existing_solar_panels` (query, array of detected | none_seen | unclear): Keep buildings whose roof photo was checked for solar panels with any of these results. Buildings never checked, or whose photo was too coarse to check, match none. Repeatable or a comma list.
- `has_solar_potential` (query, boolean, default false): Keep only buildings whose roof has a solar-potential estimate.
- `min_panel_count` (query, integer, 0–1000000): At least this many solar panels fit on the roof. Buildings where this value is unknown are left out.
- `max_panel_count` (query, integer, 0–1000000): At most this many solar panels fit on the roof. Buildings where this value is unknown are left out.
- `min_capacity_kwp` (query, number, 0–1000000000): Minimum rooftop solar capacity, in kWp. Buildings where this value is unknown are left out.
- `max_capacity_kwp` (query, number, 0–1000000000): Maximum rooftop solar capacity, in kWp. Buildings where this value is unknown are left out.
- `min_yearly_energy_kwh` (query, number, 0–1000000000): Minimum yearly rooftop solar energy, in kWh. Buildings where this value is unknown are left out.
- `max_yearly_energy_kwh` (query, number, 0–1000000000): Maximum yearly rooftop solar energy, in kWh. Buildings where this value is unknown are left out.
- `min_co2_savings_kg_per_year` (query, number, 0–1000000000): Minimum CO₂ a rooftop solar installation would save, in kg a year. Buildings where this value is unknown are left out.
- `max_co2_savings_kg_per_year` (query, number, 0–1000000000): Maximum CO₂ a rooftop solar installation would save, in kg a year. Buildings where this value is unknown are left out.
- `has_3d_model` (query, boolean, default false): Keep only buildings with a reconstructed 3D model of their roof.
- `has_registered_business` (query, boolean, default false): Keep only buildings with at least one active business whose registered office is the building's address. A registered office is never ownership or occupancy.
- `registered_business_name` (query, string, 2–120 characters): Keep buildings where the name of a business registered at the address contains this text.
- `min_registered_business_turnover` (query, integer): Minimum latest turnover of a business registered at the address, in whole units of `registered_business_turnover_currency` (required with it).
- `max_registered_business_turnover` (query, integer): Maximum latest turnover of a business registered at the address, in whole units of `registered_business_turnover_currency` (required with it).
- `registered_business_turnover_currency` (query, string): ISO 4217 currency of the turnover bounds, e.g. `RON`, `CZK`, `EUR`. Required with a turnover bound.
- `registered_business_financial_year` (query, integer, 1990–2100): Keep buildings whose registered business's latest financial statement is for this year.
- `min_registered_business_employees` (query, integer, 0–1000000): At least this many employees in one business registered at the address, reading its whole stated size: a band counts only when all of it is at or above the value (10–19 matches 10, not 15). A business whose size is not stated never matches.
- `max_registered_business_employees` (query, integer, 0–1000000): At most this many employees in every business registered at the address whose size is stated; an open-ended top band never matches.
- `has_annual_heating_estimate` (query, boolean, default false): Keep only buildings with an annual heating-demand estimate for the local climate.
- `has_thermal_assessment` (query, boolean, default false): Keep only buildings with a building-specific thermal assessment (energy certificate, audit, as-built model or survey).
- `has_peak_heat_load` (query, boolean, default false): Keep only buildings whose thermal assessment supplies the design temperatures a peak heat load needs.
- `has_recent_climate_trend` (query, boolean, default false): Keep only buildings with a recent rolling climate average and trend at their location.
- `has_recent_temperature_extremes` (query, boolean, default false): Keep only buildings with a complete recent temperature-extremes profile at their location.
- `has_recent_precipitation` (query, boolean, default false): Keep only buildings with a complete recent precipitation profile at their location.
- `min_recent_frost_days` (query, number, 0–366): At least this many frost days a year, averaged over recent complete years. Buildings where this value is unknown are left out.
- `max_recent_minimum_daily_temperature_c` (query, number, -100–100): The coldest daily minimum of recent complete years is at most this, in °C. Buildings where this value is unknown are left out.
- `min_recent_hot_days` (query, number, 0–366): At least this many hot days a year, averaged over recent complete years. Buildings where this value is unknown are left out.
- `min_recent_max_one_day_precipitation_mm` (query, number, 0–5000): The wettest single day of recent complete years brought at least this much precipitation, in mm. Buildings where this value is unknown are left out.

```sh
curl "https://api.baseray.ai/v1/buildings?bbox=25.55,45.60,25.68,45.70&sort=volume&limit=25&offset=0&category=residential_house&building_type=&roof_shape=gabled&address_corroboration=corroborated&measured_height_only=false&existing_solar_panels=detected&has_solar_potential=false&has_3d_model=false&has_registered_business=false&registered_business_turnover_currency=RON&has_annual_heating_estimate=false&has_thermal_assessment=false&has_peak_heat_load=false&has_recent_climate_trend=false&has_recent_temperature_extremes=false&has_recent_precipitation=false" \
  -H "Authorization: Bearer $BASERAY_API_KEY"
```

Response 200:

```json
{
  "data": [
    {
      "building_id": "c9eefd1b-8c8d-48fe-8b72-e015374d7720",
      "address": "Bulevardul 15 Noiembrie 78",
      "locality": "Brașov",
      "country": "RO",
      "latitude": 45.64988,
      "longitude": 25.61044,
      "category": "commercial",
      "footprint_area_m2": 31252,
      "height": {
        "metres": 18,
        "basis": "estimated"
      },
      "volume_m3": 562531,
      "volume_basis": "estimated",
      "floors": 16,
      "existing_solar_panels": {
        "status": "none_seen",
        "photo_date": "2022-09-08",
        "confidence": 0.988
      },
      "solar_potential": null,
      "registered_business_count": 0,
      "app_url": "https://app.baseray.ai/?building=c9eefd1b-8c8d-48fe-8b72-e015374d7720"
    }
  ],
  "meta": {
    "total": 1,
    "total_is_capped": false,
    "limit": 25,
    "offset": 0,
    "sort": "volume"
  },
  "links": {
    "next": null
  }
}
```

## Buildings at a point

`GET /buildings/at` · https://baseray.ai/docs/api/find-buildings-at-point

The buildings whose outline lies within `radius_m` of a point, nearest first.

Parameters:

- `lat` (query, number, required, -90–90): Latitude of the point, WGS84.
- `lon` (query, number, required, -180–180): Longitude of the point, WGS84.
- `radius_m` (query, number, 1–200, default 25): How far from the point to look, in metres.
- `limit` (query, integer, 1–25, default 10): How many buildings to return, nearest first.

```sh
curl "https://api.baseray.ai/v1/buildings/at?lat=45.64988&lon=25.61044&radius_m=25&limit=10" \
  -H "Authorization: Bearer $BASERAY_API_KEY"
```

Response 200:

```json
{
  "data": [
    {
      "building_id": "c9eefd1b-8c8d-48fe-8b72-e015374d7720",
      "address": "Bulevardul 15 Noiembrie 78",
      "locality": "Brașov",
      "country": "RO",
      "latitude": 45.64988,
      "longitude": 25.61044,
      "category": "commercial",
      "footprint_area_m2": 31252,
      "height": {
        "metres": 18,
        "basis": "estimated"
      },
      "volume_m3": 562531,
      "volume_basis": "estimated",
      "floors": 16,
      "existing_solar_panels": {
        "status": "none_seen",
        "photo_date": "2022-09-08",
        "confidence": 0.988
      },
      "solar_potential": null,
      "registered_business_count": 0,
      "app_url": "https://app.baseray.ai/?building=c9eefd1b-8c8d-48fe-8b72-e015374d7720"
    }
  ]
}
```

## One building

`GET /buildings/{building_id}` · https://baseray.ai/docs/api/get-building

One building's record. A building the catalogue no longer holds is still returned with `is_current` false and, where one now stands on its ground, `replaced_by_building_id`.

Parameters:

- `building_id` (path, string (uuid), required): The building's baseray id, a UUID returned by the other building endpoints.

```sh
curl "https://api.baseray.ai/v1/buildings/c9eefd1b-8c8d-48fe-8b72-e015374d7720" \
  -H "Authorization: Bearer $BASERAY_API_KEY"
```

Response 200:

```json
{
  "data": {
    "building_id": "c9eefd1b-8c8d-48fe-8b72-e015374d7720",
    "address": "Bulevardul 15 Noiembrie 78",
    "locality": "Brașov",
    "country": "RO",
    "latitude": 45.64988,
    "longitude": 25.61044,
    "category": "commercial",
    "footprint_area_m2": 31252,
    "height": {
      "metres": 18,
      "basis": "estimated"
    },
    "volume_m3": 562531,
    "volume_basis": "estimated",
    "floors": 16,
    "existing_solar_panels": {
      "status": "none_seen",
      "photo_date": "2022-09-08",
      "confidence": 0.988
    },
    "solar_potential": null,
    "registered_business_count": 0,
    "app_url": "https://app.baseray.ai/?building=c9eefd1b-8c8d-48fe-8b72-e015374d7720",
    "dwellings": null,
    "entrances": null,
    "is_current": true,
    "replaced_by_building_id": null
  }
}
```

## Businesses registered at a building's address

`GET /buildings/{building_id}/registered-businesses` · https://baseray.ai/docs/api/list-building-registered-businesses

The active businesses whose registered office is the building's exact official address, largest first, at most 25; `meta.total` counts them all. A registered office is never ownership or occupancy.

Parameters:

- `building_id` (path, string (uuid), required): The building's baseray id, a UUID returned by the other building endpoints.

```sh
curl "https://api.baseray.ai/v1/buildings/c9eefd1b-8c8d-48fe-8b72-e015374d7720/registered-businesses" \
  -H "Authorization: Bearer $BASERAY_API_KEY"
```

Response 200:

```json
{
  "data": [
    {
      "name": "Example Business SRL",
      "registration_number": "00000000",
      "country": "RO",
      "employees": "10–49",
      "employees_stated_for": "FY 2024"
    }
  ],
  "meta": {
    "total": 1
  }
}
```

## This document

`GET /openapi.json` · https://baseray.ai/docs/api/get-open-api-document

The OpenAPI 3.1 document of this API. Public and cacheable (`Cache-Control: public, max-age=3600`, `ETag`).


```sh
curl "https://api.baseray.ai/v1/openapi.json"
```

Response 200:

```json
{}
```

## Schemas

### Height

- `metres` (number): Height in metres.
- `basis` (measured | estimated): `measured`, or `estimated` (modelled).

### ExistingSolarPanels

Whether solar panels are already on the roof, as a dated photo of the roof shows it.

- `status` (detected | none_seen | unclear | not_checked): `detected`, `none_seen`, `unclear`, or `not_checked` (never checked, or the photo was too coarse to check).
- `photo_date` (string (date) or null): Date of the photo checked; null when undated or never checked.
- `confidence` (number or null, 0–1): The check's confidence in its result, 0 to 1; null when not checked.

### SolarPotential

Rooftop solar potential, present only where the roof has been modelled.

- `max_panel_count` (integer or null): Solar panels that fit on the roof.
- `max_capacity_kwp` (number or null): Capacity of those panels, in kWp.
- `yearly_energy_kwh` (number or null): Energy they would produce in a year, in kWh.
- `usable_roof_area_m2` (number or null): Roof area usable for panels, in m².
- `co2_savings_kg_per_year` (number or null): CO₂ the installation would save, in kg a year.

### BuildingSummary

- `building_id` (string (uuid)): The building's baseray id.
- `address` (string or null): Street and house number as recorded; null when the building has no address on record.
- `locality` (string or null): Town, city or village.
- `country` (string or null): ISO 3166-1 alpha-2 country code.
- `latitude` (number): Latitude of the building's centre, WGS84.
- `longitude` (number): Longitude of the building's centre, WGS84.
- `category` (residential_house | apartment_block | commercial | industrial | public | agricultural | ancillary | unknown): Building category; `ancillary` is an annex or outbuilding.
- `footprint_area_m2` (number): Ground footprint, in m².
- `height` (Height or any or null): Height; null when unknown.
- `volume_m3` (number or null): Volume, in m³; null when unknown.
- `volume_basis` (measured | estimated or null): Whether the volume is measured or estimated; null with the volume.
- `floors` (integer or null): Floors above ground; null when unknown.
- `existing_solar_panels` (ExistingSolarPanels): Whether solar panels are already on the roof, as a dated photo of the roof shows it.
- `solar_potential` (SolarPotential or any or null): Rooftop solar potential; null where the roof has not been modelled.
- `registered_business_count` (integer, ≥ 0): Active businesses whose registered office is the building's address. Never ownership or occupancy.
- `app_url` (string (uri)): The building in the baseray app.

### BuildingDetail

- `building_id` (string (uuid)): The building's baseray id.
- `address` (string or null): Street and house number as recorded; null when the building has no address on record.
- `locality` (string or null): Town, city or village.
- `country` (string or null): ISO 3166-1 alpha-2 country code.
- `latitude` (number): Latitude of the building's centre, WGS84.
- `longitude` (number): Longitude of the building's centre, WGS84.
- `category` (residential_house | apartment_block | commercial | industrial | public | agricultural | ancillary | unknown): Building category; `ancillary` is an annex or outbuilding.
- `footprint_area_m2` (number): Ground footprint, in m².
- `height` (Height or any or null): Height; null when unknown.
- `volume_m3` (number or null): Volume, in m³; null when unknown.
- `volume_basis` (measured | estimated or null): Whether the volume is measured or estimated; null with the volume.
- `floors` (integer or null): Floors above ground; null when unknown.
- `existing_solar_panels` (ExistingSolarPanels): Whether solar panels are already on the roof, as a dated photo of the roof shows it.
- `solar_potential` (SolarPotential or any or null): Rooftop solar potential; null where the roof has not been modelled.
- `registered_business_count` (integer, ≥ 0): Active businesses whose registered office is the building's address. Never ownership or occupancy.
- `app_url` (string (uri)): The building in the baseray app.
- `dwellings` (integer or null): Dwellings, where known; null when unknown.
- `entrances` (integer or null): Entrances: each listed address of the building counts as one; null when none are listed.
- `is_current` (boolean): False once the building is no longer in the catalogue's current release.
- `replaced_by_building_id` (string (uuid) or null): The building now standing on a retired building's ground, when there is one.

### RegisteredBusiness

Registered office at this address; never ownership or occupancy.

- `name` (string): The business's registered name.
- `registration_number` (string): Its company registration number (a CUI in Romania, an IČO in Czechia).
- `country` (string): ISO 3166-1 alpha-2 country of the registration number.
- `employees` (string or null): Employees as stated: an exact count (`12`), a band (`10–49`) or an open top band (`1000 or more`); null when not stated.
- `employees_stated_for` (string or null): When the size was stated: a date, or a financial year such as `FY 2024`.

### PaginationMeta

- `total` (integer, ≥ 0): Buildings matching, counted up to 10,000.
- `total_is_capped` (boolean): True when counting stopped at 10,000; narrow the box for an exact total.
- `limit` (integer): The page size used.
- `offset` (integer): The offset used.
- `sort` (volume | area | height | registered_business_turnover | registered_business_employees): The ranking used.

### Links

- `next` (string (uri) or null): The next page's URL; null on the last page.

### BuildingPage

- `data` (array of BuildingSummary)
- `meta` (PaginationMeta)
- `links` (Links)

### BuildingList

- `data` (array of BuildingSummary): Nearest first.

### BuildingDetailEnvelope

- `data` (BuildingDetail)

### RegisteredBusinessList

- `data` (array of RegisteredBusiness)
- `meta` (object)

### Error

- `error` (object)
