> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gabin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Construction sites and building permits

> List the building permits of a city, a department or an area, with their position: construction sites in progress, authorized and completed projects, as JSON or GeoJSON.

Building permits come from **Sitadel**, the French register of planning permissions kept by the SDES (statistics office of the ministry of ecological transition), through the BDNB. Gabin serves permits for building (*permis de construire*), development (*permis d'aménager*) and demolition (*permis de démolir*), and prior declarations (*déclarations préalables*). The permit number starts with its kind: `PC`, `PA`, `PD` or `DP`.

Each permit is placed on one of its cadastral parcels, with the building that stands on that parcel. Two endpoints serve them:

| Endpoint | Use |
| - | - |
| `GET /v1/permits` | Permits of an area (city, department, bounding box, circle), paginated, JSON or GeoJSON |
| `GET /v1/buildings/{id}/permits` | Permits on the parcels of one building. See [buildings](https://docs.gabin.ai/guides/buildings.md#building-sections) |

## Status of a permit

| `status` filter | Value in `status` | Meaning |
| - | - | - |
| `authorized` | `Autorisé` | The permit was granted; works have not been declared started |
| `started` | `Commencé` | The works-start declaration (*déclaration d'ouverture de chantier*) was filed: a construction site in progress |
| `completed` | `Terminé` | The completion declaration (*déclaration d'achèvement des travaux*) was filed |

Completion is often never declared, so an old `started` permit may be finished. Filter on `filed_after` or `started_after` to keep recent sites.

## Permits of an area

`GET /v1/permits` lists the permits of one area, ordered by permit number. Give exactly one area:

| Area | Parameters | Limit |
| - | - | - |
| Bounding box | `bbox=minLon,minLat,maxLon,maxLat` (WGS84) | 4 km² (2 km × 2 km) |
| Circle | `lat`, `lon` and `radius` (meters) | `radius` up to 1,000 |
| City or arrondissement | `insee` | |
| Department | `department` | |

Without an area, or with more than one, the API returns `400 INVALID`.

### Filters

**status** `string`

Statuses, comma-separated: `authorized`, `started`, `completed`. All by default.

**type** `string`

Permit types, comma-separated (any of them): `housing` (creates dwellings), `premises` (creates non-residential floor area), `demolition`, `development`.

**filed\_after** `integer`

Filed in or after this year. Default: 5 years before the current year.

**filed\_before** `integer`

Filed in or before this year. Default: the current year.

**started\_after** `string`

Works started on or after this date (`YYYY-MM-DD`).

**format** `string` (default: json)

`json` returns a list of permits. `geojson` returns a GeoJSON FeatureCollection of points in `data`.

This request lists the housing construction sites in progress in Villeurbanne:

```bash curl theme={null}
curl "https://api.gabin.ai/v1/permits?insee=69266&status=started&type=housing&limit=2" \
  -H "Authorization: Bearer $GABIN_API_KEY"
```

```javascript JavaScript theme={null}
const params = new URLSearchParams({ insee: "69266", status: "started", type: "housing", limit: "2" });
const res = await fetch(`https://api.gabin.ai/v1/permits?${params}`, {
  headers: { Authorization: `Bearer ${process.env.GABIN_API_KEY}` },
});
const { data: permits, meta } = await res.json();
```

```python Python theme={null}
import os
import requests

res = requests.get(
    "https://api.gabin.ai/v1/permits",
    params={"insee": "69266", "status": "started", "type": "housing", "limit": 2},
    headers={"Authorization": f"Bearer {os.environ['GABIN_API_KEY']}"},
)
permits = res.json()["data"]
```

```json theme={null}
{
  "data": [
    {
      "number": "PC0692662100002",
      "parcel_id": "69266000BM0020",
      "types": ["housing", "premises"],
      "status": "Commencé",
      "filed_year": 2021,
      "authorized_on": "2021-05-07",
      "works_started_on": "2021-12-21",
      "completed_on": null,
      "project_nature": "nouvelle construction",
      "main_use": "résidentiel",
      "housing_type": "collectif hors résidence",
      "residence_type": "résidence principale",
      "annex_type": "pas d’annexe",
      "housing_created": 33,
      "housing_demolished": 1,
      "living_area_created_m2": 2336,
      "premises_area_created_m2": 151,
      "land_area_m2": 431,
      "applicant": {
        "siren": "903438950",
        "name": "SNC ELOGE A VILLEURBANNE 69",
        "naf_code": "41.10D",
        "naf_label": "Supports juridiques de programmes",
        "legal_form": "SNC",
        "gabin_url": "https://gabin.ai/entreprise/snc-eloge-a-villeurbanne-69-903438950",
        …
      },
      "location": [4.871092, 45.770691],
      "building_id": "bdnb-bg-2GEE-6T99-RCCA",
      "gabin_url": "https://gabin.ai/batiment/bdnb-bg-2GEE-6T99-RCCA"
    },
    …
  ],
  "meta": {
    "page": { "next_cursor": "eyJ2IjoxLCJhIjoiUEMwNjkyNjYyMTAwMDA4Iiwi…", "limit": 2 },
    "total": 40,
    "total_kind": "exact"
  }
}
```

Each permit has the fields of the building section, plus:

* `location`: a point inside its cadastral parcel, WGS84 `[lon, lat]`. No geocoding is needed.
* `building_id`: the BDNB building on that parcel (the closest to the point), `null` for bare land. Open it with `GET /v1/buildings/{id}`.
* `gabin_url`: the page of that building on gabin.ai.

The applicant (`applicant`, the *maître d'ouvrage*) is given when it is a legal entity; an individual is never named. Only permits that Sitadel matches to a cadastral parcel are listed.

The total is counted on the first page (up to 10,000) and carried by the cursor. A page weighs 2 units. See [limits](https://docs.gabin.ai/limits.md#request-weights).

## Map of construction sites in progress

To map the construction sites of a department, ask for GeoJSON with `status=started` and follow the cursor: one call per page of 100 permits, not one call per company or per building. The positions are in the response.

**1. Fetch every page**

The Rhône (`69`) has about 2,600 started permits filed in the last five years: 27 pages, 54 units.

```javascript JavaScript theme={null}
const headers = { Authorization: `Bearer ${process.env.GABIN_API_KEY}` };
const features = [];
let cursor = null;
do {
  const params = new URLSearchParams({ department: "69", status: "started", format: "geojson", limit: "100" });
  if (cursor) params.set("cursor", cursor);
  const page = await fetch(`https://api.gabin.ai/v1/permits?${params}`, { headers }).then((r) => r.json());
  features.push(...page.data.features);
  cursor = page.meta.page.next_cursor;
} while (cursor);
const sites = { type: "FeatureCollection", features };
```

```python Python theme={null}
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['GABIN_API_KEY']}"}
params = {"department": "69", "status": "started", "format": "geojson", "limit": 100}
features = []
while True:
    page = requests.get("https://api.gabin.ai/v1/permits", params=params, headers=headers).json()
    features += page["data"]["features"]
    cursor = page["meta"]["page"]["next_cursor"]
    if not cursor:
        break
    params["cursor"] = cursor
sites = {"type": "FeatureCollection", "features": features}
```

Keep the other parameters unchanged when you pass `cursor`: a cursor is refused with other filters.

**2. Draw the points**

Each feature is a `Point` whose `properties` is the permit and whose `id` is the permit number.

```javascript theme={null}
map.addSource("construction-sites", { type: "geojson", data: sites });
map.addLayer({
  id: "construction-sites",
  type: "circle",
  source: "construction-sites",
  paint: { "circle-radius": 5, "circle-color": "#b8532f" },
});
```

**3. Open a site**

On click, `properties.building_id` opens the building with `GET /v1/buildings/{id}`, and `properties.gabin_url` links to its page on gabin.ai.

For France as a whole, loop over the departments. To refresh the map, store the permits and fetch again with `started_after` set to your last run.

At zoom 15 and 16, the `permits` [tile layer](https://docs.gabin.ai/guides/tiles.md) draws the same permits as vector tiles (`statut=commence` for sites in progress).

## Next steps

> [card] [Buildings](https://docs.gabin.ai/guides/buildings.md)
>
> Open the building of a permit: profile, companies, owners, sections.

> [card] [Vector tiles](https://docs.gabin.ai/guides/tiles.md)
>
> Draw permits and other layers at street level.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.