openapi: 3.1.0
info:
  title: Identix.org API
  version: 1.0.0-beta
  description: |
    Platform met alle API's van Nederland, gestandaardiseerd. Elke bron-API is
    individueel aanspreekbaar via /v1/{bron}/{entiteit}; achter de schermen
    vragen wij live op bij de bron, zetten de data om naar de Identix.org-
    standaard en geven die door. Geen gecombineerde data, geen datastore.

    De Identix.org-standaard (elke API, elk antwoord):
    * vaste envelop: `api`, `versie`, `onderdeel`, `gegenereerd_op`, `duur_ms`,
      `bronnen[]` (herkomst, licentie, attributie, timing), `data`
    * veldconventies: snake_case, ISO-8601, coördinaten in WGS84 én RD
    * `null` = onbekend/afgeschermd bij de bron
    * fouten: altijd RFC 7807
  contact:
    name: Identix.org (initiatief van identix)
servers:
  - url: https://Identix.org
  - url: https://nederland.identix.org
  - url: http://localhost:8080
paths:
  /v1/regio/{code}:
    get:
      summary: Eigen dienst · Regio-alles — alles over één regio
      description: |
        Derde vlaggenschip (naast adres-alles en punt-alles): CBS-kerncijfer-
        profiel, opvallendste afwijkingen t.o.v. het landelijk gemiddelde
        (top-5 per richting), trend over de CBS-jaartabellen met delta's,
        woningmarkt-verkoopprijzen (laatste drie jaar), onderliggende wijken
        of buurten (grootste drie op inwoners) en relevante open datasets
        over de gemeente — parallel in één call. Vervolg-links naar de
        detail-diensten (/landelijk, /trend, /woningmarkt, /top,
        /vergelijk, /monitoring).
      parameters:
        - name: code
          in: path
          required: true
          schema: { type: string }
          example: GM0363
          description: CBS-regiocode (GM/WK/BU)
      responses:
        "200": { description: Regio-profiel (bron_type eigen-dienst) }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/punt/{lon}/{lat}/context:
    get:
      summary: Eigen dienst · Punt-context — alles rond één coördinaat
      description: |
        Reverse geocoding naar het dichtstbijzijnde adres + CBS-kerncijfers van
        buurt en wijk + kadastrale percelen en bebouwing + rijksmonumenten.
        Zonder adres binnen de radius: alleen de kadastrale lagen.
      parameters:
        - name: lon
          in: path
          required: true
          schema: { type: number, format: float }
          example: 4.8937
        - name: lat
          in: path
          required: true
          schema: { type: number, format: float }
          example: 52.3733
        - name: radius
          in: query
          required: false
          schema: { type: integer, minimum: 10, maximum: 2000, default: 150 }
          description: Zoekstraal dichtstbijzijnde adres in meters
      responses:
        "200": { description: Punt-context (bron_type eigen-dienst) }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/regio/{code}/top:
    get:
      summary: Eigen dienst · Regio-ranglijst — top-N binnen een gebied
      description: |
        Alle wijken of buurten van een gemeente (GM…) of wijk (WK…) op één
        CBS-kenmerk gerangschikt. Eén bulkcall — geen N profielrequests.
      parameters:
        - name: code
          in: path
          required: true
          schema: { type: string, pattern: '^(GM|WK)[0-9A-Za-z]+$' }
          example: GM0363
        - name: kenmerk
          in: query
          required: false
          schema: { type: string, default: inwoners }
          example: gemiddelde_woz_waarde
        - name: n
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 50, default: 10 }
        - name: richting
          in: query
          required: false
          schema: { type: string, enum: [hoogste, laagste], default: hoogste }
        - name: niveau
          in: query
          required: false
          schema: { type: string, enum: [wijk, buurt] }
      responses:
        "200": { description: Ranglijst met rang, code en waarde }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/rechtspraak/{ecli}/relevante-artikelen:
    get:
      summary: Eigen dienst · Uitspraak-artikelen — wetgeving in één uitspraak
      description: |
        Extraheert wetsartikel-verwijzingen (BW-citaties en bekende wetten) uit
        de uitspraaktekst, met BWB-id en artikel-endpoint per citatie.
      parameters:
        - name: ecli
          in: path
          required: true
          schema: { type: string, pattern: '^ECLI:NL:[A-Z0-9]+:[0-9]{4}:[0-9A-Z]+$' }
          example: ECLI:NL:RBNHO:2026:8258
      responses:
        "200": { description: Verwijzingen met citatie, bwb_id en artikel_endpoint }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/regio/{code}/landelijk:
    get:
      summary: Eigen dienst · Regio vs. landelijk gemiddelde
      description: |
        Afwijking per kerncijfer t.o.v. het Nederlandse gemiddelde. Alleen
        vergelijkbare metrics; absolute totalen staan apart.
      parameters:
        - name: code
          in: path
          required: true
          schema: { type: string, pattern: '^(BU|WK|GM)[0-9A-Za-z]+$' }
          example: WK0363AE
      responses:
        "200": { description: Vergelijkbare kenmerken met afwijking_pct }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/monitoring/regio/{code}:
    get:
      summary: Eigen dienst · Monitoring-regio — wijzigingen per regio
      description: |
        CBS-kerncijfers en woningmarkt-verkoopprijzen per buurt/wijk/gemeente
        met per bron een hash — pull-based monitoring.
      parameters:
        - name: code
          in: path
          required: true
          schema: { type: string, pattern: '^(BU|WK|GM)[0-9A-Za-z]+$' }
          example: WK0363AE
      responses:
        "200": { description: Monitoring-hash met per-bron hashes }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/monitoring/pand/{postcode}/{huisnummer}:
    get:
      summary: Eigen dienst · Monitoring-pand — wijzigingen detecteren
      description: |
        Alle wijzigingsgevoelige gegevens rond een adres met per bron een hash.
        Pull-based monitoring: bewaar de hash en vergelijk.
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1012JS
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
      responses:
        "200": { description: Monitoring-hash met per-bron hashes }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/pand/{postcode}/{huisnummer}/woz:
    get:
      summary: Eigen dienst · Pand-WOZ — vastgestelde WOZ-waarden per object
      description: |
        Vastgestelde WOZ-waarden over alle peiljaren uit het publieke
        WOZ-waardeloket. Meerdere objecten per huisnummer mogelijk.
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1015CC
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
        - name: letter
          in: query
          required: false
          schema: { type: string }
        - name: toevoeging
          in: query
          required: false
          schema: { type: string }
      responses:
        "200": { description: WOZ-objecten met waarde-historie }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/adres/{postcode}/{huisnummer}/subsidies:
    get:
      summary: Eigen dienst · Adres-subsidies — verduurzamingssubsidies per adres
      description: |
        Actuele ISDE-bedragen per maatregel (RVO) rond één adres met vervolg-
        lonings. Landelijke bedragen, periodiek gewijzigd (opgevraagd_op in respons).
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1012JS
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
      responses:
        "200": { description: Subsidierubrieken met bedragen en vervolglonings }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/regio/{code}/woningmarkt:
    get:
      summary: Eigen dienst · Regio-woningmarkt — verkoopprijzen over jaren
      description: |
        Gemiddelde verkoopprijs bestaande koopwoningen per gemeente (CBS,
        vanaf 1995) met jaar-op-jaar-delta's plus WOZ/voorraad-context.
        Wijk/buurt mappen op de bovenliggende gemeente.
      parameters:
        - name: code
          in: path
          required: true
          schema: { type: string, pattern: '^(GM|WK|BU)[0-9A-Za-z]+$' }
          example: GM0363
        - name: jaren
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 31, default: 10 }
      responses:
        "200": { description: Prijsreeks met delta's en context }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/pand/{postcode}/{huisnummer}/waarde-indicatie:
    get:
      summary: Eigen dienst · Waarde-indicatie — open kengetallen per adres
      description: |
        Buurt-/wijk-WOZ, woningvoorraad en gemeentelijke verkoopprijs-reeks
        rond één adres. Expliciet géén taxatie of AVM.
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1012JS
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
      responses:
        "200": { description: Open kengetallen met geen-taxatie-toelichting }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/regio/{code}/trend:
    get:
      summary: Eigen dienst · Regio-trend — kerncijfers over jaren
      description: |
        CBS-kerncijfers van één regio over de beschikbare jaartabellen, per
        kenmerk een reeks met jaar-op-jaar-delta's. Adapter-fallback op een
        ander jaartabel wordt gedetecteerd (geen gedupliceerde jaren).
      parameters:
        - name: code
          in: path
          required: true
          schema: { type: string, pattern: '^(BU|WK|GM)[0-9A-Za-z]+$' }
          example: WK0363AE
      responses:
        "200": { description: Reeksen per kenmerk met delta's }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/punt/{lon}/{lat}/reistijden:
    get:
      summary: Eigen dienst · Punt-reistijden — actuele reistijden bij een punt
      description: |
        Dichtstbijzijnde verkeersmeetpunten (100k+ landelijk) met actuele
        reistijd per wegvak. Meetpunten 24-uurs, waarden 10-min gecached;
        eerste call na verval kan tientallen seconden duren.
      parameters:
        - name: lon
          in: path
          required: true
          schema: { type: number, format: float }
          example: 4.8937
        - name: lat
          in: path
          required: true
          schema: { type: number, format: float }
          example: 52.3733
        - name: radius
          in: query
          required: false
          schema: { type: integer, minimum: 100, maximum: 50000, default: 10000 }
        - name: n
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 25, default: 10 }
      responses:
        "200": { description: Meetpunten met actuele reistijden }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/punt/{lon}/{lat}/brugopeningen:
    get:
      summary: Eigen dienst · Punt-brugopeningen — brugopeningen + SRTI
      description: |
        Geplande brugopeningen (RIS-locaties, geldigheidsvensters) en actuele
        SRTI-veiligheidsberichten bij een punt.
      parameters:
        - name: lon
          in: path
          required: true
          schema: { type: number, format: float }
          example: 4.8937
        - name: lat
          in: path
          required: true
          schema: { type: number, format: float }
          example: 52.3733
        - name: radius
          in: query
          required: false
          schema: { type: integer, minimum: 100, maximum: 50000, default: 15000 }
        - name: n
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 25, default: 10 }
      responses:
        "200": { description: Brugopeningen en veiligheidsberichten }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/punt/{lon}/{lat}/gebieden:
    get:
      summary: Eigen dienst · Punt-gebieden — bestuurlijke gebieden op een punt
      description: |
        Gemeente, provincie en land met officiële codes en liggt-in-relaties
        (PDOK), plus vervolgloning naar CBS-regio-diensten.
      parameters:
        - name: lon
          in: path
          required: true
          schema: { type: number, format: float }
          example: 4.8937
        - name: lat
          in: path
          required: true
          schema: { type: number, format: float }
          example: 52.3733
      responses:
        "200": { description: Gebieden met codes en relaties }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/punt/{lon}/{lat}/verkeer:
    get:
      summary: Eigen dienst · Punt-verkeer — tijdelijke maatregelen bij een punt
      description: |
        Actuele afsluitingen en tijdelijke maximumsnelheden (NDW DATEX II) met
        geldigheidsvenster, oorzaak, rijstroken en limiet; afstand hemelsbreed
        tot de weglijn.
      parameters:
        - name: lon
          in: path
          required: true
          schema: { type: number, format: float }
          example: 4.8937
        - name: lat
          in: path
          required: true
          schema: { type: number, format: float }
          example: 52.3733
        - name: radius
          in: query
          required: false
          schema: { type: integer, minimum: 100, maximum: 50000, default: 10000 }
        - name: n
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 25, default: 10 }
      responses:
        "200": { description: Afsluitingen en maximale snelheden }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/punt/{lon}/{lat}/bgt:
    get:
      summary: Eigen dienst · Punt-BGT — grootschalige topografie op een punt
      description: |
        Acht BGT-collecties parallel rond een coördinaat: gebouwen (met
        BAG-pand-koppeling), wegdelen, waterdelen, vegetatie, functionele
        gebieden, straatnaamlabels, straatmeubilair, overbruggingsdelen.
        Kenmerken zonder geometrie.
      parameters:
        - name: lon
          in: path
          required: true
          schema: { type: number, format: float }
          example: 4.8937
        - name: lat
          in: path
          required: true
          schema: { type: number, format: float }
          example: 52.3733
        - name: radius
          in: query
          required: false
          schema: { type: integer, minimum: 5, maximum: 500, default: 50 }
        - name: n
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 25, default: 5 }
      responses:
        "200": { description: Kenmerken per BGT-collectie }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/punt/{lon}/{lat}/milieuzone:
    get:
      summary: Eigen dienst · Punt-milieuzone — in-emissiezone-check
      description: |
        Punt-in-polygoon over alle nationale emissiezones (NDW DATEX II): per
        treffer zone-naam, gemeente, euro-normen en regeling-verwijzing;
        anders de dichtstbijzijnde zones met afstand.
      parameters:
        - name: lon
          in: path
          required: true
          schema: { type: number, format: float }
          example: 4.8937
        - name: lat
          in: path
          required: true
          schema: { type: number, format: float }
          example: 52.3733
        - name: n
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 10, default: 3 }
      responses:
        "200": { description: Zones waarin het punt ligt + dichtstbijzijnd }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/punt/{lon}/{lat}/voorzieningen:
    get:
      summary: Eigen dienst · Punt-voorzieningen — alles in de buurt
      description: |
        Dichtstbijzijnde laadpalen (NDW, realtime beschikbaarheid), deelfiets-
        stations (alle GBFS-systemen van Nederland) en actueel weer op één punt.
      parameters:
        - name: lon
          in: path
          required: true
          schema: { type: number, format: float }
          example: 4.8937
        - name: lat
          in: path
          required: true
          schema: { type: number, format: float }
          example: 52.3733
        - name: radius
          in: query
          required: false
          schema: { type: integer, minimum: 50, maximum: 5000, default: 750 }
        - name: n
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 25, default: 5 }
      responses:
        "200": { description: Laadpalen, deelfiets-stations en weer }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/adres/{postcode}/{huisnummer}/lucht:
    get:
      summary: Eigen dienst · Adres-luchtkwaliteit — dichtstbijzijnde meetpunt
      description: |
        Adres → coördinaat → dichtstbijzijnde Luchtmeetnet-stations (hemelsbrede
        afstand) met de nieuwste meting per stof. Stationcoördinaten uit het
        detail-endpoint (24-uurs cache).
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1012JS
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
        - name: n
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 10, default: 3 }
          description: Aantal dichtstbijzijnde stations
      responses:
        "200": { description: Stations met afstand en nieuwste metingen }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/diensten/backlog:
    get:
      summary: Eigen diensten · Machinale werklijst van kandidaat-producten
      description: |
        Kandidaat-eigen diensten met machinaal afgeleide status: 'direct-bouwbaar'
        zodra alle combinatie-bronnen live zijn, 'sleutel-nodig' zolang een bron
        wacht op een key (gekoppeld aan /v1/backlog). Bron voor nieuwe producten
        in deze lane (recept: docs/AGENT-API.md).
      parameters:
        - name: status
          in: query
          required: false
          schema: { type: string, enum: [direct-bouwbaar, sleutel-nodig, onderzoek, al-live] }
          example: direct-bouwbaar
        - name: domein
          in: query
          required: false
          schema: { type: string }
          example: geo
      responses:
        "200": { description: Werklijst met kandidaat-producten en statussen }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/adres/{postcode}/{huisnummer}:
    get:
      summary: Eigen dienst · Adres-alles — 12 bronnen in één call
      description: |
        Het vlaggenschip: alles over één adres. BAG, WOZ, monument, perceel,
        pand-id's, gebieden, kerncijfers, woningmarkt, milieuzone, lucht,
        verkeer en subsidies — parallel, compact.
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1015CC
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
      responses:
        "200": { description: Alles over dit adres (12 bronnen) }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/adres/{postcode}/{huisnummer}/context:
    get:
      summary: Eigen dienst · Adres-context — alles rond één adres in één call
      description: |
        Combineert BAG-adresidentiteit (wijk-/buurtcodes, coördinaten), CBS-kerncijfers
        van buurt én wijk, kadastrale percelen en bebouwing rond het punt, en
        rijksmonumenten op het adres. Broncalls gaan parallel; deelfouten staan als
        status 'onbeschikbaar' in bronnen[].
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1012JS
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
      responses:
        "200": { description: Adres-context (bron_type eigen-dienst) }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/pand/{postcode}/{huisnummer}/dossier:
    get:
      summary: Eigen dienst · Pand-dossier — gebouw, perceel, monument, buurt
      description: |
        BAG-pandidentificaties (via de kadastrale kaart), kadastraal perceel,
        rijksmonumentstatus, CBS-buurtprofiel en energielabel-toegang (open datasets;
        label per pand vereist RVO-key — roadmap).
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1012JS
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
      responses:
        "200": { description: Pand-dossier (bron_type eigen-dienst) }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/energie/prijzen:
    get:
      summary: Bron · CBS — Gemiddelde energietarieven voor consumenten
      description: |
        Nieuwste maandgemiddelden voor consumenten: aardgas (€/m³) en
        elektriciteit (€/kWh), all-in inclusief btw (variabel
        leveringstarief + ODE + energiebelasting), met componenten,
        vaste tarieven en peilmaand. StatLine 85592NED (CC BY 4.0).
        Rekenprijzen voor besparingen in euro's (o.a. Openverduurzamen).
      responses:
        "200": { description: Consumententarieven (bron-api) }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/openverduurzamen:
    get:
      summary: Eigen dienst · Openverduurzamen — status en fasering
      description: |
        Landing van de Openverduurzamen-datavalidatielaag: modules (validatielaag,
        voorblad live; 0-meting, rapportage en Woonwijzerwinkel-uitvoer in
        ontwikkeling), de bronnen die gevoed worden en het methodiek-endpoint.
        Pandvalidatie uit primaire bronnen; bestaande tenants blijven ongemoeid.
      responses:
        "200": { description: Status (bron_type eigen-dienst) }
  /v1/openverduurzamen/pand/{postcode}/{huisnummer}:
    get:
      summary: Eigen dienst · Openverduurzamen pand — gevalideerd pand-object
      description: |
        Postcode + huisnummer (optioneel ?toevoeging=) → één gevalideerd
        pand-object: adres (BAG), bouwjaar, oppervlakte, gebruiksdoelen,
        pandstatus (BAG API Bevragen), WOZ-waarde (WOZ-waardeloket),
        geregistreerd energielabel (EP-Online), kadastraal perceel (Kadaster)
        en CBS-buurtcontext — parallel, met bron en status per veld.
        null = onbekend bij de bron; deelfout = status onbeschikbaar in bronnen[].
      parameters:
        - name: postcode
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1012JS
        - name: huisnummer
          in: path
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
        - name: toevoeging
          in: query
          required: false
          schema: { type: string }
          example: a
      responses:
        "200": { description: Gevalideerd pand-object (bron_type eigen-dienst) }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/openverduurzamen/methodiek:
    get:
      summary: Eigen dienst · Openverduurzamen methodiek — velddefinities en beperkingen
      description: |
        Per veld: definitie, bronvelden en beperkingen; bronnen met licentie
        en attributie (CBS: CC BY 4.0); privacyafspraak (geen opslag van
        opvragingen of correcties).
      responses:
        "200": { description: Methodiek-registry }
  /v1/openverduurzamen/nulmeting:
    post:
      summary: Eigen dienst · Openverduurzamen 0-meting — EPA-bestand uitlezen
      description: |
        POST met de XML-inhoud van een .epa-bestand (NTA 8800, EPA-software-
        export) als body (Content-Type: application/xml, max 2 MiB). De laag
        leest huidige energieklasse, energie-index/EPC, adres en de
        energiemaatregelen mét doel-labels/-indexen uit het bestand; de
        labelsprong wordt uitsluitend uit die doelwaarden afgeleid (niet
        herberekend). Tolerante, naamruimte-agnostische parse — er is geen
        publiek .epa-schema; de respons vermeldt wat herkend is. Het bestand
        wordt in geheugen geparseerd en direct vergeten (geen opslag, geen
        logging van de inhoud; geen externe bronnen aangeroepen).
      requestBody:
        required: true
        content:
          application/xml:
            schema: { type: string }
      responses:
        "200": { description: 0-meting (huidige situatie, maatregelen, labelsprong) }
        "400": { $ref: "#/components/responses/Fout" }
        "422": { $ref: "#/components/responses/Fout" }
  /v1/openverduurzamen/rapport.pdf:
    post:
      summary: Eigen dienst · Openverduurzamen rapport als A4-PDF
      description: |
        Zelfde invoer als /v1/openverduurzamen/rapport (query postcode +
        huisnummer [+ toevoeging]; body .epa-XML). Antwoord is het blad als
        éénpagina A4-PDF (application/pdf; geen envelop — binair): kop met
        EP-online-chips (huidig amber → doel groen), signalen voor mogelijk
        niet-aangemelde maatregelen, drie scenario's met investering,
        besparing en financiering per maand, woningwaarde en CO2, plus de
        bronregel. Volledig stdlib gegenereerd — geen dependencies, geen
        headless browser op de box. Fouten blijven RFC 7807-JSON.
      parameters:
        - name: postcode
          in: query
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
        - name: huisnummer
          in: query
          required: true
          schema: { type: integer, minimum: 1 }
        - name: toevoeging
          in: query
          required: false
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/xml:
            schema: { type: string }
      responses:
        "200": { description: A4-PDF (application/pdf, inline) }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
        "422": { $ref: "#/components/responses/Fout" }
  /v1/openverduurzamen/rapport:
    post:
      summary: Eigen dienst · Openverduurzamen rapport — voorblad + 0-meting
      description: |
        Volledig verduurzamingsrapport in één call. Query: postcode +
        huisnummer (verplicht), toevoeging (optioneel); body: de XML van het
        .epa-bestand (application/xml, max 2 MiB). Combineert de
        datavalidatielaag (live pandgegevens uit BAG/WOZ/EP-Online/Kadaster/
        CBS, 24-uurs cache) met de 0-meting (uit het EPA-bestand) en rang-
        schikt de maatregelen op doel-label (beste eerst) — géén kosten- of
        besparingsindicaties (geen bron). Printklaar via de pagina
        (/innovatie/openverduurzamen, printstijl). Niets wordt opgeslagen.
      parameters:
        - name: postcode
          in: query
          required: true
          schema: { type: string, pattern: '^[0-9]{4}[A-Za-z]{2}$' }
          example: 1012JS
        - name: huisnummer
          in: query
          required: true
          schema: { type: integer, minimum: 1 }
          example: 1
        - name: toevoeging
          in: query
          required: false
          schema: { type: string }
          example: a
      requestBody:
        required: true
        content:
          application/xml:
            schema: { type: string }
      responses:
        "200": { description: Rapport (voorblad + nulmeting + adviesvolgorde) }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
        "422": { $ref: "#/components/responses/Fout" }
  /v1/regio/{code}/vergelijk:
    get:
      summary: Eigen dienst · Regio-vergelijking — kerncijfers naast elkaar
      description: |
        CBS-kerncijfers van twee regio's in één respons met absoluut en procentueel
        verschil per kenmerk. Codes: BU…/WK…/GM… (te mengen).
      parameters:
        - name: code
          in: path
          required: true
          schema: { type: string, pattern: '^(BU|WK|GM)[0-9A-Za-z]+$' }
          example: WK0363AE
        - name: met
          in: query
          required: true
          schema: { type: string, pattern: '^(BU|WK|GM)[0-9A-Za-z]+$' }
          example: WK0363AC
        - name: jaar
          in: query
          required: false
          schema: { type: integer, example: 2025 }
      responses:
        "200": { description: Vergelijking met verschillen (bron_type eigen-dienst) }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/wet/{bwb_id}/artikelen/{artikel}/relevant:
    get:
      summary: Eigen dienst · Wet-artikel-relevantie — artikel + weg naar jurisprudentie
      description: |
        Artikel-tekst per BWB-regeling met genormaliseerde citatievormen (bijv.
        'art. 1:1 BW') en directe vervolgstappen: officiële rechtspraak-zoeklink,
        open-data-feed en uitspraak-per-ECLI-endpoint. De open-data-feed ondersteunt
        géén tekstzoek op artikelnummer — vandaar deze koppeling.
      parameters:
        - name: bwb_id
          in: path
          required: true
          schema: { type: string, pattern: '^BWBR[0-9]{7}$' }
          example: BWBR0005181
        - name: artikel
          in: path
          required: true
          schema: { type: string }
          example: "2"
      responses:
        "200": { description: Artikelen + citatievormen + rechtspraaklinks (bron_type eigen-dienst) }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/afm/register:
    get:
      summary: Collectiebron · AFM-register — metadata, peildatum en hergebruiksvoorwaarden
      description: |
        Eerste collectiebron (register zonder open API): Identix.org importeert
        het officiële publieke XML-extract van het AFM-register financiële
        dienstverleners dagelijks en ontsluit het als curated API. Elke respons
        bevat peildatum, bron_url naar het officiële extract en de vereiste
        bronvermelding van de AFM (hergebruik toegestaan mits uitdrukkelijke
        bronvermelding — sitevoorwaarden afm.nl).
      responses:
        "200": { description: Manifest met peildatum, sha-256, tellingen en verversingsstatus (bron_type collectiebron) }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/afm/instellingen:
    get:
      summary: Collectiebron · AFM-register — instanties zoeken
      description: |
        Zoekt in 23.000+ geregistreerde financiële dienstverleners op statutaire-
        en handelsnamen, met filters op KvK-nummer, land, plaats en inkomende
        Europese paspoorting. Ondersteunt de enterprise-laag
        (waar/velden/sorteer/rijen/start).
      parameters:
        - name: q
          in: query
          required: false
          schema: { type: string }
          example: elevate finance
        - name: kvk_nummer
          in: query
          required: false
          schema: { type: string, pattern: '^[0-9]{8}$' }
          example: "94805172"
        - name: land
          in: query
          required: false
          schema: { type: string }
          example: Nederland
        - name: plaats
          in: query
          required: false
          schema: { type: string }
          example: Utrecht
        - name: ep
          in: query
          required: false
          schema: { type: string, enum: [ja, nee] }
          example: ja
        - name: rijen
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 500, default: 50 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200": { description: Instanties met bedrijfsgegevens en vergunningtellingen (bron_type collectiebron) }
        "400": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/afm/instellingen/{id}:
    get:
      summary: Collectiebron · AFM-register — volledig dossier per instelling
      description: |
        Volledig genormaliseerd dossier: bedrijfsgegevens, handelsnamen, adressen,
        inkomende Europese paspoorting en alle vergunningen met vergunde producten,
        diensten (adviseren, bemiddelen, ...) en beleidsbepalers.
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          example: 4385f1d1-ef65-ef11-bfe2-000d3a2183de
      responses:
        "200": { description: Dossier met vergunningen, producten en diensten (bron_type collectiebron) }
        "404": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/afm/vergunningen:
    get:
      summary: Collectiebron · AFM-register — vlakke vergunningenlijst
      description: |
        Alle 14.000+ vergunningen als vlakke rijen (vergunningnummer, instelling,
        data, status). Status is een afleiding: geldig (geen einddatum of
        einddatum op/na de peildatum) of beëindigd. Ondersteunt de enterprise-laag.
      parameters:
        - name: vergunningnummer
          in: query
          required: false
          schema: { type: string }
          example: "12050233"
        - name: instelling_id
          in: query
          required: false
          schema: { type: string }
          example: 4385f1d1-ef65-ef11-bfe2-000d3a2183de
        - name: status
          in: query
          required: false
          schema: { type: string, enum: [geldig, beëindigd] }
          example: geldig
        - name: rijen
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 500, default: 50 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200": { description: Vergunningenlijst met filters en paging (bron_type collectiebron) }
        "400": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/dnb/register:
    get:
      summary: Collectiebron · DNB Openbaar register — metadata, peildatum en hergebruiksvoorwaarden
      description: |
        Tweede collectiebron: DNB publiceert het Openbaar register zonder sleutelloze
        API, maar met een officiële complete CSV-export (elke werkdag 06:00 ververst).
        Identix.org importeert en ontsluit die als curated API. Elke respons
        bevat peildatum, bron_url en CC-BY-attributie (DNB-disclaimer: CC BY 4.0,
        met bron-, licentie- en bewerkingsvermelding).
      responses:
        "200": { description: Manifest met peildatum, sha-256, tellingen per deelregister en verversingsstatus (bron_type collectiebron) }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/dnb/instellingen:
    get:
      summary: Collectiebron · DNB Openbaar register — instellingen zoeken
      description: |
        Zoekt in 3.300+ geregistreerde financiële instellingen op statutaire- en
        handelsnaam, met filters op KvK-nummer, RSIN, LEI, deelregister, land en
        plaats. Ondersteunt de enterprise-laag (waar/velden/sorteer/rijen/start).
      parameters:
        - name: q
          in: query
          required: false
          schema: { type: string }
          example: ing bank
        - name: kvk_nummer
          in: query
          required: false
          schema: { type: string, pattern: '^[0-9]{8}$' }
          example: "73712590"
        - name: rsin
          in: query
          required: false
          schema: { type: string, pattern: '^[0-9]{9}$' }
          example: "859637177"
        - name: lei
          in: query
          required: false
          schema: { type: string }
          example: W22ILOSFF9600DE5R120
        - name: deelregister
          in: query
          required: false
          schema: { type: string }
          example: Pensioenfondsen
        - name: land
          in: query
          required: false
          schema: { type: string }
          example: Nederland
        - name: plaats
          in: query
          required: false
          schema: { type: string }
          example: Amsterdam
        - name: rijen
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 500, default: 50 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200": { description: Instellingen met identificaties (KvK/RSIN/LEI) en registratietellingen (bron_type collectiebron) }
        "400": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/dnb/instellingen/{relatienummer}:
    get:
      summary: Collectiebron · DNB Openbaar register — dossier per instelling
      description: |
        Volledig genormaliseerd dossier: identiteit, adressen, KvK/RSIN/LEI,
        deelregisters en alle registraties met type (Vergunning, Ontheffing,
        Goedkeuring...), wetsartikel, geldigheidsdatums, activiteiten en
        gerelateerde relaties.
      parameters:
        - name: relatienummer
          in: path
          required: true
          schema: { type: string }
          example: R182615
      responses:
        "200": { description: Dossier met alle registraties (bron_type collectiebron) }
        "404": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/dnb/registraties:
    get:
      summary: Collectiebron · DNB Openbaar register — vlakke registratielijst
      description: |
        Alle 46.000+ registraties als vlakke rijen over 15 deelregisters.
        Status is een afleiding: geldig (geen einddatum of einddatum op/na de
        peildatum) of beëindigd. Ondersteunt de enterprise-laag.
      parameters:
        - name: deelregister
          in: query
          required: false
          schema: { type: string }
          example: Banken
        - name: status
          in: query
          required: false
          schema: { type: string, enum: [geldig, beëindigd] }
          example: geldig
        - name: type
          in: query
          required: false
          schema: { type: string }
          example: Vergunning
        - name: q
          in: query
          required: false
          schema: { type: string }
          example: lanschot
        - name: rijen
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 500, default: 50 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200": { description: Registratielijst met filters en paging (bron_type collectiebron) }
        "400": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/anbi/register:
    get:
      summary: Collectiebron · ANBI-register — metadata, peildatum (uit het bestand) en hergebruik
      description: |
        Derde collectiebron: het ANBI-register van de Belastingdienst als officiële
        open-data-export (CC0, zip met XML, wekelijks elke dinsdag). Elke respons
        bevat de peildatum uit het bestand zelf (header/aanmaakDatum), bron_url
        en bronvermelding.
      responses:
        "200": { description: Manifest met peildatum, bronversie, sha-256, tellingen en verversingsstatus (bron_type collectiebron) }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/anbi/instellingen:
    get:
      summary: Collectiebron · ANBI-register — instellingen zoeken
      description: |
        Zoekt in 54.000+ algemeen nut beogende instellingen op naam en alias, met
        filters op RSIN (koppelsleutel naar KvK/LEI), vestigingsplaats, status
        (geldig/beëindigd, afgeleid tegen de peildatum) en cultuur-ANBI.
        Ondersteunt de enterprise-laag (waar/velden/sorteer/rijen/start).
      parameters:
        - name: q
          in: query
          required: false
          schema: { type: string }
          example: rozenkruis
        - name: rsin
          in: query
          required: false
          schema: { type: string, pattern: '^[0-9]{9}$' }
          example: "001000652"
        - name: plaats
          in: query
          required: false
          schema: { type: string }
          example: Haarlem
        - name: status
          in: query
          required: false
          schema: { type: string, enum: [geldig, beëindigd] }
          example: geldig
        - name: cultuur
          in: query
          required: false
          schema: { type: string, enum: [ja, nee] }
          example: ja
        - name: rijen
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 500, default: 50 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200": { description: Instellingen met RSIN, namen, plaats en status (bron_type collectiebron) }
        "400": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/anbi/instellingen/{id}:
    get:
      summary: Collectiebron · ANBI-register — volledige beschikking per instelling
      description: |
        Volledige genormaliseerde beschikking: naam, alias, RSIN, dossiernummer,
        vestigingsplaats, website, geldigheidsdatums (algemeen én cultuur) en
        de afgeleide status. Voor de vijf wettelijke ANBI's is het id het
        dossiernummer.
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          example: "001000652"
      responses:
        "200": { description: Beschikking met alle velden (bron_type collectiebron) }
        "404": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/gleif/register:
    get:
      summary: Collectiebron · GLEIF Golden Copy (NL) — metadata, peildatum en hergebruik
      description: |
        Vierde collectiebron: de NL-slice van de GLEIF LEI Golden Copy (officiële
        bulk-export, CC0, GLEIF publiceert 3x per dag). Elke respons bevat peildatum
        (uit de GLEIF-publicatienaam), bron_url en bronvermelding.
      responses:
        "200": { description: Manifest met peildatum, sha-256, tellingen en verversingsstatus (bron_type collectiebron) }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/gleif/entiteiten:
    get:
      summary: Collectiebron · GLEIF Golden Copy (NL) — entiteiten zoeken
      description: |
        Zoekt in 195.000+ Nederlandse LEI-entiteiten op naam, met filters op
        KvK-nummer, plaats en status (actief/inactief). Ondersteunt de
        enterprise-laag (waar/velden/sorteer/rijen/start).
      parameters:
        - name: q
          in: query
          required: false
          schema: { type: string }
          example: snap-on
        - name: kvk_nummer
          in: query
          required: false
          schema: { type: string, pattern: '^[0-9]{8}$' }
          example: "34153487"
        - name: plaats
          in: query
          required: false
          schema: { type: string }
          example: Helmond
        - name: status
          in: query
          required: false
          schema: { type: string, enum: [actief, inactief] }
          example: actief
        - name: rijen
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 500, default: 50 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200": { description: Entiteiten met LEI, naam, KvK-nummer en status (bron_type collectiebron) }
        "400": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/gleif/entiteiten/{lei}:
    get:
      summary: Collectiebron · GLEIF Golden Copy (NL) — volledig LEI-record
      parameters:
        - name: lei
          in: path
          required: true
          schema: { type: string, pattern: '^[A-Z0-9]{20}$' }
          example: 04VK4ASM6OJ180YRBJ15
      responses:
        "200": { description: Volledig record met datums, statussen en beherende LOU (bron_type collectiebron) }
        "404": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/gleif/kvk/{kvk_nummer}:
    get:
      summary: Collectiebron · GLEIF — de LEI↔KvK-brug voor één onderneming
      description: |
        Alle LEI-records (actief én historisch) die bij één KvK-nummer horen —
        de koppelingslaag tussen handelsregister en het wereldwijde LEI-systeem.
      parameters:
        - name: kvk_nummer
          in: path
          required: true
          schema: { type: string, pattern: '^[0-9]{8}$' }
          example: "34153487"
      responses:
        "200": { description: LEI-records bij dit KvK-nummer (bron_type collectiebron) }
        "400": { $ref: "#/components/responses/Fout" }
        "503": { $ref: "#/components/responses/Fout" }
  /v1/bronnen:
    get:
      summary: Catalogus van alle beschikbare API's
      responses:
        "200":
          description: Lijst met API's (endpoint, parameters, licentie, status) + roadmap
  /v1/bag/adressen:
    get:
      summary: BAG · Adressen — adres-zoekactie (PDOK Locatieserver)
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string, minLength: 2 }
          example: Dam 1, Amsterdam
        - name: rows
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 50, default: 8 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200":
          description: Gestandaardiseerde adresobjecten
          content:
            application/json:
              schema: { $ref: "#/components/schemas/AdresResponse" }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/bag/suggest:
    get:
      summary: BAG · Type-ahead-suggesties
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string, minLength: 2 }
          example: keizersgr
        - name: rows
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 25, default: 6 }
      responses:
        "200": { description: Suggesties {id, weergavenaam, type} }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/bag/lookup:
    get:
      summary: BAG · Object per Locatieserver-id
      parameters:
        - name: id
          in: query
          required: true
          schema: { type: string }
          example: adr-2a8dc1af055da20b8bcdc8e4dbda1eaa
      responses:
        "200": { description: Object (adres-objecten volledig genormaliseerd) }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/cbs/kerncijfers:
    get:
      summary: CBS · Kerncijfers wijken en buurten per regio
      parameters:
        - name: regio
          in: query
          required: true
          schema: { type: string, pattern: "^(BU|WK|GM)[0-9A-Z]+$" }
          example: WK0363AE
        - name: jaar
          in: query
          required: false
          schema: { type: integer, example: 2024 }
          description: Peiljaar; standaard de nieuwste beschikbare tabel.
      responses:
        "200":
          description: Gestandaardiseerde kerncijfers
          content:
            application/json:
              schema: { $ref: "#/components/schemas/KerncijfersResponse" }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/cbs/regios:
    get:
      summary: CBS · Alle regio's van één niveau binnen een gebied
      parameters:
        - name: binnen
          in: query
          required: true
          schema: { type: string, pattern: "^(BU|WK|GM)[0-9A-Z]+$" }
          example: GM0363
        - name: niveau
          in: query
          required: true
          schema: { type: string, enum: [buurt, wijk, gemeente] }
          example: wijk
      responses:
        "200": { description: Lijst regio's met codes }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/kadaster/percelen:
    get:
      summary: Kadaster · Kadastrale percelen bij een locatie
      parameters:
        - name: lon
          in: query
          required: true
          schema: { type: number, minimum: -180, maximum: 180 }
          example: 4.8930
        - name: lat
          in: query
          required: true
          schema: { type: number, minimum: -90, maximum: 90 }
          example: 52.3730
        - name: radius
          in: query
          required: false
          schema: { type: integer, minimum: 5, maximum: 2000, default: 50 }
          description: Zoekstraal in meters.
      responses:
        "200":
          description: Gestandaardiseerde percelen
          content:
            application/json:
              schema: { $ref: "#/components/schemas/PercelenResponse" }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/kadaster/percelen/{id}:
    get:
      summary: Kadaster · Eén perceel per kadastrale objectidentificatie
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { description: Perceel }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/kadaster/grenzen:
    get:
      summary: Kadaster · Kadastrale grenzen bij een locatie
      parameters:
        - { name: lon, in: query, required: true, schema: { type: number }, example: 4.8930 }
        - { name: lat, in: query, required: true, schema: { type: number }, example: 52.3730 }
        - { name: radius, in: query, required: false, schema: { type: integer, minimum: 5, maximum: 2000, default: 50 } }
      responses:
        "200": { description: "Grenzen: type_grens, kwaliteit, perceel_links_id, perceel_rechts_id, geometrie" }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/kadaster/bebouwing:
    get:
      summary: Kadaster · Bebouwing bij een locatie (met BAG-pandkoppeling)
      parameters:
        - { name: lon, in: query, required: true, schema: { type: number }, example: 4.8930 }
        - { name: lat, in: query, required: true, schema: { type: number }, example: 52.3730 }
        - { name: radius, in: query, required: false, schema: { type: integer, minimum: 5, maximum: 2000, default: 50 } }
      responses:
        "200": { description: "Bebouwing: bag_pand_id, status_bgt, geometrie" }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/kadaster/openbareruimtenamen:
    get:
      summary: Kadaster · Openbare ruimtenamen (straatnamen) bij een locatie
      parameters:
        - { name: lon, in: query, required: true, schema: { type: number }, example: 4.8930 }
        - { name: lat, in: query, required: true, schema: { type: number }, example: 52.3730 }
        - { name: radius, in: query, required: false, schema: { type: integer, minimum: 5, maximum: 2000, default: 50 } }
      responses:
        "200": { description: "Namen: naam, type, bag_openbare_ruimte_id, geometrie" }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/kadaster/nummeraanduidingreeksen:
    get:
      summary: Kadaster · Huisnummerreeksen bij een locatie
      parameters:
        - { name: lon, in: query, required: true, schema: { type: number }, example: 4.8930 }
        - { name: lat, in: query, required: true, schema: { type: number }, example: 52.3730 }
        - { name: radius, in: query, required: false, schema: { type: integer, minimum: 5, maximum: 2000, default: 50 } }
      responses:
        "200": { description: "Reeksen: label, vbo-ids, bebouwing_id, geometrie" }
        "400": { $ref: "#/components/responses/Fout" }
  /v1/luchtmeetnet/metingen:
    get:
      summary: Luchtmeetnet · Metingen per station, met optionele filters
      parameters:
        - name: station
          in: query
          required: true
          schema: { type: string, pattern: "^NL[0-9]+$" }
          example: NL49565
        - name: formule
          in: query
          required: false
          schema: { type: string }
          example: PM10
        - name: van
          in: query
          required: false
          schema: { type: string, format: date-time }
        - name: tot
          in: query
          required: false
          schema: { type: string, format: date-time }
      responses:
        "200":
          description: Gestandaardiseerde metingen
          content:
            application/json:
              schema: { $ref: "#/components/schemas/MetingenResponse" }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/luchtmeetnet/stations:
    get:
      summary: Luchtmeetnet · Stationlijst (optioneel gefilterd)
      parameters:
        - name: zoek
          in: query
          required: false
          schema: { type: string }
          example: amsterdam
      responses:
        "200": { description: Stations }
  /v1/catalogus/datasets:
    get:
      summary: Catalogus · Zoek in alle open datasets van Nederland (20.000+)
      parameters:
        - name: q
          in: query
          required: false
          schema: { type: string }
          example: energielabel
        - name: instantie
          in: query
          required: false
          schema: { type: string }
          example: gemeente-rotterdam
        - name: rows
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 100, default: 10 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200": { description: "Datasets: titel, instantie, licentie, resources (met api-vlag)" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/catalogus/datasets/{id}:
    get:
      summary: Catalogus · Eén dataset per slug of uuid
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { description: Datasetdetail }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/catalogus/instanties:
    get:
      summary: Catalogus · Alle publicerende instanties met dataset-aantallen
      responses:
        "200": { description: Instanties }
  /v1/rdw/voertuigen:
    get:
      summary: RDW · Voertuigen per kenteken of merk
      parameters:
        - name: kenteken
          in: query
          required: false
          schema: { type: string }
          example: XS005T
        - name: merk
          in: query
          required: false
          schema: { type: string }
          example: TESLA
        - name: rows
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 100, default: 10 }
      responses:
        "200": { description: "Genormaliseerde voertuiggegevens (ISO-datums, getallen als getallen)" }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/rce/monumenten:
    get:
      summary: RCE · Rijksmonumenten per nummer, adres of plaats
      parameters:
        - { name: rijksmonumentnummer, in: query, required: false, schema: { type: string }, example: "518313" }
        - { name: postcode, in: query, required: false, schema: { type: string }, example: 1012JS }
        - { name: straat, in: query, required: false, schema: { type: string }, example: Dam }
        - { name: woonplaatsnaam, in: query, required: false, schema: { type: string }, example: Amsterdam }
        - { name: page, in: query, required: false, schema: { type: integer, minimum: 1, default: 1 } }
      responses:
        "200": { description: "Monumenten met BAG-koppelingen (heeft_pand, heeft_verblijfsobject)" }
        "400": { $ref: "#/components/responses/Fout" }
        "502": { $ref: "#/components/responses/Fout" }
  /v1/datasets/{id}/query:
    get:
      summary: Universele query-API · filter, sorteer en pagineer door elke dataset
      description: |
        Bevraagt een dataset als een normale API. Eerste aanroep materialiseert de
        dataset (24-uursverversing); daarna filteren, sorteren en pagineren lokaal.
        Filters: kolom=waarde, kolom~deel, kolom!=waarde, kolom>=getal, kolom<=getal (EN).
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
        - name: waar
          in: query
          required: false
          schema: { type: array, items: { type: string } }
          example: postcode~9401
        - name: velden
          in: query
          required: false
          schema: { type: string }
          example: postcode,label
        - name: sorteer
          in: query
          required: false
          schema: { type: string }
        - name: richting
          in: query
          required: false
          schema: { type: string, enum: [asc, desc], default: asc }
        - name: rijen
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 500, default: 50 }
        - name: start
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
      responses:
        "200": { description: "Query-resultaat met materiaal-status en herkomst" }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/datasets/{id}/data:
    get:
      summary: Universele ontsluiting · lever de inhoud van elke dataset
      description: |
        Raadpleegt de catalogus, kiest de resource, haalt de data op en normaliseert:
        JSON direct, CSV als tabel (kolommen + rijen), ArcGIS als features.
        Niet-machine-leesbare resources (PDF/XLS/…) leveren een heldere verklaring.
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
        - name: resource
          in: query
          required: false
          schema: { type: integer, minimum: 0, default: 0 }
        - name: rijen
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 500, default: 50 }
      responses:
        "200": { description: Genormaliseerde dataset-inhoud (vorm: tabel|features|json|tekst|niet_machine_leesbaar) }
        "400": { $ref: "#/components/responses/Fout" }
        "404": { $ref: "#/components/responses/Fout" }
  /v1/health:
    get:
      summary: Gezondheidscheck
      responses:
        "200": { description: ok }
components:
  responses:
    Fout:
      description: RFC 7807-fout
      content:
        application/json:
          schema: { $ref: "#/components/schemas/Fout" }
  schemas:
    Fout:
      type: object
      properties:
        type: { type: string }
        title: { type: string }
        status: { type: integer }
        detail: { type: string }
    Bron:
      type: object
      properties:
        naam: { type: string, example: CBS StatLine }
        instantie: { type: string, example: Centraal Bureau voor de Statistiek }
        licentie: { type: string, example: CC BY 4.0 }
        attributie: { type: string, example: "CBS, Den Haag" }
        duur_ms: { type: number }
        uit_cache: { type: boolean }
        status: { type: string, enum: [ok, fout] }
    Adres:
      type: object
      properties:
        nummeraanduiding_id: { type: string, example: "0363200003761447" }
        straat: { type: string, example: Dam }
        huisnummer: { type: integer, example: 1 }
        huisletter: { type: string, nullable: true }
        huisnummertoevoeging: { type: string, nullable: true }
        postcode: { type: string, example: 1012JS }
        woonplaats: { type: string, example: Amsterdam }
        weergavenaam: { type: string }
        gemeente:
          type: object
          properties:
            code: { type: string, example: "0363" }
            naam: { type: string, example: Amsterdam }
        provincie:
          type: object
          properties:
            code: { type: string, example: PV27 }
            naam: { type: string, example: Noord-Holland }
        wijk:
          type: object
          properties:
            code: { type: string, example: WK0363AE }
            naam: { type: string, nullable: true, example: Burgwallen-Oude Zijde }
        buurt:
          type: object
          properties:
            code: { type: string, example: BU0363AE02 }
            naam: { type: string, nullable: true, example: Oude Kerk e.o. }
        percelen:
          type: array
          items:
            type: object
            properties:
              kadastrale_aanduiding: { type: string, example: ASD04-F-6417 }
        geometrie:
          type: object
          properties:
            centroide_wgs84:
              type: object
              nullable: true
              properties:
                lon: { type: number, example: 4.893 }
                lat: { type: number, example: 52.373 }
            centroide_rd:
              type: object
              nullable: true
              properties:
                lon: { type: number, example: 121347.914 }
                lat: { type: number, example: 487347.519 }
    Kerncijfer:
      type: object
      properties:
        waarde: { type: number, nullable: true, description: null = onbekend/afgeschermd bij de bron }
        eenheid: { type: string, example: personen }
    Perceel:
      type: object
      properties:
        kadastrale_aanduiding: { type: string, example: "Amsterdam F 6417" }
        kadastrale_aanduiding_code: { type: string, example: "ASD04-F-6417" }
        kadastrale_gemeente: { type: string, example: Amsterdam }
        sectie: { type: string, example: F }
        perceelnummer: { type: integer, example: 6417 }
        oppervlak_m2: { type: integer, example: 816 }
        soort_grootte: { type: string, example: Vastgesteld }
        status: { type: string, example: Geldig }
        geldig_vanaf: { type: string, format: date-time, nullable: true }
        identificatie: { type: string, nullable: true }
        geometrie_wgs84: { type: object, nullable: true, description: GeoJSON-geometrie }
    Meting:
      type: object
      properties:
        stof: { type: string, example: PM10 }
        waarde: { type: number, nullable: true }
        eenheid: { type: string, nullable: true, example: "µg/m³" }
        gemeten_op: { type: string, format: date-time, nullable: true }
    Envelop:
      type: object
      properties:
        api: { type: string, example: Identix.org }
        versie: { type: string }
        onderdeel: { type: string, example: bag.adressen }
        gegenereerd_op: { type: string, format: date-time }
        duur_ms: { type: number, nullable: true }
        bronnen:
          type: array
          items: { $ref: "#/components/schemas/Bron" }
    AdresResponse:
      allOf:
        - $ref: "#/components/schemas/Envelop"
        - type: object
          properties:
            data:
              type: object
              properties:
                zoekterm: { type: string }
                aantal: { type: integer }
                resultaten:
                  type: array
                  items: { $ref: "#/components/schemas/Adres" }
    KerncijfersResponse:
      allOf:
        - $ref: "#/components/schemas/Envelop"
        - type: object
          properties:
            data:
              type: object
              properties:
                regio:
                  type: object
                  properties:
                    code: { type: string, example: WK0363AE }
                    niveau: { type: string, enum: [buurt, wijk, gemeente] }
                    naam: { type: string, nullable: true }
                    indelingswijziging: { type: string, nullable: true }
                kerncijfers:
                  type: object
                  additionalProperties: { $ref: "#/components/schemas/Kerncijfer" }
    PercelenResponse:
      allOf:
        - $ref: "#/components/schemas/Envelop"
        - type: object
          properties:
            data:
              type: object
              properties:
                locatie:
                  type: object
                  properties:
                    lon: { type: number }
                    lat: { type: number }
                aantal: { type: integer }
                percelen:
                  type: array
                  items: { $ref: "#/components/schemas/Perceel" }
    MetingenResponse:
      allOf:
        - $ref: "#/components/schemas/Envelop"
        - type: object
          properties:
            data:
              type: object
              properties:
                station: { type: string }
                aantal: { type: integer }
                metingen:
                  type: array
                  items: { $ref: "#/components/schemas/Meting" }
