openapi: 3.0.3 info: title: 'gwr-datahub API Documentation' description: 'API for accessing Swiss building registry (GWR) data, electricity tariffs from grid operators (VNB), and related infrastructure information.' version: 1.0.0 servers: - url: 'https://gwr-datahub.test' tags: - name: Buildings description: '' - name: 'EVU Tariffs' description: '' - name: 'BDEW Profiles' description: '' - name: 'Reference Market Prices' description: '' - name: 'Reference Market Price Predictions' description: '' - name: 'Transformer Stations' description: '' - name: 'Educational Institutions' description: '' - name: 'Municipal Properties' description: '' - name: 'Water Supply Buildings' description: '' - name: Endpoints description: '' - name: 'Electricity Production Plants' description: '' - name: 'Municipality Enrichment' description: '' - name: 'PV Multi-Roof Configuration' description: '' components: securitySchemes: default: type: http scheme: bearer description: 'You can retrieve your API token by logging into your account and navigating to Settings → API Tokens. Use Laravel Sanctum Bearer tokens for authentication.' security: - default: [] paths: /api/buildings: get: summary: 'List buildings by municipality (BFS)' operationId: listBuildingsByMunicipalityBFS description: "Returns a paginated list of GWR buildings for a given municipality (BFS number).\nCode label resolution is disabled by default for performance; enable with resolve_codes=1." parameters: - in: query name: municipality description: 'integer BFS municipality number.' example: '261' required: true schema: type: string description: 'integer BFS municipality number.' example: '261' - in: query name: per_page description: 'Number of items per page. Min: 1, Max: 1000. Default: 200.' example: 200 required: false schema: type: integer description: 'Number of items per page. Min: 1, Max: 1000. Default: 200.' example: 200 - in: query name: lang description: 'Language for code labels when resolve_codes=1. Options: de, fr, it. Default: de.' example: de required: false schema: type: string description: 'Language for code labels when resolve_codes=1. Options: de, fr, it. Default: de.' example: de - in: query name: resolve_codes description: 'Whether to resolve code labels. Default: 0.' example: true required: false schema: type: boolean description: 'Whether to resolve code labels. Default: 0.' example: true responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - Buildings requestBody: required: true content: application/json: schema: type: object properties: municipality: type: number description: '' example: 4326.41688 per_page: type: integer description: 'Must be at least 1. Must not be greater than 1000.' example: 17 nullable: true lang: type: string description: '' example: fr enum: - de - fr - it nullable: true resolve_codes: type: boolean description: '' example: false nullable: true required: - municipality /api/buildings/map-data: get: summary: 'Get lightweight map data for buildings by municipality' operationId: getLightweightMapDataForBuildingsByMunicipality description: "Returns minimal building data optimized for map visualizations.\nOnly includes buildings with valid coordinates (latitude/longitude)." parameters: - in: query name: municipality description: 'integer BFS municipality number.' example: '261' required: true schema: type: string description: 'integer BFS municipality number.' example: '261' - in: query name: per_page description: 'Number of items per page. Min: 1, Max: 1000. Default: 200.' example: 200 required: false schema: type: integer description: 'Number of items per page. Min: 1, Max: 1000. Default: 200.' example: 200 - in: query name: page description: 'Page number. Min: 1. Default: 1.' example: 1 required: false schema: type: integer description: 'Page number. Min: 1. Default: 1.' example: 1 responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - Buildings requestBody: required: true content: application/json: schema: type: object properties: municipality: type: number description: '' example: 4326.41688 per_page: type: integer description: 'Must be at least 1. Must not be greater than 1000.' example: 17 nullable: true page: type: integer description: 'Must be at least 1.' example: 35 nullable: true required: - municipality '/api/buildings/{egid}': get: summary: 'Get building information by EGID' operationId: getBuildingInformationByEGID description: "Returns detailed information about a building from the GWR (Gebäude- und Wohnungsregister) database.\nAll code fields are automatically resolved to their human-readable labels in the specified language.\n\nIf address or solar potential data is missing, it will be automatically synchronized before returning the response." parameters: - in: query name: lang description: 'The language for code labels. Options: `de` (German), `fr` (French), `it` (Italian). Default: `de`.' example: de required: false schema: type: string description: 'The language for code labels. Options: `de` (German), `fr` (French), `it` (Italian). Default: `de`.' example: de - in: query name: sync description: 'Whether to sync missing address/solar data from external APIs (OSB, GeoAdmin). Default: `0` (disabled). Set to `1` to enable on-demand sync. When disabled, returns only locally stored data.' example: false required: false schema: type: boolean description: 'Whether to sync missing address/solar data from external APIs (OSB, GeoAdmin). Default: `0` (disabled). Set to `1` to enable on-demand sync. When disabled, returns only locally stored data.' example: false responses: 200: description: '' content: application/json: schema: type: object example: egid: '1234567890' gdekt: ZH ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' gbez: Wohnhaus gkode: '01' gkode_label: Wohngebäude gstat: '01' gstat_label: Bestehend gkat: '01' gkat_label: Einfamilienhaus gbauj: 1990 garea: 150.5 gvol: 450.0 address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' properties: egid: type: string example: '1234567890' gdekt: type: string example: ZH ggdenr: type: string example: '261' ggdename: type: string example: Zürich egrid: type: string example: '2680000.0,1240000.0' gbez: type: string example: Wohnhaus gkode: type: string example: '01' gkode_label: type: string example: Wohngebäude gstat: type: string example: '01' gstat_label: type: string example: Bestehend gkat: type: string example: '01' gkat_label: type: string example: Einfamilienhaus gbauj: type: integer example: 1990 garea: type: number example: 150.5 gvol: type: number example: 450.0 address: type: object properties: street: type: string example: 'Hauptstrasse 45' postal_code: type: string example: '6260' city: type: string example: Reiden solar_roofs: type: array example: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: high geometry: type: object properties: rings: type: array example: - - - 2640325.75 - 1232914.625 items: type: array solar_facades: type: array example: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: medium geometry: type: object properties: rings: type: array example: - - - 2640325.75 - 1232914.625 items: type: array created_at: type: string example: '2025-01-01T00:00:00+00:00' updated_at: type: string example: '2025-01-01T00:00:00+00:00' 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: '' content: application/json: schema: type: object example: message: 'Building not found' properties: message: type: string example: 'Building not found' tags: - Buildings parameters: - in: path name: egid description: 'string The building EGID (Eidgenössische Gebäudeidentifikator).' example: '1234567890' required: true schema: type: string /api/evu-tariffs/operators: get: summary: 'List all grid operators' operationId: listAllGridOperators description: "Returns a paginated list of all active grid operators (Verteilnetzbetreiber) with their tariff URL status\nand information about the latest successful tariff submission." parameters: - in: query name: per_page description: 'Number of items per page. Min: 1, Max: 100. Default: 50.' example: 50 required: false schema: type: integer description: 'Number of items per page. Min: 1, Max: 100. Default: 50.' example: 50 - in: query name: status description: 'Filter by tariff URL status. Options: pending, found, not_found, manual, invalid.' example: found required: false schema: type: string description: 'Filter by tariff URL status. Options: pending, found, not_found, manual, invalid.' example: found - in: query name: search description: 'Search by operator name or CH UID.' example: EKZ required: false schema: type: string description: 'Search by operator name or CH UID.' example: EKZ responses: 200: description: '' content: application/json: schema: type: object example: data: - ch_uid: CHE-108.954.688 name: 'Elektrizitätswerke des Kantons Zürich (EKZ)' website_url: www.ekz.ch tariff_url: 'https://ekz.ch/api/tariffs.json' tariff_url_status: found tariff_url_verified_at: '2026-01-15T10:00:00+00:00' is_active: true latest_submission: fetched_at: '2026-01-15T10:00:00+00:00' tariff_year: 2026 tariff_count: 12 elcom_synced_at: '2026-01-01T00:00:00+00:00' links: first: 'https://example.com/api/evu-tariffs/operators?page=1' last: 'https://example.com/api/evu-tariffs/operators?page=10' prev: null next: 'https://example.com/api/evu-tariffs/operators?page=2' meta: current_page: 1 from: 1 last_page: 10 per_page: 50 to: 50 total: 500 properties: data: type: array example: - ch_uid: CHE-108.954.688 name: 'Elektrizitätswerke des Kantons Zürich (EKZ)' website_url: www.ekz.ch tariff_url: 'https://ekz.ch/api/tariffs.json' tariff_url_status: found tariff_url_verified_at: '2026-01-15T10:00:00+00:00' is_active: true latest_submission: fetched_at: '2026-01-15T10:00:00+00:00' tariff_year: 2026 tariff_count: 12 elcom_synced_at: '2026-01-01T00:00:00+00:00' items: type: object properties: ch_uid: type: string example: CHE-108.954.688 name: type: string example: 'Elektrizitätswerke des Kantons Zürich (EKZ)' website_url: type: string example: www.ekz.ch tariff_url: type: string example: 'https://ekz.ch/api/tariffs.json' tariff_url_status: type: string example: found tariff_url_verified_at: type: string example: '2026-01-15T10:00:00+00:00' is_active: type: boolean example: true latest_submission: type: object properties: fetched_at: type: string example: '2026-01-15T10:00:00+00:00' tariff_year: type: integer example: 2026 tariff_count: type: integer example: 12 elcom_synced_at: type: string example: '2026-01-01T00:00:00+00:00' links: type: object properties: first: type: string example: 'https://example.com/api/evu-tariffs/operators?page=1' last: type: string example: 'https://example.com/api/evu-tariffs/operators?page=10' prev: type: string example: null nullable: true next: type: string example: 'https://example.com/api/evu-tariffs/operators?page=2' meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 10 per_page: type: integer example: 50 to: type: integer example: 50 total: type: integer example: 500 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. tags: - 'EVU Tariffs' '/api/evu-tariffs/operators/{chUid}': get: summary: 'Get a single grid operator' operationId: getASingleGridOperator description: "Returns detailed information about a specific grid operator (Verteilnetzbetreiber) by its CH UID,\nincluding the latest submission status and tariff URL information." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: ch_uid: CHE-108.954.688 name: 'Elektrizitätswerke des Kantons Zürich (EKZ)' website_url: www.ekz.ch tariff_url: 'https://ekz.ch/api/tariffs.json' tariff_url_status: found tariff_url_verified_at: '2026-01-15T10:00:00+00:00' is_active: true latest_submission: fetched_at: '2026-01-15T10:00:00+00:00' tariff_year: 2026 tariff_count: 12 elcom_synced_at: '2026-01-01T00:00:00+00:00' properties: ch_uid: type: string example: CHE-108.954.688 name: type: string example: 'Elektrizitätswerke des Kantons Zürich (EKZ)' website_url: type: string example: www.ekz.ch tariff_url: type: string example: 'https://ekz.ch/api/tariffs.json' tariff_url_status: type: string example: found tariff_url_verified_at: type: string example: '2026-01-15T10:00:00+00:00' is_active: type: boolean example: true latest_submission: type: object properties: fetched_at: type: string example: '2026-01-15T10:00:00+00:00' tariff_year: type: integer example: 2026 tariff_count: type: integer example: 12 elcom_synced_at: type: string example: '2026-01-01T00:00:00+00:00' 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: '' content: application/json: schema: type: object example: error: 'Grid operator not found' code: operator_not_found properties: error: type: string example: 'Grid operator not found' code: type: string example: operator_not_found tags: - 'EVU Tariffs' parameters: - in: path name: chUid description: 'string The CH UID (Unternehmens-Identifikationsnummer) of the grid operator.' example: CHE-108.954.688 required: true schema: type: string '/api/evu-tariffs/operators/{chUid}/tariffs': get: summary: 'Get tariffs for a grid operator' operationId: getTariffsForAGridOperator description: "Returns the cached tariffs for a specific grid operator in the standard format\naccording to StromVV Art. 7b. The response includes all tariff types:\n- `electricity`: Elektrizitätstarif (energy costs)\n- `grid`: Netznutzungstarif (grid usage fees)\n- `metering`: Messtarif (metering costs)\n- `regional_fees`: Abgaben an Gemeinwesen (taxes and levies)\n\nTariff forms can be:\n- `constant`: Single price (Einheitstarif)\n- `multilevel`: Time-of-use pricing with HT/NT (Mehrstufentarif)\n- `dynamic`: Real-time pricing (Dynamischer Tarif) - use the dynamic endpoint for current prices" parameters: - in: query name: year description: 'Filter by tariff year. Default: current year.' example: 2026 required: false schema: type: integer description: 'Filter by tariff year. Default: current year.' example: 2026 responses: 200: description: '' content: application/json: schema: type: object example: dsoName: 'Elektrizitätswerke des Kantons Zürich (EKZ)' dsoNumber: 10895468800 tariffs: - customerVoltageLevel: 7 tariffName: 'Haushalt Standard' tariffType: electricity tariffForm: multilevel startDate: '2026-01-01' endDate: '2026-12-31' comment: null customerType: household prices: multilevel: levels: - name: HT price: 0.22 unit: CHF/kWh - name: NT price: 0.18 unit: CHF/kWh - customerVoltageLevel: 7 tariffName: 'Netznutzung Haushalt' tariffType: grid tariffForm: constant startDate: '2026-01-01' endDate: '2026-12-31' comment: null customerType: household prices: constant: price: 0.08 unit: CHF/kWh _meta: ch_uid: CHE-108.954.688 fetched_at: '2026-01-15T10:00:00+00:00' tariff_year: 2026 source_url: 'https://ekz.ch/api/tariffs.json' properties: dsoName: type: string example: 'Elektrizitätswerke des Kantons Zürich (EKZ)' dsoNumber: type: integer example: 10895468800 tariffs: type: array example: - customerVoltageLevel: 7 tariffName: 'Haushalt Standard' tariffType: electricity tariffForm: multilevel startDate: '2026-01-01' endDate: '2026-12-31' comment: null customerType: household prices: multilevel: levels: - name: HT price: 0.22 unit: CHF/kWh - name: NT price: 0.18 unit: CHF/kWh - customerVoltageLevel: 7 tariffName: 'Netznutzung Haushalt' tariffType: grid tariffForm: constant startDate: '2026-01-01' endDate: '2026-12-31' comment: null customerType: household prices: constant: price: 0.08 unit: CHF/kWh items: type: object properties: customerVoltageLevel: type: integer example: 7 tariffName: type: string example: 'Haushalt Standard' tariffType: type: string example: electricity tariffForm: type: string example: multilevel startDate: type: string example: '2026-01-01' endDate: type: string example: '2026-12-31' comment: type: string example: null nullable: true customerType: type: string example: household prices: type: object properties: multilevel: type: object properties: levels: type: array example: - name: HT price: 0.22 unit: CHF/kWh - name: NT price: 0.18 unit: CHF/kWh items: type: object properties: name: { type: string, example: HT } price: { type: number, example: 0.22 } unit: { type: string, example: CHF/kWh } _meta: type: object properties: ch_uid: type: string example: CHE-108.954.688 fetched_at: type: string example: '2026-01-15T10:00:00+00:00' tariff_year: type: integer example: 2026 source_url: type: string example: 'https://ekz.ch/api/tariffs.json' 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: '' content: application/json: schema: oneOf: - description: 'Operator not found' type: object example: error: 'Grid operator not found' code: operator_not_found properties: error: type: string example: 'Grid operator not found' code: type: string example: operator_not_found - description: 'No tariffs available' type: object example: error: 'No tariffs found for this operator' code: tariffs_not_found operator: CHE-108.954.688 year: 2026 properties: error: type: string example: 'No tariffs found for this operator' code: type: string example: tariffs_not_found operator: type: string example: CHE-108.954.688 year: type: integer example: 2026 tags: - 'EVU Tariffs' parameters: - in: path name: chUid description: 'string The CH UID of the grid operator.' example: CHE-108.954.688 required: true schema: type: string '/api/evu-tariffs/operators/{chUid}/dynamic': get: summary: 'Proxy dynamic tariff data' operationId: proxyDynamicTariffData description: "Proxies requests to the dynamic tariff URL of a grid operator to retrieve real-time pricing data.\nThis endpoint is only available for operators that offer dynamic tariffs (tariffForm: \"dynamic\").\n\nThe response format depends on the grid operator's implementation but typically includes\ncurrent and/or upcoming electricity prices with timestamps." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: timestamp: '2026-01-15T14:00:00+01:00' prices: - start: '2026-01-15T14:00:00+01:00' end: '2026-01-15T15:00:00+01:00' price: 0.185 unit: CHF/kWh - start: '2026-01-15T15:00:00+01:00' end: '2026-01-15T16:00:00+01:00' price: 0.215 unit: CHF/kWh properties: timestamp: type: string example: '2026-01-15T14:00:00+01:00' prices: type: array example: - start: '2026-01-15T14:00:00+01:00' end: '2026-01-15T15:00:00+01:00' price: 0.185 unit: CHF/kWh - start: '2026-01-15T15:00:00+01:00' end: '2026-01-15T16:00:00+01:00' price: 0.215 unit: CHF/kWh items: type: object properties: start: type: string example: '2026-01-15T14:00:00+01:00' end: type: string example: '2026-01-15T15:00:00+01:00' price: type: number example: 0.185 unit: type: string example: CHF/kWh 400: description: 'No dynamic tariff available' content: application/json: schema: type: object example: error: 'Operator does not have a dynamic tariff URL configured' code: proxy_error properties: error: type: string example: 'Operator does not have a dynamic tariff URL configured' code: type: string example: proxy_error 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: '' content: application/json: schema: type: object example: error: 'Grid operator not found' code: operator_not_found properties: error: type: string example: 'Grid operator not found' code: type: string example: operator_not_found 502: description: 'Upstream error' content: application/json: schema: type: object example: error: 'Failed to fetch dynamic tariff data from operator' code: proxy_error properties: error: type: string example: 'Failed to fetch dynamic tariff data from operator' code: type: string example: proxy_error tags: - 'EVU Tariffs' parameters: - in: path name: chUid description: 'string The CH UID of the grid operator.' example: CHE-108.954.688 required: true schema: type: string /api/bdew-profiles: get: summary: 'List all BDEW profile codes' operationId: listAllBDEWProfileCodes description: "Returns a list of all available BDEW standard load profile codes (e.g., H0, G0-G6, L0-L2).\nEach profile code represents a category of electricity consumption patterns." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: - code: H0 name: Household category: household description: 'Standard household profile' metadata: { } - code: G25 name: Commercial category: commercial description: 'Commercial profile' metadata: { } properties: data: type: array example: - code: H0 name: Household category: household description: 'Standard household profile' metadata: [] - code: G25 name: Commercial category: commercial description: 'Commercial profile' metadata: [] items: type: object properties: code: type: string example: H0 name: type: string example: Household category: type: string example: household description: type: string example: 'Standard household profile' metadata: type: object properties: { } 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. tags: - 'BDEW Profiles' '/api/bdew-profiles/{code}': get: summary: 'Get all variations for a BDEW profile code' operationId: getAllVariationsForABDEWProfileCode description: "Returns all 9 variations (3 seasons × 3 day types) for a specific BDEW profile code.\nEach variation contains 96 normalized values representing 15-minute intervals for a day." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"code\": \"H0\",\n \"name\": \"Household\",\n \"category\": \"household\",\n \"variations\": [\n {\n \"profile_code\": \"H0\",\n \"season\": \"winter\",\n \"day_type\": \"weekday\",\n \"values\": [0.0104, 0.0099, ...],\n \"is_dynamized\": true,\n \"description\": null,\n \"metadata\": {}\n },\n {\n \"profile_code\": \"H0\",\n \"season\": \"winter\",\n \"day_type\": \"saturday\",\n \"values\": [0.0104, 0.0099, ...],\n \"is_dynamized\": true,\n \"description\": null,\n \"metadata\": {}\n }\n ]\n}" 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: '' content: application/json: schema: type: object example: message: 'Profile code not found' properties: message: type: string example: 'Profile code not found' tags: - 'BDEW Profiles' parameters: - in: path name: code description: 'string The BDEW profile code (e.g., H0, G25, L25).' example: H0 required: true schema: type: string '/api/bdew-profiles/{code}/daily': get: summary: 'Get daily template for a BDEW profile code by date' operationId: getDailyTemplateForABDEWProfileCodeByDate description: "Returns the correct BDEW load profile template for a specific date.\nThe season (winter/summer/transition) and day type (weekday/saturday/sunday) are automatically determined from the date." parameters: - in: query name: date description: 'string The date in YYYY-MM-DD format.' example: '2025-01-15' required: true schema: type: string description: 'string The date in YYYY-MM-DD format.' example: '2025-01-15' responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"code\": \"H0\",\n \"date\": \"2025-01-15\",\n \"season\": \"winter\",\n \"day_type\": \"wednesday\",\n \"values\": [0.0104, 0.0099, ...],\n \"is_dynamized\": true,\n \"description\": null,\n \"metadata\": {}\n}" 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: '' content: application/json: schema: type: object example: message: 'Profile code not found' properties: message: type: string example: 'Profile code not found' 422: description: '' content: application/json: schema: type: object example: message: 'The given data was invalid.' errors: date: - 'The date field is required.' properties: message: type: string example: 'The given data was invalid.' errors: type: object properties: date: type: array example: - 'The date field is required.' items: type: string tags: - 'BDEW Profiles' requestBody: required: true content: application/json: schema: type: object properties: date: type: string description: 'Must be a valid date in the format Y-m-d.' example: '2026-02-10' required: - date parameters: - in: path name: code description: 'string The BDEW profile code (e.g., H0, G25, L25).' example: H0 required: true schema: type: string '/api/bdew-profiles/{code}/year': get: summary: 'Get yearly profile for a BDEW profile code' operationId: getYearlyProfileForABDEWProfileCode description: "Returns a complete year's worth of BDEW load profile data with all 365/366 days.\nEach day includes 96 quarter-hour values, with dynamization applied where applicable.\nHolidays are treated as Sundays, and Dec 24/31 use Saturday templates." parameters: - in: query name: year description: 'integer The year for the profile (2020-2035).' example: '2025' required: true schema: type: string description: 'integer The year for the profile (2020-2035).' example: '2025' responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"code\": \"H25\",\n \"year\": 2025,\n \"is_dynamized\": true,\n \"total_kwh\": 1000000.00,\n \"days\": [\n {\n \"date\": \"2025-01-01\",\n \"day_of_year\": 1,\n \"month\": 1,\n \"day_type\": \"sunday\",\n \"is_holiday\": true,\n \"holiday_name\": \"Neujahr\",\n \"dynamization_factor\": 1.2421,\n \"values\": [22.15, 20.81, 19.76, ...]\n }\n ],\n \"meta\": {\n \"total_days\": 365,\n \"is_leap_year\": false,\n \"generated_at\": \"2025-01-15T10:30:00Z\"\n }\n}" 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 404: description: '' content: application/json: schema: type: object example: message: 'Profile code not found' properties: message: type: string example: 'Profile code not found' 422: description: '' content: application/json: schema: type: object example: message: 'The given data was invalid.' errors: year: - 'The year field is required.' properties: message: type: string example: 'The given data was invalid.' errors: type: object properties: year: type: array example: - 'The year field is required.' items: type: string tags: - 'BDEW Profiles' requestBody: required: false content: application/json: schema: type: object properties: year: type: string description: '' example: null parameters: - in: path name: code description: 'string The BDEW profile code (e.g., H25, G25, L25).' example: H25 required: true schema: type: string '/api/bdew-profiles/{code}/years': get: summary: 'List available years for a profile code' operationId: listAvailableYearsForAProfileCode description: 'Returns the years that have pre-generated yearly profiles available.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: code: H25 available_years: - 2024 - 2025 - 2026 supported_range: min: 2020 max: 2035 properties: code: type: string example: H25 available_years: type: array example: - 2024 - 2025 - 2026 items: type: integer supported_range: type: object properties: min: type: integer example: 2020 max: type: integer example: 2035 404: description: '' content: application/json: schema: type: object example: message: 'Profile code not found' properties: message: type: string example: 'Profile code not found' tags: - 'BDEW Profiles' parameters: - in: path name: code description: 'string The BDEW profile code (e.g., H25, G25).' example: H25 required: true schema: type: string /api/reference-market-prices: get: summary: 'List reference market prices' operationId: listReferenceMarketPrices description: "Returns a paginated list of BFE reference market prices (Art. 15 EnFV).\nPrices are available for different technologies (photovoltaic, hydropower, biomass, wind, geothermal)\nand different period types (monthly, quarterly)." parameters: - in: query name: technology description: 'Filter by technology. Options: photovoltaic, hydropower, biomass, wind, geothermal.' example: photovoltaic required: false schema: type: string description: 'Filter by technology. Options: photovoltaic, hydropower, biomass, wind, geothermal.' example: photovoltaic - in: query name: period_type description: 'Filter by period type. Options: monthly, quarterly.' example: monthly required: false schema: type: string description: 'Filter by period type. Options: monthly, quarterly.' example: monthly - in: query name: year description: 'Filter by year.' example: 2025 required: false schema: type: integer description: 'Filter by year.' example: 2025 - in: query name: per_page description: 'Number of items per page. Min: 1, Max: 1000. Default: 100.' example: 100 required: false schema: type: integer description: 'Number of items per page. Min: 1, Max: 1000. Default: 100.' example: 100 responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 1 technology: photovoltaic technology_label: Photovoltaik period_type: monthly period_type_label: Monatlich year: 2025 period: 1 period_label: 'Januar 2025' price: 85.5 price_unit: CHF/MWh volume: 125000.0 volume_unit: MWh created_at: '2025-01-15T12:00:00+00:00' updated_at: '2025-01-15T12:00:00+00:00' links: first: ... last: ... prev: null next: ... meta: current_page: 1 from: 1 last_page: 5 per_page: 100 to: 100 total: 450 properties: data: type: array example: - id: 1 technology: photovoltaic technology_label: Photovoltaik period_type: monthly period_type_label: Monatlich year: 2025 period: 1 period_label: 'Januar 2025' price: 85.5 price_unit: CHF/MWh volume: 125000 volume_unit: MWh created_at: '2025-01-15T12:00:00+00:00' updated_at: '2025-01-15T12:00:00+00:00' items: type: object properties: id: type: integer example: 1 technology: type: string example: photovoltaic technology_label: type: string example: Photovoltaik period_type: type: string example: monthly period_type_label: type: string example: Monatlich year: type: integer example: 2025 period: type: integer example: 1 period_label: type: string example: 'Januar 2025' price: type: number example: 85.5 price_unit: type: string example: CHF/MWh volume: type: number example: 125000.0 volume_unit: type: string example: MWh created_at: type: string example: '2025-01-15T12:00:00+00:00' updated_at: type: string example: '2025-01-15T12:00:00+00:00' links: type: object properties: first: type: string example: ... last: type: string example: ... prev: type: string example: null nullable: true next: type: string example: ... meta: type: object properties: current_page: type: integer example: 1 from: type: integer example: 1 last_page: type: integer example: 5 per_page: type: integer example: 100 to: type: integer example: 100 total: type: integer example: 450 tags: - 'Reference Market Prices' requestBody: required: false content: application/json: schema: type: object properties: technology: type: string description: '' example: wind enum: - photovoltaic - hydropower - biomass - wind - geothermal nullable: true period_type: type: string description: '' example: monthly enum: - monthly - quarterly nullable: true year: type: integer description: 'Must be at least 2007. Must not be greater than 2100.' example: 1 nullable: true per_page: type: integer description: 'Must be at least 1. Must not be greater than 1000.' example: 22 nullable: true /api/reference-market-prices/latest: get: summary: 'Get latest prices per technology' operationId: getLatestPricesPerTechnology description: "Returns the most recent reference market price for each technology,\ngrouped by period type (monthly and quarterly)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: monthly: photovoltaic: id: 1 technology: photovoltaic technology_label: Photovoltaik period_type: monthly period_type_label: Monatlich year: 2025 period: 12 period_label: 'Dezember 2025' price: 85.5 price_unit: CHF/MWh volume: 125000.0 volume_unit: MWh created_at: '2025-01-15T12:00:00+00:00' updated_at: '2025-01-15T12:00:00+00:00' quarterly: photovoltaic: id: 2 technology: photovoltaic period_type: quarterly year: 2025 period: 4 period_label: 'Q4 2025' price: 82.3 properties: monthly: type: object properties: photovoltaic: type: object properties: id: type: integer example: 1 technology: type: string example: photovoltaic technology_label: type: string example: Photovoltaik period_type: type: string example: monthly period_type_label: type: string example: Monatlich year: type: integer example: 2025 period: type: integer example: 12 period_label: type: string example: 'Dezember 2025' price: type: number example: 85.5 price_unit: type: string example: CHF/MWh volume: type: number example: 125000.0 volume_unit: type: string example: MWh created_at: type: string example: '2025-01-15T12:00:00+00:00' updated_at: type: string example: '2025-01-15T12:00:00+00:00' quarterly: type: object properties: photovoltaic: type: object properties: id: type: integer example: 2 technology: type: string example: photovoltaic period_type: type: string example: quarterly year: type: integer example: 2025 period: type: integer example: 4 period_label: type: string example: 'Q4 2025' price: type: number example: 82.3 tags: - 'Reference Market Prices' /api/reference-market-prices/technologies: get: summary: 'List available technologies' operationId: listAvailableTechnologies description: 'Returns a list of all available technologies with their labels.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: technologies: - value: photovoltaic label: Photovoltaik - value: hydropower label: Wasserkraft - value: biomass label: Biomasse - value: wind label: Windenergie - value: geothermal label: Geothermie period_types: - value: monthly label: Monatlich - value: quarterly label: Quartal properties: technologies: type: array example: - value: photovoltaic label: Photovoltaik - value: hydropower label: Wasserkraft - value: biomass label: Biomasse - value: wind label: Windenergie - value: geothermal label: Geothermie items: type: object properties: value: type: string example: photovoltaic label: type: string example: Photovoltaik period_types: type: array example: - value: monthly label: Monatlich - value: quarterly label: Quartal items: type: object properties: value: type: string example: monthly label: type: string example: Monatlich tags: - 'Reference Market Prices' /api/reference-market-price-predictions: get: summary: 'List reference market price predictions' operationId: listReferenceMarketPricePredictions description: "Returns a paginated list of predicted reference market prices based on EPEX spot prices\nand ENTSO-E generation profiles (BFE Art. 15 EnFV methodology)." parameters: - in: query name: technology description: 'Filter by technology. Options: photovoltaic, hydropower, biomass, wind, geothermal.' example: photovoltaic required: false schema: type: string description: 'Filter by technology. Options: photovoltaic, hydropower, biomass, wind, geothermal.' example: photovoltaic - in: query name: period_type description: 'Filter by period type. Options: monthly, quarterly.' example: monthly required: false schema: type: string description: 'Filter by period type. Options: monthly, quarterly.' example: monthly - in: query name: year description: 'Filter by year.' example: 2026 required: false schema: type: integer description: 'Filter by year.' example: 2026 - in: query name: per_page description: 'Number of items per page. Min: 1, Max: 1000. Default: 100.' example: 100 required: false schema: type: integer description: 'Number of items per page. Min: 1, Max: 1000. Default: 100.' example: 100 responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 1 technology: photovoltaic technology_label: Photovoltaik period_type: monthly period_type_label: Monatlich year: 2026 period: 1 period_label: 'Januar 2026' price: 72.35 price_unit: EUR/MWh volume: 125000.0 volume_unit: MWh calculated_at: '2026-02-10T07:30:00+00:00' data_completeness: 98.5 is_partial: false created_at: '2026-01-15T12:00:00+00:00' updated_at: '2026-02-10T07:30:00+00:00' links: { } meta: { } properties: data: type: array example: - id: 1 technology: photovoltaic technology_label: Photovoltaik period_type: monthly period_type_label: Monatlich year: 2026 period: 1 period_label: 'Januar 2026' price: 72.35 price_unit: EUR/MWh volume: 125000 volume_unit: MWh calculated_at: '2026-02-10T07:30:00+00:00' data_completeness: 98.5 is_partial: false created_at: '2026-01-15T12:00:00+00:00' updated_at: '2026-02-10T07:30:00+00:00' items: type: object properties: id: type: integer example: 1 technology: type: string example: photovoltaic technology_label: type: string example: Photovoltaik period_type: type: string example: monthly period_type_label: type: string example: Monatlich year: type: integer example: 2026 period: type: integer example: 1 period_label: type: string example: 'Januar 2026' price: type: number example: 72.35 price_unit: type: string example: EUR/MWh volume: type: number example: 125000.0 volume_unit: type: string example: MWh calculated_at: type: string example: '2026-02-10T07:30:00+00:00' data_completeness: type: number example: 98.5 is_partial: type: boolean example: false created_at: type: string example: '2026-01-15T12:00:00+00:00' updated_at: type: string example: '2026-02-10T07:30:00+00:00' links: type: object properties: { } meta: type: object properties: { } tags: - 'Reference Market Price Predictions' requestBody: required: false content: application/json: schema: type: object properties: technology: type: string description: '' example: biomass enum: - photovoltaic - hydropower - biomass - wind - geothermal nullable: true period_type: type: string description: '' example: monthly enum: - monthly - quarterly nullable: true year: type: integer description: 'Must be at least 2020. Must not be greater than 2100.' example: 1 nullable: true per_page: type: integer description: 'Must be at least 1. Must not be greater than 1000.' example: 22 nullable: true /api/reference-market-price-predictions/latest: get: summary: 'Get latest predictions per technology' operationId: getLatestPredictionsPerTechnology description: "Returns the most recent prediction for each technology,\ngrouped by period type (monthly and quarterly)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: monthly: photovoltaic: { } quarterly: photovoltaic: { } properties: monthly: type: object properties: photovoltaic: type: object properties: { } quarterly: type: object properties: photovoltaic: type: object properties: { } tags: - 'Reference Market Price Predictions' /api/reference-market-price-predictions/current-month: get: summary: 'Get current month prediction' operationId: getCurrentMonthPrediction description: "Returns the prediction for the current (in-progress) month,\nincluding data completeness and partial status." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: year: 2026 month: 2 predictions: { } properties: year: type: integer example: 2026 month: type: integer example: 2 predictions: type: object properties: { } tags: - 'Reference Market Price Predictions' /api/reference-market-price-predictions/compare: get: summary: 'Compare predictions with official BFE values' operationId: comparePredictionsWithOfficialBFEValues description: "Returns a side-by-side comparison of predicted values against\nthe official BFE reference market prices where both are available." parameters: - in: query name: technology description: 'Filter by technology.' example: photovoltaic required: false schema: type: string description: 'Filter by technology.' example: photovoltaic - in: query name: year description: 'Filter by year.' example: 2026 required: false schema: type: integer description: 'Filter by year.' example: 2026 responses: 200: description: '' content: application/json: schema: type: object example: comparisons: - technology: photovoltaic period_type: monthly year: 2026 period: 1 period_label: 'Januar 2026' predicted_price: 72.35 official_price: 73.1 deviation: -0.75 deviation_percent: -1.03 data_completeness: 98.5 properties: comparisons: type: array example: - technology: photovoltaic period_type: monthly year: 2026 period: 1 period_label: 'Januar 2026' predicted_price: 72.35 official_price: 73.1 deviation: -0.75 deviation_percent: -1.03 data_completeness: 98.5 items: type: object properties: technology: type: string example: photovoltaic period_type: type: string example: monthly year: type: integer example: 2026 period: type: integer example: 1 period_label: type: string example: 'Januar 2026' predicted_price: type: number example: 72.35 official_price: type: number example: 73.1 deviation: type: number example: -0.75 deviation_percent: type: number example: -1.03 data_completeness: type: number example: 98.5 tags: - 'Reference Market Price Predictions' /api/transformer-stations: get: summary: 'List transformer stations' operationId: listTransformerStations description: "Returns a list of transformer stations (Trafostationen) with various filtering options.\nYou can filter by municipality (BFS number), postal code, status, or search within a radius using coordinates.\nCoordinates are taken directly from `gwr_buildings.GKODE` (Easting) and `gwr_buildings.GKODN` (Northing).\nThe `egrid` field contains the raw EGRID value from `gwr_buildings.EGRID`." parameters: - in: query name: municipality description: 'Filter by municipality BFS number (Gemeindenummer).' example: 261 required: false schema: type: integer description: 'Filter by municipality BFS number (Gemeindenummer).' example: 261 - in: query name: postal_code description: 'Filter by postal code (PLZ).' example: 8001 required: false schema: type: integer description: 'Filter by postal code (PLZ).' example: 8001 - in: query name: status description: 'Filter by status. Options: `candidate`, `confirmed`.' example: confirmed required: false schema: type: string description: 'Filter by status. Options: `candidate`, `confirmed`.' example: confirmed - in: query name: lat description: 'Latitude (WGS84) for radius search. Required together with `lng` and `radius`.' example: 47.3769 required: false schema: type: number description: 'Latitude (WGS84) for radius search. Required together with `lng` and `radius`.' example: 47.3769 - in: query name: lng description: 'Longitude (WGS84) for radius search. Required together with `lat` and `radius`.' example: 8.5417 required: false schema: type: number description: 'Longitude (WGS84) for radius search. Required together with `lat` and `radius`.' example: 8.5417 - in: query name: radius description: 'Search radius in meters (WGS84). Required together with `lat` and `lng`. Min: 1, Max: 50000.' example: 1000.0 required: false schema: type: number description: 'Search radius in meters (WGS84). Required together with `lat` and `lng`. Min: 1, Max: 50000.' example: 1000.0 - in: query name: east description: 'Easting (CH1903+) for radius search. Required together with `north` and `radius`.' example: 2680000.0 required: false schema: type: number description: 'Easting (CH1903+) for radius search. Required together with `north` and `radius`.' example: 2680000.0 - in: query name: north description: 'Northing (CH1903+) for radius search. Required together with `east` and `radius`.' example: 1240000.0 required: false schema: type: number description: 'Northing (CH1903+) for radius search. Required together with `east` and `radius`.' example: 1240000.0 responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 1 egid: '1234567890' status: confirmed building: egid: '1234567890' gbez: 'Trafo Station 1' ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 coordinates: east: 2680000.0 north: 1240000.0 coordinates_wgs84: lat: 47.3769 lng: 8.5417 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' properties: data: type: array example: - id: 1 egid: '1234567890' status: confirmed building: egid: '1234567890' gbez: 'Trafo Station 1' ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 coordinates: east: 2680000 north: 1240000 coordinates_wgs84: lat: 47.3769 lng: 8.5417 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' items: type: object properties: id: type: integer example: 1 egid: type: string example: '1234567890' status: type: string example: confirmed building: type: object properties: egid: type: string example: '1234567890' gbez: type: string example: 'Trafo Station 1' ggdenr: type: string example: '261' ggdename: type: string example: Zürich egrid: type: string example: '2680000.0,1240000.0' address: type: object properties: street: type: string example: 'Hauptstrasse 45' postal_code: type: string example: '6260' city: type: string example: Reiden solar_roofs: type: array example: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: high geometry: type: object properties: rings: type: array example: - [[2640325.75, 1232914.625]] items: type: array solar_facades: type: array example: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: medium geometry: type: object properties: rings: type: array example: - [[2640325.75, 1232914.625]] items: type: array coordinates: type: object properties: east: type: number example: 2680000.0 north: type: number example: 1240000.0 coordinates_wgs84: type: object properties: lat: type: number example: 47.3769 lng: type: number example: 8.5417 created_at: type: string example: '2025-01-01T00:00:00+00:00' updated_at: type: string example: '2025-01-01T00:00:00+00:00' 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. 422: description: '' content: application/json: schema: type: object example: message: 'The given data was invalid.' errors: lat: - 'The lat field is required when lng is present.' properties: message: type: string example: 'The given data was invalid.' errors: type: object properties: lat: type: array example: - 'The lat field is required when lng is present.' items: type: string tags: - 'Transformer Stations' requestBody: required: false content: application/json: schema: type: object properties: municipality: type: number description: '' example: 4326.41688 nullable: true postal_code: type: number description: '' example: 4326.41688 nullable: true lat: type: number description: 'This field is required when lng or radius is present. Must be between -90 and 90.' example: -90 nullable: true lng: type: number description: 'This field is required when lat or radius is present. Must be between -180 and 180.' example: -180 nullable: true east: type: number description: 'This field is required when north or radius is present.' example: 4326.41688 nullable: true north: type: number description: 'This field is required when east or radius is present.' example: 4326.41688 nullable: true radius: type: number description: 'Must be at least 1. Must not be greater than 50000.' example: 17 nullable: true status: type: string description: '' example: candidate enum: - candidate - confirmed nullable: true /api/educational-institutions: get: summary: 'List educational institutions' operationId: listEducationalInstitutions description: "Returns a list of educational institutions (Schulhäuser, Kindergärten, etc.) with various filtering options.\nYou can filter by municipality (BFS number), postal code, status, or search within a radius using coordinates.\nCoordinates are taken directly from `gwr_buildings.GKODE` (Easting) and `gwr_buildings.GKODN` (Northing)." parameters: - in: query name: municipality description: 'Filter by municipality BFS number (Gemeindenummer).' example: 261 required: false schema: type: integer description: 'Filter by municipality BFS number (Gemeindenummer).' example: 261 - in: query name: postal_code description: 'Filter by postal code (PLZ).' example: 8001 required: false schema: type: integer description: 'Filter by postal code (PLZ).' example: 8001 - in: query name: status description: 'Filter by status. Options: `candidate`, `confirmed`.' example: confirmed required: false schema: type: string description: 'Filter by status. Options: `candidate`, `confirmed`.' example: confirmed - in: query name: lat description: 'Latitude (WGS84) for radius search. Required together with `lng` and `radius`.' example: 47.3769 required: false schema: type: number description: 'Latitude (WGS84) for radius search. Required together with `lng` and `radius`.' example: 47.3769 - in: query name: lng description: 'Longitude (WGS84) for radius search. Required together with `lat` and `radius`.' example: 8.5417 required: false schema: type: number description: 'Longitude (WGS84) for radius search. Required together with `lat` and `radius`.' example: 8.5417 - in: query name: radius description: 'Search radius in meters (WGS84). Required together with `lat` and `lng`. Min: 1, Max: 50000.' example: 1000.0 required: false schema: type: number description: 'Search radius in meters (WGS84). Required together with `lat` and `lng`. Min: 1, Max: 50000.' example: 1000.0 - in: query name: east description: 'Easting (CH1903+) for radius search. Required together with `north` and `radius`.' example: 2680000.0 required: false schema: type: number description: 'Easting (CH1903+) for radius search. Required together with `north` and `radius`.' example: 2680000.0 - in: query name: north description: 'Northing (CH1903+) for radius search. Required together with `east` and `radius`.' example: 1240000.0 required: false schema: type: number description: 'Northing (CH1903+) for radius search. Required together with `east` and `radius`.' example: 1240000.0 responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 1 egid: '1234567890' status: confirmed building: egid: '1234567890' gbez: 'Schulhaus Muster' ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 coordinates: east: 2680000.0 north: 1240000.0 coordinates_wgs84: lat: 47.3769 lng: 8.5417 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' properties: data: type: array example: - id: 1 egid: '1234567890' status: confirmed building: egid: '1234567890' gbez: 'Schulhaus Muster' ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 coordinates: east: 2680000 north: 1240000 coordinates_wgs84: lat: 47.3769 lng: 8.5417 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' items: type: object properties: id: type: integer example: 1 egid: type: string example: '1234567890' status: type: string example: confirmed building: type: object properties: egid: type: string example: '1234567890' gbez: type: string example: 'Schulhaus Muster' ggdenr: type: string example: '261' ggdename: type: string example: Zürich egrid: type: string example: '2680000.0,1240000.0' address: type: object properties: street: type: string example: 'Hauptstrasse 45' postal_code: type: string example: '6260' city: type: string example: Reiden solar_roofs: type: array example: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: high geometry: type: object properties: rings: type: array example: - [[2640325.75, 1232914.625]] items: type: array solar_facades: type: array example: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: medium geometry: type: object properties: rings: type: array example: - [[2640325.75, 1232914.625]] items: type: array coordinates: type: object properties: east: type: number example: 2680000.0 north: type: number example: 1240000.0 coordinates_wgs84: type: object properties: lat: type: number example: 47.3769 lng: type: number example: 8.5417 created_at: type: string example: '2025-01-01T00:00:00+00:00' updated_at: type: string example: '2025-01-01T00:00:00+00:00' tags: - 'Educational Institutions' requestBody: required: false content: application/json: schema: type: object properties: municipality: type: number description: '' example: 4326.41688 nullable: true postal_code: type: number description: '' example: 4326.41688 nullable: true lat: type: number description: 'This field is required when lng or radius is present. Must be between -90 and 90.' example: -90 nullable: true lng: type: number description: 'This field is required when lat or radius is present. Must be between -180 and 180.' example: -180 nullable: true east: type: number description: 'This field is required when north or radius is present.' example: 4326.41688 nullable: true north: type: number description: 'This field is required when east or radius is present.' example: 4326.41688 nullable: true radius: type: number description: 'Must be at least 1. Must not be greater than 50000.' example: 17 nullable: true status: type: string description: '' example: candidate enum: - candidate - confirmed nullable: true /api/municipal-properties: get: summary: 'List municipal properties' operationId: listMunicipalProperties description: "Returns a list of municipal properties (Werkhöfe, Gemeindeverwaltung, Gemeindehaus, Feuerwehrmagazin, etc.) with various filtering options.\nYou can filter by municipality (BFS number), postal code, status, or search within a radius using coordinates.\nCoordinates are taken directly from `gwr_buildings.GKODE` (Easting) and `gwr_buildings.GKODN` (Northing)." parameters: - in: query name: municipality description: 'Filter by municipality BFS number (Gemeindenummer).' example: 261 required: false schema: type: integer description: 'Filter by municipality BFS number (Gemeindenummer).' example: 261 - in: query name: postal_code description: 'Filter by postal code (PLZ).' example: 8001 required: false schema: type: integer description: 'Filter by postal code (PLZ).' example: 8001 - in: query name: status description: 'Filter by status. Options: `candidate`, `confirmed`.' example: confirmed required: false schema: type: string description: 'Filter by status. Options: `candidate`, `confirmed`.' example: confirmed - in: query name: lat description: 'Latitude (WGS84) for radius search. Required together with `lng` and `radius`.' example: 47.3769 required: false schema: type: number description: 'Latitude (WGS84) for radius search. Required together with `lng` and `radius`.' example: 47.3769 - in: query name: lng description: 'Longitude (WGS84) for radius search. Required together with `lat` and `radius`.' example: 8.5417 required: false schema: type: number description: 'Longitude (WGS84) for radius search. Required together with `lat` and `radius`.' example: 8.5417 - in: query name: radius description: 'Search radius in meters (WGS84). Required together with `lat` and `lng`. Min: 1, Max: 50000.' example: 1000.0 required: false schema: type: number description: 'Search radius in meters (WGS84). Required together with `lat` and `lng`. Min: 1, Max: 50000.' example: 1000.0 - in: query name: east description: 'Easting (CH1903+) for radius search. Required together with `north` and `radius`.' example: 2680000.0 required: false schema: type: number description: 'Easting (CH1903+) for radius search. Required together with `north` and `radius`.' example: 2680000.0 - in: query name: north description: 'Northing (CH1903+) for radius search. Required together with `east` and `radius`.' example: 1240000.0 required: false schema: type: number description: 'Northing (CH1903+) for radius search. Required together with `east` and `radius`.' example: 1240000.0 responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 1 egid: '1234567890' status: confirmed building: egid: '1234567890' gbez: Gemeindehaus ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 coordinates: east: 2680000.0 north: 1240000.0 coordinates_wgs84: lat: 47.3769 lng: 8.5417 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' properties: data: type: array example: - id: 1 egid: '1234567890' status: confirmed building: egid: '1234567890' gbez: Gemeindehaus ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 coordinates: east: 2680000 north: 1240000 coordinates_wgs84: lat: 47.3769 lng: 8.5417 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' items: type: object properties: id: type: integer example: 1 egid: type: string example: '1234567890' status: type: string example: confirmed building: type: object properties: egid: type: string example: '1234567890' gbez: type: string example: Gemeindehaus ggdenr: type: string example: '261' ggdename: type: string example: Zürich egrid: type: string example: '2680000.0,1240000.0' address: type: object properties: street: type: string example: 'Hauptstrasse 45' postal_code: type: string example: '6260' city: type: string example: Reiden solar_roofs: type: array example: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: high geometry: type: object properties: rings: type: array example: - [[2640325.75, 1232914.625]] items: type: array solar_facades: type: array example: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: medium geometry: type: object properties: rings: type: array example: - [[2640325.75, 1232914.625]] items: type: array coordinates: type: object properties: east: type: number example: 2680000.0 north: type: number example: 1240000.0 coordinates_wgs84: type: object properties: lat: type: number example: 47.3769 lng: type: number example: 8.5417 created_at: type: string example: '2025-01-01T00:00:00+00:00' updated_at: type: string example: '2025-01-01T00:00:00+00:00' tags: - 'Municipal Properties' requestBody: required: false content: application/json: schema: type: object properties: municipality: type: number description: '' example: 4326.41688 nullable: true postal_code: type: number description: '' example: 4326.41688 nullable: true lat: type: number description: 'This field is required when lng or radius is present. Must be between -90 and 90.' example: -90 nullable: true lng: type: number description: 'This field is required when lat or radius is present. Must be between -180 and 180.' example: -180 nullable: true east: type: number description: 'This field is required when north or radius is present.' example: 4326.41688 nullable: true north: type: number description: 'This field is required when east or radius is present.' example: 4326.41688 nullable: true radius: type: number description: 'Must be at least 1. Must not be greater than 50000.' example: 17 nullable: true status: type: string description: '' example: confirmed enum: - candidate - confirmed nullable: true /api/water-supply-buildings: get: summary: 'List water supply buildings' operationId: listWaterSupplyBuildings description: "Returns a list of water supply buildings (Wasserversorgung) with various filtering options.\nYou can filter by municipality (BFS number), postal code, status, or search within a radius using coordinates.\nCoordinates are taken directly from `gwr_buildings.GKODE` (Easting) and `gwr_buildings.GKODN` (Northing)." parameters: - in: query name: municipality description: 'Filter by municipality BFS number (Gemeindenummer).' example: 261 required: false schema: type: integer description: 'Filter by municipality BFS number (Gemeindenummer).' example: 261 - in: query name: postal_code description: 'Filter by postal code (PLZ).' example: 8001 required: false schema: type: integer description: 'Filter by postal code (PLZ).' example: 8001 - in: query name: status description: 'Filter by status. Options: `candidate`, `confirmed`.' example: confirmed required: false schema: type: string description: 'Filter by status. Options: `candidate`, `confirmed`.' example: confirmed - in: query name: lat description: 'Latitude (WGS84) for radius search. Required together with `lng` and `radius`.' example: 47.3769 required: false schema: type: number description: 'Latitude (WGS84) for radius search. Required together with `lng` and `radius`.' example: 47.3769 - in: query name: lng description: 'Longitude (WGS84) for radius search. Required together with `lat` and `radius`.' example: 8.5417 required: false schema: type: number description: 'Longitude (WGS84) for radius search. Required together with `lat` and `radius`.' example: 8.5417 - in: query name: radius description: 'Search radius in meters (WGS84). Required together with `lat` and `lng`. Min: 1, Max: 50000.' example: 1000.0 required: false schema: type: number description: 'Search radius in meters (WGS84). Required together with `lat` and `lng`. Min: 1, Max: 50000.' example: 1000.0 - in: query name: east description: 'Easting (CH1903+) for radius search. Required together with `north` and `radius`.' example: 2680000.0 required: false schema: type: number description: 'Easting (CH1903+) for radius search. Required together with `north` and `radius`.' example: 2680000.0 - in: query name: north description: 'Northing (CH1903+) for radius search. Required together with `east` and `radius`.' example: 1240000.0 required: false schema: type: number description: 'Northing (CH1903+) for radius search. Required together with `east` and `radius`.' example: 1240000.0 responses: 200: description: '' content: application/json: schema: type: object example: data: - id: 1 egid: '1234567890' status: confirmed building: egid: '1234567890' gbez: Wasserwerk ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 coordinates: east: 2680000.0 north: 1240000.0 coordinates_wgs84: lat: 47.3769 lng: 8.5417 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' properties: data: type: array example: - id: 1 egid: '1234567890' status: confirmed building: egid: '1234567890' gbez: Wasserwerk ggdenr: '261' ggdename: Zürich egrid: '2680000.0,1240000.0' address: street: 'Hauptstrasse 45' postal_code: '6260' city: Reiden solar_roofs: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 solar_facades: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 coordinates: east: 2680000 north: 1240000 coordinates_wgs84: lat: 47.3769 lng: 8.5417 created_at: '2025-01-01T00:00:00+00:00' updated_at: '2025-01-01T00:00:00+00:00' items: type: object properties: id: type: integer example: 1 egid: type: string example: '1234567890' status: type: string example: confirmed building: type: object properties: egid: type: string example: '1234567890' gbez: type: string example: Wasserwerk ggdenr: type: string example: '261' ggdename: type: string example: Zürich egrid: type: string example: '2680000.0,1240000.0' address: type: object properties: street: type: string example: 'Hauptstrasse 45' postal_code: type: string example: '6260' city: type: string example: Reiden solar_roofs: type: array example: - attributes: building_id: '229760' suitability: high geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: high geometry: type: object properties: rings: type: array example: - [[2640325.75, 1232914.625]] items: type: array solar_facades: type: array example: - attributes: building_id: '229760' suitability: medium geometry: rings: - - - 2640325.75 - 1232914.625 items: type: object properties: attributes: type: object properties: building_id: type: string example: '229760' suitability: type: string example: medium geometry: type: object properties: rings: type: array example: - [[2640325.75, 1232914.625]] items: type: array coordinates: type: object properties: east: type: number example: 2680000.0 north: type: number example: 1240000.0 coordinates_wgs84: type: object properties: lat: type: number example: 47.3769 lng: type: number example: 8.5417 created_at: type: string example: '2025-01-01T00:00:00+00:00' updated_at: type: string example: '2025-01-01T00:00:00+00:00' tags: - 'Water Supply Buildings' requestBody: required: false content: application/json: schema: type: object properties: municipality: type: number description: '' example: 4326.41688 nullable: true postal_code: type: number description: '' example: 4326.41688 nullable: true lat: type: number description: 'This field is required when lng or radius is present. Must be between -90 and 90.' example: -90 nullable: true lng: type: number description: 'This field is required when lat or radius is present. Must be between -180 and 180.' example: -180 nullable: true east: type: number description: 'This field is required when north or radius is present.' example: 4326.41688 nullable: true north: type: number description: 'This field is required when east or radius is present.' example: 4326.41688 nullable: true radius: type: number description: 'Must be at least 1. Must not be greater than 50000.' example: 17 nullable: true status: type: string description: '' example: candidate enum: - candidate - confirmed nullable: true /api/user: get: summary: '' operationId: getApiUser description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - Endpoints /api/health: get: summary: '' operationId: getApiHealth description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: ok time: '2026-02-10T16:25:53+00:00' properties: status: type: string example: ok time: type: string example: '2026-02-10T16:25:53+00:00' tags: - Endpoints '/api/osb/{path}': get: summary: 'Proxy all requests to OSB API.' operationId: proxyAllRequestsToOSBAPI description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - Endpoints parameters: - in: path name: path description: 'Optional parameter.' required: true schema: type: string examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: '|{+-0p' '/api/osb-v2/{path}': get: summary: 'Proxy all requests to OSB API.' operationId: proxyAllRequestsToOSBAPI description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - Endpoints parameters: - in: path name: path description: 'Optional parameter.' required: true schema: type: string examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: '|{+-0p' '/api/buildings/{egid}/electricity-plants': get: summary: 'Get combined building and electricity production plants data' operationId: getCombinedBuildingAndElectricityProductionPlantsData description: '' parameters: - in: query name: plant_type description: 'Optional filter by plant type (photovoltaic, hydro, wind, biomass, etc.).' example: photovoltaic required: false schema: type: string description: 'Optional filter by plant type (photovoltaic, hydro, wind, biomass, etc.).' example: photovoltaic responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'Electricity Production Plants' parameters: - in: path name: egid description: 'Optional parameter. Building EGID.' required: true schema: type: string examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: '123456' /api/electricity-plants: get: summary: 'Get electricity production plants for a building by EGID' operationId: getElectricityProductionPlantsForABuildingByEGID description: '' parameters: - in: query name: egid description: 'Building EGID.' example: '123456' required: false schema: type: string description: 'Building EGID.' example: '123456' - in: query name: plant_type description: 'Optional filter by plant type (photovoltaic, hydro, wind, biomass, etc.).' example: photovoltaic required: false schema: type: string description: 'Optional filter by plant type (photovoltaic, hydro, wind, biomass, etc.).' example: photovoltaic responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'Electricity Production Plants' /api/electricity-plants/search: get: summary: 'Search electricity production plants by location' operationId: searchElectricityProductionPlantsByLocation description: '' parameters: - in: query name: municipality description: 'Municipality name.' example: Zürich required: false schema: type: string description: 'Municipality name.' example: Zürich - in: query name: post_code description: 'Postal code.' example: 8001 required: false schema: type: integer description: 'Postal code.' example: 8001 - in: query name: bfs_number description: 'BFS municipality number.' example: '261' required: false schema: type: string description: 'BFS municipality number.' example: '261' - in: query name: plant_type description: 'Optional filter by plant type (photovoltaic, hydro, wind, biomass, etc.).' example: photovoltaic required: false schema: type: string description: 'Optional filter by plant type (photovoltaic, hydro, wind, biomass, etc.).' example: photovoltaic responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'Electricity Production Plants' '/api/electricity-plants/{xtf_id}': get: summary: 'Get specific electricity production plant by XTF-ID' operationId: getSpecificElectricityProductionPlantByXTFID description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'Electricity Production Plants' parameters: - in: path name: xtf_id description: 'Optional parameter. XTF-ID of the plant.' required: true schema: type: string examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: ch.bfe.epa.123456 '/api/municipalities/{bfs_number}/electricity-plant-statistics': get: summary: 'Get electricity production plant statistics for a municipality' operationId: getElectricityProductionPlantStatisticsForAMunicipality description: '' parameters: - in: query name: plant_type description: 'Optional filter by plant type (photovoltaic, hydro, wind, biomass, etc.).' example: photovoltaic required: false schema: type: string description: 'Optional filter by plant type (photovoltaic, hydro, wind, biomass, etc.).' example: photovoltaic responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'Electricity Production Plants' parameters: - in: path name: bfs_number description: 'Optional parameter. BFS municipality number.' required: true schema: type: string examples: omitted: summary: 'When the value is omitted' value: '' present: summary: 'When the value is present' value: '261' '/api/municipalities/{bfs_number}/enrich': post: summary: 'Enrich all buildings in a municipality.' operationId: enrichAllBuildingsInAMunicipality description: "Triggers a background job that enriches building data including:\n- WGS84 coordinates (converted from CH1903+)\n- BDEW consumption profiles\n- Municipality names\n- Address data (via OSB API)" parameters: [] responses: { } tags: - 'Municipality Enrichment' requestBody: required: false content: application/json: schema: type: object properties: force: type: boolean description: 'Force re-enrichment even if already enriched. Default: false.' example: false parameters: - in: path name: bfs_number description: 'Municipality BFS number.' example: 261 required: true schema: type: integer '/api/municipalities/{bfs_number}/enrichment-status/{batch_id}': get: summary: 'Get the status of a municipality enrichment batch.' operationId: getTheStatusOfAMunicipalityEnrichmentBatch description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'Municipality Enrichment' parameters: - in: path name: bfs_number description: 'Municipality BFS number.' example: 261 required: true schema: type: integer - in: path name: batch_id description: 'Batch ID from enrich response.' example: 9d4f8a3c-1b2e-4f5a-8c3d-9a7b6e4f2c1d required: true schema: type: string '/api/buildings/{egid}/pv-roofs': get: summary: 'List available PV roof and facade surfaces for a building' operationId: listAvailablePVRoofAndFacadeSurfacesForABuilding description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'PV Multi-Roof Configuration' parameters: - in: path name: egid description: 'Building EGID.' example: '123456' required: true schema: type: string '/api/buildings/{egid}/pv-multi-roof-configurations': get: summary: 'List all PV multi-roof configurations for a building' operationId: listAllPVMultiRoofConfigurationsForABuilding description: '' parameters: - in: query name: status description: 'Filter by status (draft, calculating, completed, failed)' example: architecto required: false schema: type: string description: 'Filter by status (draft, calculating, completed, failed)' example: architecto - in: query name: per_page description: 'Number of items per page.' example: 20 required: false schema: type: integer description: 'Number of items per page.' example: 20 responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'PV Multi-Roof Configuration' post: summary: 'Create or update a PV multi-roof configuration' operationId: createOrUpdateAPVMultiRoofConfiguration description: '' parameters: [] responses: { } tags: - 'PV Multi-Roof Configuration' requestBody: required: true content: application/json: schema: type: object properties: id: type: integer description: 'Configuration ID (for updates).' example: 1 nullable: true name: type: string description: 'Configuration name.' example: 'Main PV System' nullable: true description: type: string description: 'Configuration description' example: 'Eius et animi quos velit et.' nullable: true status: type: string description: 'Status (draft, calculating, completed, failed).' example: draft nullable: true surfaces: type: array description: 'Array of surface configurations' example: - architecto items: type: string required: - surfaces parameters: - in: path name: egid description: 'Building EGID.' example: '123456' required: true schema: type: string '/api/buildings/{egid}/pv-multi-roof-configurations/{configId}': get: summary: 'Get a specific PV multi-roof configuration' operationId: getASpecificPVMultiRoofConfiguration description: '' parameters: - in: query name: lang description: 'Language code (de, fr, it).' example: de required: false schema: type: string description: 'Language code (de, fr, it).' example: de responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'PV Multi-Roof Configuration' parameters: - in: path name: egid description: 'Building EGID.' example: '123456' required: true schema: type: string - in: path name: configId description: 'Configuration ID.' example: '1' required: true schema: type: string '/api/buildings/{egid}/pv-multi-roof-configurations/{configId}/profiles/{year}': get: summary: 'Get production profile for a specific configuration and year' operationId: getProductionProfileForASpecificConfigurationAndYear description: "Supports both TMY (Typical Meteorological Year) profiles and year-specific profiles.\nFor TMY profiles, the data is mapped to the requested year's calendar." parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. code: unauthenticated properties: message: type: string example: Unauthenticated. code: type: string example: unauthenticated tags: - 'PV Multi-Roof Configuration' parameters: - in: path name: egid description: 'Building EGID.' example: '123456' required: true schema: type: string - in: path name: configId description: 'Configuration ID.' example: '1' required: true schema: type: string - in: path name: year description: Year. example: '2025' required: true schema: type: string