From 595946687042190a6e27223fea130ad83a39a328 Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Thu, 1 Oct 2026 10:02:10 +0200 Subject: [PATCH 1/8] docs: update info.description with expanded terminology and clarifications --- .../population-density-data.yaml | 1773 ++++++++--------- 1 file changed, 871 insertions(+), 902 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index f50ba8c..c74ff1e 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -1,902 +1,871 @@ -openapi: 3.0.3 -info: - title: Population Density Data - description: | - The Population Density Data API exposes population density estimations - for a specified area for a specified time interval. - - # Introduction - - With the Population Density Data API the customer can retrieve population density estimations - for a specific area at the current or a specified period of time. The estimation considers historical - anonymized information of the network connected devices in the requested - area. * Note that the data provided are estimations of population, based on past or future predicted data, for both past or future time ranges. - - - This functionality can be used for multiple use - cases, some of the possible use cases for this API are: - - - - Supporting BVLOS (Beyond Visual Line of Sight) flights with the - information needed to meet SORA 2.5 (Specific Operation Risk Assessment) - requirements in terms of intrinsic Ground Risk Class (iGRC). - More information in [Specific Operations Risk Assessment](https://www.easa.europa.eu/en/domains/civil-drones-rpas/specific-category-civil-drones/specific-operations-risk-assessment-sora) - - - Providing information to identify if the ground risk class for - a given drone flight path is acceptable for the time of the flight, or an - alternative time should be considered to lower the risk. - - - Sustainable Urban Planning. - - - Environmental monitoring at mass events, such as concerts or festivals. - - - The list above is just a few examples, the API can be used for other use cases as well. - - - # Relevant terms and definitions - - * **Population Density**: refers to the number of people in a given area divided by the total size of the area. - - * **Notification URL and token**: Developers may provide a callback URL (`sink`) for receiving an async response. - This is an optional parameter. If `sink` is included, it is RECOMMENDED for the client to provide as well the `sinkCredential` - property to protect the notification endpoint. In the current version,`sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT` if provided. - When an asynchronous response is requested, the 202 response of the API will include an `operationId` property. This `operationId` property will - also be sent in the callback notification. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. - - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters to be pre-configured - out-of-band between the API consumer and the API provider as part of the onboarding process. No response of - this API returns `sinkCredential`, so the provider's `jwksUri` is never conveyed in-band. Unlike an event - subscription, this operation creates no resource to read back, the same static `jwksUri` would be repeated on - every `202` response, and the callback may be delivered before the API consumer has processed that response. - If `PRIVATE_KEY_JWT` is requested and no JWK Set is configured for the API consumer, the API returns the - error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's - authorization server when the callback is delivered cannot be detected while the request is being processed, - and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. - - # API Functionality - - Once a developer specifies (1) the area (either as a polygon shape or as a list of geohashes), - (2) a precision level (only when the area is a polygon) and (3) time interval - in which they want to obtain the population density, the API returns a data - set consisting of a sequence of time ranges, with each time range containing the - requested area subdivided into equal-sized grid cells. - - - When the area is provided as a list of geohashes (`areaType: GEOHASHLIST`), the response - contains one cell per requested geohash; each geohash determines the granularity of its own - response cell, and the `precision` request property MUST NOT be included. - - - For each of the equal-sized cells of the grid, an estimated population density is - reported for each time slot within the range, this includes: estimated population density people/km2, and a range for this estimation - [minimum, maximum] - (exact definitions of minimum and maximum are estimation algorithm specific). - - - These values are calculated based on historical data, prediction models, and population estimation models. The requested interval must either be completely in the future or in the past. - - The API has the following time constraints for requests: the minimum startTime must cover at least 3 months before the request time, - and the maximum endTime allowed is 3 months from the time of the request. - - The polygon specifying an area of interest must comply with certain restrictions, - which must be previously validated by the developer: - - - The polygon may not exceed a certain area. - - - The polygon may not contain more than 15 vertexes. - - - The polygon must be associated with a location where the MNO provides - mobile connectivity services. If a polygon is located entirely outside the - supported area, an empty array is returned. - - - When the area is specified as a list of geohashes (`areaType: GEOHASHLIST`): - - - All MNOs must support the `POLYGON` area type; support for `GEOHASHLIST` is optional. - If the MNO does not support `GEOHASHLIST`, the API returns the error response - `POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE`. - - - The requested geohashes do not need to be adjacent or contiguous; the API - returns one cell per requested geohash. - - - Geohashes within the same request may have different precisions (string lengths), - as long as the MNO supports all of them. If any geohash uses a precision not - supported by the MNO, the API returns the error response - `POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION`. - - - Geohashes within the list that fall outside the MNO coverage area are returned - with cell type `NO_DATA`. If the entire list is outside the coverage area, the - response will have `status` set to `AREA_NOT_SUPPORTED`. - - - The standard behaviour of the API is synchronous, although for large - area requests the API may behave asynchronously. An API invoker can enforce - asynchronous behaviour by providing a callback URL (`sink`) - in the request; in this case the API sends a callback - to the callback URL provided with the result of the request. If `sink` is - included, it is RECOMMENDED for the client to provide as well the `sinkCredential` - property to protect the notification endpoint. In the current version,`sinkCredential.credentialType` - MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT` if provided. - - - Three different `422` error responses distinguish why a request cannot be served. They are - mutually exclusive and are evaluated in this order: - - - `POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE`: the API consumer requested the - asynchronous behaviour by providing `sink`, but the API provider does not support asynchronous - processing at all. This error depends only on the capabilities of the implementation, never on - the size of the request: it is returned even for a request small enough to be served - synchronously. The API consumer can retry the same request without `sink` to obtain a - synchronous response. - - - `POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE`: the combination of `area`, `precision`, - `startTime` and `endTime` involves an amount of processing that cannot be handled synchronously, - and asynchronous processing is not enabled. Unlike the previous error, this one depends on the - size of the request, so a smaller request would succeed. - - - `POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST`: the combination of `area`, `precision`, - `startTime` and `endTime` is too big to be processed **even asynchronously**. Retrying with - `sink` does not help; only a smaller request does. - - If an error happens during the asynchronous processing of the request. The API callback - will have property `status` with value `OPERATION_NOT_COMPLETED` as an error cannot be returned in the callback. - The callback will also include the `statusInfo` property to add extra information about the error. - - **NOTE**: In order to ensure anonymized information, if the data relating to - a grid cell in the required time interval is not sufficient to be exposed due - to [k-anonymity](https://en.wikipedia.org/wiki/K-anonymity), no such data is - returned by the API and the value of the dataType property is `LOW_DENSITY`. - - # Resources and Operations overview - - The API provides one endpoint that accepts POST requests for retrieving population - density information in the specified area. - - - - # Authorization and authentication - - The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. - - The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. - - In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. - - - Population Density Data API ensures the usage of anonymized information and does not treat personal data as either input or output. - Therefore, the access to Population Density Data API is defined as Client Credentials - 2-legged. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the latest detailed specification of this authentication/authorization flow. - - - - # Additional CAMARA error responses - - The list of error codes in this API specification is not exhaustive. Therefore the API specification MAY not document some non-mandatory error statuses as indicated in `CAMARA API Design Guide`. - - Please refer to the `CAMARA_common.yaml` of the Commonalities Release associated to this API version for a complete list of error responses. The applicable Commonalities Release can be identified from the `x-camara-commonalities` field, the changelog and the metadata of the released API version. - - As a specific rule, error `501 - NOT_IMPLEMENTED` can be only a possible error response if it is explicitly documented in the API. - - - - - # Request body strictness - - This API rejects requests with JSON request bodies that contain properties not declared in this specification, at any nesting level. Unknown properties result in a `400 INVALID_ARGUMENT` response. - - - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html - version: wip - - x-camara-commonalities: 0.9.0 -externalDocs: - description: Product documentation at CAMARA. - url: https://github.com/camaraproject/PopulationDensityData - -servers: - - url: '{apiRoot}/population-density-data/vwip' - - variables: - apiRoot: - default: http://localhost:9091 - description: API root -tags: - - name: Population Density Data - description: Operations to retrieve population density information. -paths: - /retrieve: - post: - tags: - - Population Density Data - summary: Retrieves population density information in a specified area - description: >- - Retrieves population density estimation together with the estimation range related - for a time slot for a given area (described as a polygon) as a data set - consisting of a sequence of equally-sized objects covering the input - polygon area. - operationId: retrievePopulationDensity - parameters: - - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/PopulationDensityRequest' - example: - area: - areaType: POLYGON - boundary: - - latitude: 45.754114 - longitude: 4.860374 - - latitude: 45.753845 - longitude: 4.863185 - - latitude: 45.75249 - longitude: 4.861876 - - latitude: 45.751224 - longitude: 4.861125 - - latitude: 45.751442 - longitude: 4.859827 - startTime: '2024-04-23T14:44:18.165Z' - endTime: '2024-04-23T14:44:18.165Z' - precision: 7 - required: true - callbacks: - populationDensityDataCallback: - '{$request.body#/sink}': - post: - tags: - - Population Density Data - summary: 'Population Density Data callback' - description: | - Important: this endpoint is to be implemented by the API consumer. - The Population Density Data server will call this endpoint when the request result is ready. - operationId: postNotification - parameters: - - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" - requestBody: - description: Population density data result. - content: - application/json: - schema: - $ref: '#/components/schemas/PopulationDensityAsyncResponse' - examples: - PopulationDensitySupportedAreaAsyncResponseExample: - $ref: '#/components/examples/PopulationDensitySupportedAreaAsyncResponseExample' - PopulationDensityAreaNotSupportedAsyncResponseExample: - $ref: '#/components/examples/PopulationDensityAreaNotSupportedAsyncResponseExample' - PopulationDensityPartOfAreaNotSupportedAsyncResponseExample: - $ref: '#/components/examples/PopulationDensityPartOfAreaNotSupportedAsyncResponseExample' - PopulationDensityOperationNotCompletedExample: - $ref: '#/components/examples/PopulationDensityOperationNotCompletedExample' - responses: - '204': - description: Successful notification - headers: - x-correlator: - $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" - '400': - $ref: '../common/CAMARA_common.yaml#/components/responses/BadRequest400' - '401': - $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' - '403': - $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' - '410': - $ref: '../common/CAMARA_event_common.yaml#/components/responses/SinkGone410' - '429': - $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' - security: - - {} - - notificationsBearerAuth: [] - responses: - '200': - description: Population density data result. - headers: - x-correlator: - $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: '#/components/schemas/PopulationDensityResponse' - examples: - PopulationDensitySupportedAreaResponseExample: - $ref: '#/components/examples/PopulationDensitySupportedAreaResponseExample' - PopulationDensityAreaNotSupportedResponseExample: - $ref: '#/components/examples/PopulationDensityAreaNotSupportedResponseExample' - PopulationDensityPartOfAreaNotSupportedResponseExample: - $ref: '#/components/examples/PopulationDensityPartOfAreaNotSupportedResponseExample' - - '202': - description: Population density data requested. This response is returned when the behaviour of the API is asynchronous. - headers: - x-correlator: - $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: '#/components/schemas/AcceptedAsyncResponse' - '400': - $ref: '#/components/responses/RetrieveLocationBadRequest400' - '401': - $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' - '403': - $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' - '422': - $ref: '#/components/responses/RetrieveLocationUnprocessableContent422' - '429': - $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' - security: - - openId: - - population-density-data:read -components: - securitySchemes: - openId: - $ref: "../common/CAMARA_common.yaml#/components/securitySchemes/openId" - notificationsBearerAuth: - $ref: "../common/CAMARA_event_common.yaml#/components/securitySchemes/notificationsBearerAuth" - schemas: - PopulationDensityRequest: - type: object - description: >- - Request object for retrieving population density data in a - specified area. - **NOTE**: The difference between `startTime` and `endTime` cannot be greater than 7 days. - additionalProperties: false - properties: - area: - $ref: '#/components/schemas/Area' - startTime: - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" - endTime: - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" - precision: - type: integer - format: int32 - description: >- - Precision required of response cells. Precision defines a geohash level and corresponds to the length of the geohash for each cell. More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). - If not included the default precision level 7 is used by default. - Values within the schema range (1–12) that are not supported by the MNO return the error response `422 POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION`. Values outside the schema range are invalid per the OpenAPI definition and return `400 INVALID_ARGUMENT` via request validation. - This property MUST only be set when `area.areaType` is `POLYGON`, if not included the default precision level 7 is used. When `area.areaType` is `GEOHASHLIST`, each requested geohash determines the granularity of its own response cell; if `precision` is sent, the API returns a `400 INVALID_ARGUMENT` error. - minimum: 1 - maximum: 12 - default: 7 - sink: - description: | - The address where the API response will be asynchronously delivered, using the HTTP protocol. - Providing `sink` enforces the asynchronous behaviour of the API. If the API provider does not - support asynchronous processing, the request MUST be rejected with the error response - `422 POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE` and no callback is delivered. - The API consumer can then retry the request without `sink` to obtain a synchronous response. - allOf: - - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Sink" - sinkCredential: - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" - required: - - area - - startTime - - endTime - Area: - description: Base schema for all areas - type: object - properties: - areaType: - $ref: "#/components/schemas/AreaType" - required: - - areaType - discriminator: - propertyName: areaType - mapping: - POLYGON: "#/components/schemas/Polygon" - GEOHASHLIST: "#/components/schemas/GeohashList" - AreaType: - type: string - description: | - Type of this area. - POLYGON - The area is defined as a polygon. - GEOHASHLIST - The area is defined as a list of geohashes. - enum: - - POLYGON - - GEOHASHLIST - Polygon: - description: Polygonal area. The Polygon should be a simple polygon, i.e. should not intersect itself. - allOf: - - $ref: "#/components/schemas/Area" - - type: object - required: - - boundary - properties: - boundary: - $ref: "../common/CAMARA_common.yaml#/components/schemas/PointList" - GeohashList: - description: >- - Area defined as a list of geohashes. Geohashes do not need to be adjacent or contiguous and may have different precision levels (string lengths), as long as the MNO supports all of them. The `precision` request property MUST NOT be set when `areaType` is `GEOHASHLIST`; if set, the API returns a `400 INVALID_ARGUMENT` error. - allOf: - - $ref: "#/components/schemas/Area" - - type: object - required: - - geohashes - properties: - geohashes: - type: array - description: List of geohashes that define the area of interest. - minItems: 1 - maxItems: 1000 - items: - $ref: "#/components/schemas/Geohash" - Geohash: - type: string - description: >- - Geohash string identifying a cell using the [Geohash system](https://en.wikipedia.org/wiki/Geohash), - encoding a geographic location into a short string. Characters are taken from the - base-32 geohash alphabet (`0-9` and `b-z` excluding `a`, `i`, `l`, `o`). - The length of the string determines the cell granularity (precision). - pattern: ^[0-9bcdefghjkmnpqrstuvwxyz]{1,12}$ - maxLength: 12 - example: ezdmemd - PopulationDensityResponse: - type: object - description: >- - Population density values is represented in time intervals for different - cells of the requested area. Each element in `timedPopulationDensityData` array corresponds - to a time interval, containing population density data for the grid cells. The intervals are 1 hour long. - properties: - timedPopulationDensityData: - type: array - description: >- - Time ranges along with the population density data for the cells within it. - The request startTime or the request endTime have to be fully covered by the intervals. - For example, if the intervals are 1-hour long and the input date range were [2024-01-03T11:25:00Z - to 2024-01-03T12:45:00Z] it would contain 2 intervals (Interval from 2024-01-03T11:00:00Z - to 2024-01-03T12:00:00Z and interval from 2024-01-03T12:00:00Z to 2024-01-03T13:00:00Z). - items: - $ref: '#/components/schemas/TimedPopulationDensityData' - maxItems: 168 - status: - $ref: '#/components/schemas/ResponseStatus' - statusInfo: - type: string - maxLength: 512 - description: Information about the status, mandatory when property `status` is `OPERATION_NOT_COMPLETED` for adding extra information about the error. - example: Some error happened during the processing of the request - required: - - timedPopulationDensityData - - status - AcceptedAsyncResponse: - type: object - description: Accepted asynchronous response - properties: - operationId: - $ref: '#/components/schemas/OperationId' - required: - - operationId - PopulationDensityAsyncResponse: - description: Asynchronous population density data response - allOf: - - $ref: '#/components/schemas/PopulationDensityResponse' - - type: object - properties: - operationId: - $ref: '#/components/schemas/OperationId' - required: - - operationId - OperationId: - type: string - maxLength: 256 - description: The unique identifier of the asynchronous operation that is returned when the operation is initiated. - ResponseStatus: - type: string - description: >- - Represents the state of the response for the input polygon defined in the request, the possible values are: - - `SUPPORTED_AREA`: The whole request area is supported. Population density data for the entire requested area is returned. - - `PART_OF_AREA_NOT_SUPPORTED`: Part of the requested area is outside the MNOs coverage area, the cells outside the coverage - area will have property `dataType` with value `NO_DATA`. - - `AREA_NOT_SUPPORTED`: The whole requested area is outside the MNOs coverage area. No data will be returned. - - `OPERATION_NOT_COMPLETED`: An error happened during asynchronous processing of the request. This status will only be returned - in case the asynchronous API behaviour is used. - enum: - - SUPPORTED_AREA - - PART_OF_AREA_NOT_SUPPORTED - - AREA_NOT_SUPPORTED - - OPERATION_NOT_COMPLETED - TimedPopulationDensityData: - type: object - properties: - startTime: - allOf: - - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" - - description: Interval start time. - example: "2023-07-03T10:00:00Z" - endTime: - allOf: - - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" - - description: Interval end time. - example: "2023-07-03T11:00:00Z" - cellPopulationDensityData: - $ref: '#/components/schemas/CellPopulationDensityDataArray' - required: - - startTime - - endTime - - cellPopulationDensityData - CellPopulationDensityDataArray: - type: array - description: >- - Population density data for the different cells in a concrete time range. - items: - $ref: '#/components/schemas/CellPopulationDensityData' - minItems: 1 - maxItems: 10000 - CellPopulationDensityData: - type: object - description: >- - Population density data of a cell in a concrete time range. In case of - insufficient data, to guarantee an anonymized prediction due to the - k-anonymity within a specific cell and time range, no population density - data is returned and the property `dataType` value is "LOW_DENSITY". In - case of a cell not supported `dataType` value is "NO_DATA" - properties: - geohash: - $ref: '#/components/schemas/Geohash' - dataType: - type: string - enum: - - NO_DATA - - LOW_DENSITY - - DENSITY_ESTIMATION - required: - - geohash - - dataType - discriminator: - propertyName: dataType - mapping: - NO_DATA: '#/components/schemas/NoData' - LOW_DENSITY: '#/components/schemas/LowDensity' - DENSITY_ESTIMATION: '#/components/schemas/DensityEstimation' - NoData: - allOf: - - $ref: '#/components/schemas/CellPopulationDensityData' - LowDensity: - allOf: - - $ref: '#/components/schemas/CellPopulationDensityData' - DensityEstimation: - allOf: - - $ref: '#/components/schemas/CellPopulationDensityData' - - type: object - properties: - maxPplDensity: - type: integer - format: int32 - minimum: 0 - maximum: 2147483647 - description: Maximum people/km2 estimated for the defined area. - minPplDensity: - type: integer - format: int32 - minimum: 0 - maximum: 2147483647 - description: Minimum people/km2 estimated for the defined area. - pplDensity: - type: integer - format: int32 - minimum: 0 - maximum: 2147483647 - description: people/km2 estimation for the defined area. - required: - - maxPplDensity - - minPplDensity - - pplDensity - responses: - RetrieveLocationBadRequest400: - description: >- - Problem with the client request. In addition to generic scenarios of - `INVALID_ARGUMENT`, `INVALID_CREDENTIAL`, `INVALID_TOKEN`, another scenarios may exist: - - The area is not a polygon shape or exceeds supported complexity ("code": "POPULATION_DENSITY_DATA.INVALID_AREA", "message": "The area is not a polygon shape or exceeds supported complexity") - - Indicated `startTime` is greater than the maximum allowed ("code": "POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED", "message": "Indicated startTime is greater than the maximum allowed") - - Indicated `startTime` is earlier than the minimum allowed ("code": "POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED", "message": "Indicated startTime is earlier than the minimum allowed") - - Indicated `endTime` is earlier than the `startTime` ("code": "POPULATION_DENSITY_DATA.INVALID_END_TIME", "message": "Indicated endTime is earlier than the startTime") - - Indicated time period is partially in the past and partially in the future ("code": "POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD", "message": "time period is partially in the past and partially in the future") - - Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime) ("code": "POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED", "message": "Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime)") - headers: - x-correlator: - $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' - content: - application/json: - schema: - allOf: - - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 400 - code: - enum: - - INVALID_ARGUMENT - - INVALID_CREDENTIAL - - INVALID_TOKEN - - INVALID_SINK - - POPULATION_DENSITY_DATA.INVALID_AREA - - POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED - - POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED - - POPULATION_DENSITY_DATA.INVALID_END_TIME - - POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED - - POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD - examples: - GENERIC_400_INVALID_ARGUMENT: - $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_INVALID_ARGUMENT" - GENERIC_400_INVALID_CREDENTIAL: - $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_CREDENTIAL" - GENERIC_400_INVALID_TOKEN: - $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_TOKEN" - GENERIC_400_INVALID_SINK: - $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_SINK" - POPULATION_DENSITY_DATA_400_INVALID_AREA: - value: - status: 400 - code: POPULATION_DENSITY_DATA.INVALID_AREA - message: The area is not a polygon shape or has an arbitrary complexity - POPULATION_DENSITY_DATA_400_MAX_STARTTIME_EXCEEDED: - value: - status: 400 - code: POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED - message: >- - Indicated startTime is greater than the maximum allowed - POPULATION_DENSITY_DATA_400_MIN_STARTTIME_EXCEEDED: - value: - status: 400 - code: POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED - message: >- - Indicated startTime is earlier than the minimum allowed - POPULATION_DENSITY_DATA_400_INVALID_END_TIME: - value: - status: 400 - code: POPULATION_DENSITY_DATA.INVALID_END_TIME - message: Indicated endDate is earlier than the startTime - POPULATION_DENSITY_DATA_400_MAX_TIME_PERIOD_EXCEEDED: - value: - status: 400 - code: POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED - message: >- - Indicated time period is greater than the maximum allowed - (More than maximum hours between startTime and endTime) - POPULATION_DENSITY_DATA_400_INVALID_TIME_PERIOD: - value: - status: 400 - code: POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD - message: >- - Indicated time period is partially in the past and partially in the future - - RetrieveLocationUnprocessableContent422: - description: >- - Problem with the client request. The following scenarios may exist: - - Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing, so providing `sink` does not help ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST", "message": "Indicated combination of area, time interval and precision is too big") - - Indicated cell precision (Geohash level) is not supported ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION", "message": "Indicated cell precision (Geohash level) is not supported") - - Indicated combination of area, time interval and precision is too big for a sync response and asynchronous processing is not enabled ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE", "message": "Indicated combination of area, time interval and precision is too big for a sync response") - - `sink` is provided but the API provider does not support asynchronous processing at all, whatever the size of the request ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE", "message": "The API provider does not support the asynchronous processing") - - The requested `areaType` is not supported by the MNO ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE", "message": "The requested areaType is not supported by the MNO") - - `sinkCredential.credentialType` is set to `PRIVATE_KEY_JWT` but no JWK Set is configured for the API consumer ("code": "PRIVATE_KEY_JWT_NOT_CONFIGURED", "message": "No JWK Set configured for PRIVATE_KEY_JWT authentication.") - headers: - x-correlator: - $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' - content: - application/json: - schema: - allOf: - - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 422 - code: - enum: - - POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST - - POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION - - POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE - - POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE - - POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE - - PRIVATE_KEY_JWT_NOT_CONFIGURED - examples: - POPULATION_DENSITY_DATA_422_UNSUPPORTED_REQUEST: - description: >- - The request is too big to be processed even asynchronously, so retrying it with sink does not - help. Only a smaller request does - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST - message: Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing - POPULATION_DENSITY_DATA_422_UNSUPPORTED_PRECISION: - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION - message: >- - Indicated cell precision (Geohash length) is not supported - POPULATION_DENSITY_DATA_422_UNSUPPORTED_SYNC_RESPONSE: - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE - message: >- - Indicated combination of area, time interval and precision is too big for synchronous processing - and asynchronous processing is not enabled - POPULATION_DENSITY_DATA_422_UNSUPPORTED_AREA_TYPE: - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE - message: The requested areaType is not supported by the MNO - POPULATION_DENSITY_DATA_422_UNSUPPORTED_ASYNC_RESPONSE: - description: >- - The API consumer requested the asynchronous behaviour by providing sink, but the API provider - does not support asynchronous processing. Unlike UNSUPPORTED_REQUEST, this error does not depend - on the size of the request - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE - message: The API provider does not support the asynchronous processing - GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: - $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED" - examples: - PopulationDensitySupportedAreaResponseExample: - description: Population density supported area response example - value: - status: SUPPORTED_AREA - timedPopulationDensityData: - - startTime: '2024-01-03T10:00:00Z' - endTime: '2024-01-03T11:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 150 - minPplDensity: 30 - pplDensity: 60 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 40 - pplDensity: 90 - - geohash: ezdqemu - dataType: LOW_DENSITY - - startTime: '2024-01-03T11:00:00Z' - endTime: '2024-01-03T12:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 30 - pplDensity: 70 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - - geohash: ezdqemu - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - PopulationDensityPartOfAreaNotSupportedResponseExample: - description: Population density part of area not supported response example - value: - status: PART_OF_AREA_NOT_SUPPORTED - timedPopulationDensityData: - - startTime: '2024-01-03T10:00:00Z' - endTime: '2024-01-03T11:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 150 - minPplDensity: 30 - pplDensity: 60 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 40 - pplDensity: 90 - - geohash: ezdqemu - dataType: NO_DATA - - startTime: '2024-01-03T11:00:00Z' - endTime: '2024-01-03T12:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 30 - pplDensity: 70 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - - geohash: ezdqemu - dataType: NO_DATA - PopulationDensityAreaNotSupportedResponseExample: - description: Population density area not supported response example - value: - status: AREA_NOT_SUPPORTED - timedPopulationDensityData: [] - PopulationDensitySupportedAreaAsyncResponseExample: - description: Population density supported area async response example - value: - status: SUPPORTED_AREA - timedPopulationDensityData: - - startTime: '2024-01-03T10:00:00Z' - endTime: '2024-01-03T11:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 150 - minPplDensity: 30 - pplDensity: 60 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 40 - pplDensity: 90 - - geohash: ezdqemu - dataType: LOW_DENSITY - - startTime: '2024-01-03T11:00:00Z' - endTime: '2024-01-03T12:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 30 - pplDensity: 70 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - - geohash: ezdqemu - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 - PopulationDensityPartOfAreaNotSupportedAsyncResponseExample: - description: Population density part of area not supported async response example - value: - status: PART_OF_AREA_NOT_SUPPORTED - timedPopulationDensityData: - - startTime: '2024-01-03T10:00:00Z' - endTime: '2024-01-03T11:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 150 - minPplDensity: 30 - pplDensity: 60 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 40 - pplDensity: 90 - - geohash: ezdqemu - dataType: NO_DATA - - startTime: '2024-01-03T11:00:00Z' - endTime: '2024-01-03T12:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 30 - pplDensity: 70 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - - geohash: ezdqemu - dataType: NO_DATA - operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 - PopulationDensityAreaNotSupportedAsyncResponseExample: - description: Population density area not supported async response example - value: - status: AREA_NOT_SUPPORTED - timedPopulationDensityData: [] - operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 - PopulationDensityOperationNotCompletedExample: - description: Population density operation not completed example - value: - status: OPERATION_NOT_COMPLETED - timedPopulationDensityData: [] - statusInfo: Some error happened during the processing of the request - operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 +openapi: 3.0.3 +info: + title: Population Density Data + description: | + The Population Density Data API provides estimated population density information for a specified geographic area and time interval. + + # Introduction + + The Population Density Data API allows API Consumers to retrieve anonymized estimations of the number of people per square kilometer in the given area in the time interval on an hourly basis. The resulting data is prepared by the API Provider, either derived from historical network data or using prediction algorithms. The API supports both synchronous and asynchronous processing depending on the size and complexity of the request. + + - The defined **area** is either a polygon (a list of geographical coordinates) or a list of geohashes + - The provided **time interval** is either a fully past or a fully future time interval. + - The resulting estimations are derived from anonymized historical device‑based information and predictive models. Returned values include the estimated population density (number of people) for each cell in the requested **area** and each hourly timeslot in the requested **time interval**, as well as an estimation density range [minimum, maximum]. The exact interpretation of minimum and maximum depends on the API Provider's underlying estimation algorithm. + + This API supports a wide range of use cases, including but not limited to: + + - **BVLOS (Beyond Visual Line of Sight) drone operations**, providing information required for SORA 2.5 intrinsic Ground Risk Class (iGRC) assessments. See [Specific Operations Risk Assessment](https://www.easa.europa.eu/en/domains/civil-drones-rpas/specific-category-civil-drones/specific-operations-risk-assessment-sora) + - **Drone flight planning**, enabling to determine whether the ground risk class at a given time is acceptable or whether alternative times should be considered. + - **Sustainable urban planning**, supporting analysis of population distribution patterns. + - **Environmental and safety monitoring** during large events such as concerts, festivals, or public gatherings. + + These examples illustrate typical applications, but the API can be used in many other scenarios where population density estimation is relevant. + + # Relevant Terms and Definitions + + **Population Density** + Number of people at a given time in a given area expressed as an integer value. + + **Area Types** + - **POLYGON**: Area defined by a list of latitude/longitude points forming a simple polygon. The polygon is subdivided into a grid of equal-sized cells. The number of cells in the grid is dependent on the requested precision. + - **GEOHASHLIST**: Area defined as a list of geohash strings. Geohashes may be individual, non‑contiguous geographical areas each with their own (possibly different) precision. + + **Grid Cell** + A subdivision of the requested area. + + - For polygon areas, the API generates equal‑sized grid cells based on the requested precision, by mapping each polygon coordinate to a geohash at the requested precision level. + - For geohash lists, each geohash corresponds to a single cell at the requested precision level. + + **Geohash** + A geohash is a string-encoded representation of a geographical area/point on the globe. The (32-base) geohash model represents the globe as a grid of 32 fixed rectangular areas, referred to as cells. Each cell is identified by a single letter or digit. Zooming in to one cell (recursively) gives a more granular (or higher precision) 32-cell grid at the next level with each cell again identified by a single letter or digit. The geohash is a string that identifies a cell at a given zoom level by concatenating the identifiers of all previous level grid cells selected. The deeper the zoom, the longer the string and the higher the granularity/precision of the cell. The maximum zoom/precision level in this system is 12. The length (number of characters) of the geohash indicates its precision (zoom level/granularity). For examples, see [here](https://esp.info/geohash) or [here](https://www.geohash.es/encode). + + **Precision** + Defines the granularity level of grid cells. + + - **POLYGON**: For polygon areas, the precision level 7 is used by default. I.e. a grid is generated for the polygon by creating a list of geohashes, one for each of the coordinates of the provided polygon at zoom level 7. NOTE: several very close polygon coordinates may map into the same geohash. + - **GEOHASHLIST**: For geohash lists, each geohash’s own length determines its precision. Example: the geohash for Spain is "e" at precision level 1; the geohash for Madrid (2 cell zoom levels deeper) is "ezj" at precision level 3. Further zooming adds more characters to the geohash, each time identifying a smaller rectangular area on the globe. + + **MNO Coverage Area** + The geographic area where the Mobile Network Operator (MNO) provides connectivity services. Cells outside this area are returned with `dataType = NO_DATA`. + + **Population Density Data API call result: DataType** + - **DENSITY_ESTIMATION**: Population density estimation is available. + - **LOW_DENSITY**: Insufficient anonymized data due to k‑anonymity constraints; no density estimation is returned. + - **NO_DATA**: The cell lies outside the MNO coverage area. + + **k‑Anonymity** + A privacy mechanism ensuring that data cannot be attributed to fewer than *k* individuals. If insufficient data exists for a cell/time interval, the API returns `LOW_DENSITY`. + + **Synchronous vs Asynchronous Processing** + - **Synchronous**: The API returns the result immediately in the response. + - **Asynchronous**: For large requests or when explicitly requested via `sink`, the API returns a 202 response with an `operationId` and later delivers the result to the callback URL, including the same `operationId`. + + **OperationId** + A unique identifier correlating an asynchronous request with its callback notification. + + **Callback URL and Token** + A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, the client should also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. + + # API Functionality + + To retrieve population density data, the API consumer specifies: + 1. The area (polygon or geohash list) + 2. The precision (only for polygon areas) + 3. A fully past or fully future time interval + + The API returns a sequence of hourly time slots covering the specified interval (adjusted to the begin and end full hour boundaries). Each time slot contains population density data result for all the grid cells covering the requested area. + + - For polygon areas, the API implementation subdivides the polygon into equal‑sized grid cells based on the precision requested in the API call. If not specified in the request, a default precision level 7 is used. + - For geohash lists, each geohash corresponds to a single cell, and the `precision` property must not be included in the API call. + + Population density values are estimated using historical data, prediction models, and population estimation algorithms. The allowed time interval is constrained: + - The minimum allowed `startTime` is up to 3 months before the request time. + - The maximum allowed `endTime` is up to 3 months after the request time. + - The difference between `startTime` and `endTime` must not exceed 7 days (168 hours). + + Polygon areas must meet certain constraints: + - Maximum polygon area size (implementation‑specific). + - Must have a minimum of 3 and can have a maximum of 15 geographical points defining the polygon. + - Must lie at least partially within the MNO coverage area; otherwise, an empty array is returned. + + For geohash lists: + - Support for `GEOHASHLIST` is optional for MNOs. + - Geohashes may be non‑contiguous and have varying precision. + - Unsupported geohash precisions result in `UNSUPPORTED_PRECISION`. + - Geohashes outside coverage are returned with `NO_DATA`. + - If all geohashes are outside coverage, the response status is `AREA_NOT_SUPPORTED`. + + The API normally behaves synchronously. However, large requests may trigger asynchronous processing. Clients may enforce asynchronous behavior by providing a `sink` callback URL. If asynchronous processing is not supported, the API returns `UNSUPPORTED_ASYNC_RESPONSE`. + + Three mutually exclusive `422` errors indicate why a request cannot be served: + - **UNSUPPORTED_ASYNC_RESPONSE**: Asynchronous processing is not supported. + - **UNSUPPORTED_SYNC_RESPONSE**: Request too large for synchronous processing and asynchronous processing is not enabled. + - **UNSUPPORTED_REQUEST**: Request too large for both synchronous and asynchronous processing. + + If an error occurs during asynchronous processing, the callback includes `status = OPERATION_NOT_COMPLETED` and a `statusInfo` field with additional details. + + **Privacy Note** + To ensure anonymization, if data for a cell/time interval does not meet k‑anonymity requirements, the API returns `LOW_DENSITY` for that cell. + + # Resources and Operations Overview + + The API exposes a single POST endpoint for retrieving population density data for a specified area and time interval. + The API call result is an array of hourly timeslots (`timedPopulationDensityData`), with per timeslot an array of cells (`cellPopulationDensityData`), with for each cell the resulting `DataType` with the density data result. If data is available, the result `DataType` is **DENSITY_ESTIMATION**, and the estimated density data is a number of estimated people in the cell in the timeslot, as well as minimum and maximum estimated values. Other possible results are indicated by different DataTypes. The 3 possible results are as follows: + + - **DENSITY_ESTIMATION**: Population density estimation is available. + - **LOW_DENSITY**: Insufficient anonymized data due to k‑anonymity constraints; no density estimation is returned. + - **NO_DATA**: The cell lies outside the MNO coverage area. + + **Callback URL and token** + Developers may provide a callback URL (`sink`) for receiving an asynchronous response. This is an optional parameter. If `sink` is included, it is RECOMMENDED for the client to provide as well the `sinkCredential` property to protect the notification endpoint. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. + + - When an asynchronous response is requested (using `sink`), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. + + - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the contained provider's `jwksUri` is never conveyed in the response. The `/retrieve` operation creates no resource to read back. The same static `jwksUri` is returned on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. + + + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. + + The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. + + In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. + + + For this API, only anonymized data is processed, and no personal data is exposed. Therefore, access is granted using the Client Credentials (2‑legged) flow. + + + + # Additional CAMARA error responses + + The list of error codes in this API specification is not exhaustive. Therefore the API specification MAY not document some non-mandatory error statuses as indicated in `CAMARA API Design Guide`. + + Please refer to the `CAMARA_common.yaml` of the Commonalities Release associated to this API version for a complete list of error responses. The applicable Commonalities Release can be identified from the `x-camara-commonalities` field, the changelog and the metadata of the released API version. + + As a specific rule, error `501 - NOT_IMPLEMENTED` can be only a possible error response if it is explicitly documented in the API. + + + + + # Request body strictness + + This API rejects requests with JSON request bodies that contain properties not declared in this specification, at any nesting level. Unknown properties result in a `400 INVALID_ARGUMENT` response. + + + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: wip + + x-camara-commonalities: 0.9.0 +externalDocs: + description: Product documentation at CAMARA. + url: https://github.com/camaraproject/PopulationDensityData + +servers: + - url: '{apiRoot}/population-density-data/vwip' + + variables: + apiRoot: + default: http://localhost:9091 + description: API root +tags: + - name: Population Density Data + description: Operations to retrieve population density information. +paths: + /retrieve: + post: + tags: + - Population Density Data + summary: Retrieves population density information in a specified area + description: >- + Retrieves population density estimations for a specified area (polygon or geohash list) + and time interval. The response is a sequence of hourly time slots, each containing + estimated population density data for the grid cells covering the requested area. + operationId: retrievePopulationDensity + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PopulationDensityRequest' + example: + area: + areaType: POLYGON + boundary: + - latitude: 45.754114 + longitude: 4.860374 + - latitude: 45.753845 + longitude: 4.863185 + - latitude: 45.75249 + longitude: 4.861876 + - latitude: 45.751224 + longitude: 4.861125 + - latitude: 45.751442 + longitude: 4.859827 + startTime: '2024-04-23T14:44:18.165Z' + endTime: '2024-04-23T14:44:18.165Z' + precision: 7 + required: true + callbacks: + populationDensityDataCallback: + '{$request.body#/sink}': + post: + tags: + - Population Density Data + summary: 'Population Density Data callback' + description: | + Important: this endpoint is to be implemented by the API consumer. + The Population Density Data server will call this endpoint when the request result is ready. + operationId: postNotification + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + requestBody: + description: Population density data result. + content: + application/json: + schema: + $ref: '#/components/schemas/PopulationDensityAsyncResponse' + examples: + PopulationDensitySupportedAreaAsyncResponseExample: + $ref: '#/components/examples/PopulationDensitySupportedAreaAsyncResponseExample' + PopulationDensityAreaNotSupportedAsyncResponseExample: + $ref: '#/components/examples/PopulationDensityAreaNotSupportedAsyncResponseExample' + PopulationDensityPartOfAreaNotSupportedAsyncResponseExample: + $ref: '#/components/examples/PopulationDensityPartOfAreaNotSupportedAsyncResponseExample' + PopulationDensityOperationNotCompletedExample: + $ref: '#/components/examples/PopulationDensityOperationNotCompletedExample' + responses: + '204': + description: Successful notification + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + '400': + $ref: '../common/CAMARA_common.yaml#/components/responses/BadRequest400' + '401': + $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' + '403': + $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' + '410': + $ref: '../common/CAMARA_event_common.yaml#/components/responses/SinkGone410' + '429': + $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' + security: + - {} + - notificationsBearerAuth: [] + responses: + '200': + description: Population density data result. + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: '#/components/schemas/PopulationDensityResponse' + examples: + PopulationDensitySupportedAreaResponseExample: + $ref: '#/components/examples/PopulationDensitySupportedAreaResponseExample' + PopulationDensityAreaNotSupportedResponseExample: + $ref: '#/components/examples/PopulationDensityAreaNotSupportedResponseExample' + PopulationDensityPartOfAreaNotSupportedResponseExample: + $ref: '#/components/examples/PopulationDensityPartOfAreaNotSupportedResponseExample' + + '202': + description: Population density data requested. This response is returned when the behaviour of the API is asynchronous. + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: '#/components/schemas/AcceptedAsyncResponse' + '400': + $ref: '#/components/responses/RetrieveLocationBadRequest400' + '401': + $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' + '403': + $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' + '422': + $ref: '#/components/responses/RetrieveLocationUnprocessableContent422' + '429': + $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' + security: + - openId: + - population-density-data:read +components: + securitySchemes: + openId: + $ref: "../common/CAMARA_common.yaml#/components/securitySchemes/openId" + notificationsBearerAuth: + $ref: "../common/CAMARA_event_common.yaml#/components/securitySchemes/notificationsBearerAuth" + schemas: + PopulationDensityRequest: + type: object + description: >- + Request object for retrieving population density data in a + specified area. + **NOTE**: The difference between `startTime` and `endTime` cannot be greater than 7 days. + additionalProperties: false + properties: + area: + $ref: '#/components/schemas/Area' + startTime: + $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + endTime: + $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + precision: + type: integer + format: int32 + description: >- + Precision required of response cells. Precision defines a geohash level and corresponds to the length of the geohash for each cell. More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). + If not included the default precision level 7 is used by default. + Values within the schema range (1–12) that are not supported by the MNO return the error response `422 POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION`. Values outside the schema range are invalid per the OpenAPI definition and return `400 INVALID_ARGUMENT` via request validation. + This property MUST only be set when `area.areaType` is `POLYGON`, if not included the default precision level 7 is used. When `area.areaType` is `GEOHASHLIST`, each requested geohash determines the granularity of its own response cell; if `precision` is sent, the API returns a `400 INVALID_ARGUMENT` error. + minimum: 1 + maximum: 12 + default: 7 + sink: + description: | + The address where the API response will be asynchronously delivered, using the HTTP protocol. + Providing `sink` enforces the asynchronous behaviour of the API. If the API provider does not + support asynchronous processing, the request MUST be rejected with the error response + `422 POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE` and no callback is delivered. + The API consumer can then retry the request without `sink` to obtain a synchronous response. + allOf: + - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Sink" + sinkCredential: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" + required: + - area + - startTime + - endTime + Area: + description: Base schema for all areas + type: object + properties: + areaType: + $ref: "#/components/schemas/AreaType" + required: + - areaType + discriminator: + propertyName: areaType + mapping: + POLYGON: "#/components/schemas/Polygon" + GEOHASHLIST: "#/components/schemas/GeohashList" + AreaType: + type: string + description: | + Type of this area. + POLYGON - The area is defined as a polygon. + GEOHASHLIST - The area is defined as a list of geohashes. + enum: + - POLYGON + - GEOHASHLIST + Polygon: + description: Polygonal area. The Polygon should be a simple polygon, i.e. should not intersect itself. + allOf: + - $ref: "#/components/schemas/Area" + - type: object + required: + - boundary + properties: + boundary: + $ref: "../common/CAMARA_common.yaml#/components/schemas/PointList" + GeohashList: + description: >- + Area defined as a list of geohashes. Geohashes do not need to be adjacent or contiguous and may have different precision levels (string lengths), as long as the MNO supports all of them. The `precision` request property MUST NOT be set when `areaType` is `GEOHASHLIST`; if set, the API returns a `400 INVALID_ARGUMENT` error. + allOf: + - $ref: "#/components/schemas/Area" + - type: object + required: + - geohashes + properties: + geohashes: + type: array + description: List of geohashes that define the area of interest. + minItems: 1 + maxItems: 1000 + items: + $ref: "#/components/schemas/Geohash" + Geohash: + type: string + description: >- + Geohash string identifying a cell using the [Geohash system](https://en.wikipedia.org/wiki/Geohash), + encoding a geographic location into a short string. Characters are taken from the + base-32 geohash alphabet (`0-9` and `b-z` excluding `a`, `i`, `l`, `o`). + The length of the string determines the cell granularity (precision). + pattern: ^[0-9bcdefghjkmnpqrstuvwxyz]{1,12}$ + maxLength: 12 + example: ezdmemd + PopulationDensityResponse: + type: object + description: >- + Population density data represented as hourly time intervals for the + cells of the requested area. Each element in `timedPopulationDensityData` array corresponds + to a one-hour time interval, containing population density data for the grid cells. + properties: + timedPopulationDensityData: + type: array + description: >- + Time ranges along with the population density data for the cells within it. + The request startTime or the request endTime have to be fully covered by the intervals. + For example, if the intervals are 1-hour long and the input date range were [2024-01-03T11:25:00Z + to 2024-01-03T12:45:00Z] it would contain 2 intervals (Interval from 2024-01-03T11:00:00Z + to 2024-01-03T12:00:00Z and interval from 2024-01-03T12:00:00Z to 2024-01-03T13:00:00Z). + items: + $ref: '#/components/schemas/TimedPopulationDensityData' + maxItems: 168 + status: + $ref: '#/components/schemas/ResponseStatus' + statusInfo: + type: string + maxLength: 512 + description: Information about the status, mandatory when property `status` is `OPERATION_NOT_COMPLETED` for adding extra information about the error. + example: Some error happened during the processing of the request + required: + - timedPopulationDensityData + - status + AcceptedAsyncResponse: + type: object + description: Accepted asynchronous response + properties: + operationId: + $ref: '#/components/schemas/OperationId' + required: + - operationId + PopulationDensityAsyncResponse: + description: Asynchronous population density data response + allOf: + - $ref: '#/components/schemas/PopulationDensityResponse' + - type: object + properties: + operationId: + $ref: '#/components/schemas/OperationId' + required: + - operationId + OperationId: + type: string + maxLength: 256 + description: The unique identifier of the asynchronous operation that is returned when the operation is initiated. + ResponseStatus: + type: string + description: >- + Represents the state of the response for the input polygon defined in the request, the possible values are: + - `SUPPORTED_AREA`: The whole request area is supported. Population density data for the entire requested area is returned. + - `PART_OF_AREA_NOT_SUPPORTED`: Part of the requested area is outside the MNOs coverage area, the cells outside the coverage + area will have property `dataType` with value `NO_DATA`. + - `AREA_NOT_SUPPORTED`: The whole requested area is outside the MNOs coverage area. No data will be returned. + - `OPERATION_NOT_COMPLETED`: An error happened during asynchronous processing of the request. This status will only be returned + in case the asynchronous API behaviour is used. + enum: + - SUPPORTED_AREA + - PART_OF_AREA_NOT_SUPPORTED + - AREA_NOT_SUPPORTED + - OPERATION_NOT_COMPLETED + TimedPopulationDensityData: + type: object + properties: + startTime: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + - description: Interval start time. + example: "2023-07-03T10:00:00Z" + endTime: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + - description: Interval end time. + example: "2023-07-03T11:00:00Z" + cellPopulationDensityData: + $ref: '#/components/schemas/CellPopulationDensityDataArray' + required: + - startTime + - endTime + - cellPopulationDensityData + CellPopulationDensityDataArray: + type: array + description: >- + Population density data for the different cells in a concrete time range. + items: + $ref: '#/components/schemas/CellPopulationDensityData' + minItems: 1 + maxItems: 10000 + CellPopulationDensityData: + type: object + description: >- + Population density data of a cell in a concrete time range. In case of + insufficient data, to guarantee an anonymized prediction due to the + k-anonymity within a specific cell and time range, no population density + data is returned and the property `dataType` value is "LOW_DENSITY". In + case of a cell not supported `dataType` value is "NO_DATA" + properties: + geohash: + $ref: '#/components/schemas/Geohash' + dataType: + type: string + enum: + - NO_DATA + - LOW_DENSITY + - DENSITY_ESTIMATION + required: + - geohash + - dataType + discriminator: + propertyName: dataType + mapping: + NO_DATA: '#/components/schemas/NoData' + LOW_DENSITY: '#/components/schemas/LowDensity' + DENSITY_ESTIMATION: '#/components/schemas/DensityEstimation' + NoData: + allOf: + - $ref: '#/components/schemas/CellPopulationDensityData' + LowDensity: + allOf: + - $ref: '#/components/schemas/CellPopulationDensityData' + DensityEstimation: + allOf: + - $ref: '#/components/schemas/CellPopulationDensityData' + - type: object + properties: + maxPplDensity: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Maximum estimated number of people for the cell. + minPplDensity: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Minimum estimated number of people for the cell. + pplDensity: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Estimated number of people for the cell. + required: + - maxPplDensity + - minPplDensity + - pplDensity + responses: + RetrieveLocationBadRequest400: + description: >- + Problem with the client request. In addition to generic scenarios of + `INVALID_ARGUMENT`, `INVALID_CREDENTIAL`, `INVALID_TOKEN`, another scenarios may exist: + - The area is not a polygon shape or exceeds supported complexity ("code": "POPULATION_DENSITY_DATA.INVALID_AREA", "message": "The area is not a polygon shape or exceeds supported complexity") + - Indicated `startTime` is greater than the maximum allowed ("code": "POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED", "message": "Indicated startTime is greater than the maximum allowed") + - Indicated `startTime` is earlier than the minimum allowed ("code": "POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED", "message": "Indicated startTime is earlier than the minimum allowed") + - Indicated `endTime` is earlier than the `startTime` ("code": "POPULATION_DENSITY_DATA.INVALID_END_TIME", "message": "Indicated endTime is earlier than the startTime") + - Indicated time period is partially in the past and partially in the future ("code": "POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD", "message": "time period is partially in the past and partially in the future") + - Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime) ("code": "POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED", "message": "Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime)") + headers: + x-correlator: + $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - INVALID_CREDENTIAL + - INVALID_TOKEN + - INVALID_SINK + - POPULATION_DENSITY_DATA.INVALID_AREA + - POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED + - POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED + - POPULATION_DENSITY_DATA.INVALID_END_TIME + - POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED + - POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD + examples: + GENERIC_400_INVALID_ARGUMENT: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_INVALID_ARGUMENT" + GENERIC_400_INVALID_CREDENTIAL: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_CREDENTIAL" + GENERIC_400_INVALID_TOKEN: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_TOKEN" + GENERIC_400_INVALID_SINK: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_SINK" + POPULATION_DENSITY_DATA_400_INVALID_AREA: + value: + status: 400 + code: POPULATION_DENSITY_DATA.INVALID_AREA + message: The area is not a polygon shape or has an arbitrary complexity + POPULATION_DENSITY_DATA_400_MAX_STARTTIME_EXCEEDED: + value: + status: 400 + code: POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED + message: >- + Indicated startTime is greater than the maximum allowed + POPULATION_DENSITY_DATA_400_MIN_STARTTIME_EXCEEDED: + value: + status: 400 + code: POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED + message: >- + Indicated startTime is earlier than the minimum allowed + POPULATION_DENSITY_DATA_400_INVALID_END_TIME: + value: + status: 400 + code: POPULATION_DENSITY_DATA.INVALID_END_TIME + message: Indicated endDate is earlier than the startTime + POPULATION_DENSITY_DATA_400_MAX_TIME_PERIOD_EXCEEDED: + value: + status: 400 + code: POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED + message: >- + Indicated time period is greater than the maximum allowed + (More than maximum hours between startTime and endTime) + POPULATION_DENSITY_DATA_400_INVALID_TIME_PERIOD: + value: + status: 400 + code: POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD + message: >- + Indicated time period is partially in the past and partially in the future + + RetrieveLocationUnprocessableContent422: + description: >- + Problem with the client request. The following scenarios may exist: + - Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing, so providing `sink` does not help ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST", "message": "Indicated combination of area, time interval and precision is too big") + - Indicated cell precision (Geohash level) is not supported ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION", "message": "Indicated cell precision (Geohash level) is not supported") + - Indicated combination of area, time interval and precision is too big for a sync response and asynchronous processing is not enabled ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE", "message": "Indicated combination of area, time interval and precision is too big for a sync response") + - `sink` is provided but the API provider does not support asynchronous processing at all, whatever the size of the request ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE", "message": "The API provider does not support the asynchronous processing") + - The requested `areaType` is not supported by the MNO ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE", "message": "The requested areaType is not supported by the MNO") + - `sinkCredential.credentialType` is set to `PRIVATE_KEY_JWT` but no JWK Set is configured for the API consumer ("code": "PRIVATE_KEY_JWT_NOT_CONFIGURED", "message": "No JWK Set configured for PRIVATE_KEY_JWT authentication.") + headers: + x-correlator: + $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST + - POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION + - POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE + - POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE + - POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE + - PRIVATE_KEY_JWT_NOT_CONFIGURED + examples: + POPULATION_DENSITY_DATA_422_UNSUPPORTED_REQUEST: + description: >- + The request is too big to be processed even asynchronously, so retrying it with sink does not + help. Only a smaller request does + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST + message: Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing + POPULATION_DENSITY_DATA_422_UNSUPPORTED_PRECISION: + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION + message: >- + Indicated cell precision (Geohash length) is not supported + POPULATION_DENSITY_DATA_422_UNSUPPORTED_SYNC_RESPONSE: + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE + message: >- + Indicated combination of area, time interval and precision is too big for synchronous processing + and asynchronous processing is not enabled + POPULATION_DENSITY_DATA_422_UNSUPPORTED_AREA_TYPE: + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE + message: The requested areaType is not supported by the MNO + POPULATION_DENSITY_DATA_422_UNSUPPORTED_ASYNC_RESPONSE: + description: >- + The API consumer requested the asynchronous behaviour by providing sink, but the API provider + does not support asynchronous processing. Unlike UNSUPPORTED_REQUEST, this error does not depend + on the size of the request + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE + message: The API provider does not support the asynchronous processing + GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED" + examples: + PopulationDensitySupportedAreaResponseExample: + description: Population density supported area response example + value: + status: SUPPORTED_AREA + timedPopulationDensityData: + - startTime: '2024-01-03T10:00:00Z' + endTime: '2024-01-03T11:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 150 + minPplDensity: 30 + pplDensity: 60 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 40 + pplDensity: 90 + - geohash: ezdqemu + dataType: LOW_DENSITY + - startTime: '2024-01-03T11:00:00Z' + endTime: '2024-01-03T12:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 30 + pplDensity: 70 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + - geohash: ezdqemu + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + PopulationDensityPartOfAreaNotSupportedResponseExample: + description: Population density part of area not supported response example + value: + status: PART_OF_AREA_NOT_SUPPORTED + timedPopulationDensityData: + - startTime: '2024-01-03T10:00:00Z' + endTime: '2024-01-03T11:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 150 + minPplDensity: 30 + pplDensity: 60 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 40 + pplDensity: 90 + - geohash: ezdqemu + dataType: NO_DATA + - startTime: '2024-01-03T11:00:00Z' + endTime: '2024-01-03T12:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 30 + pplDensity: 70 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + - geohash: ezdqemu + dataType: NO_DATA + PopulationDensityAreaNotSupportedResponseExample: + description: Population density area not supported response example + value: + status: AREA_NOT_SUPPORTED + timedPopulationDensityData: [] + PopulationDensitySupportedAreaAsyncResponseExample: + description: Population density supported area async response example + value: + status: SUPPORTED_AREA + timedPopulationDensityData: + - startTime: '2024-01-03T10:00:00Z' + endTime: '2024-01-03T11:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 150 + minPplDensity: 30 + pplDensity: 60 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 40 + pplDensity: 90 + - geohash: ezdqemu + dataType: LOW_DENSITY + - startTime: '2024-01-03T11:00:00Z' + endTime: '2024-01-03T12:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 30 + pplDensity: 70 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + - geohash: ezdqemu + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 + PopulationDensityPartOfAreaNotSupportedAsyncResponseExample: + description: Population density part of area not supported async response example + value: + status: PART_OF_AREA_NOT_SUPPORTED + timedPopulationDensityData: + - startTime: '2024-01-03T10:00:00Z' + endTime: '2024-01-03T11:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 150 + minPplDensity: 30 + pplDensity: 60 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 40 + pplDensity: 90 + - geohash: ezdqemu + dataType: NO_DATA + - startTime: '2024-01-03T11:00:00Z' + endTime: '2024-01-03T12:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 30 + pplDensity: 70 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + - geohash: ezdqemu + dataType: NO_DATA + operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 + PopulationDensityAreaNotSupportedAsyncResponseExample: + description: Population density area not supported async response example + value: + status: AREA_NOT_SUPPORTED + timedPopulationDensityData: [] + operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 + PopulationDensityOperationNotCompletedExample: + description: Population density operation not completed example + value: + status: OPERATION_NOT_COMPLETED + timedPopulationDensityData: [] + statusInfo: Some error happened during the processing of the request + operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 From f00fb77b6643c34f8ffae00b13a0042c088b6f56 Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Thu, 1 Oct 2026 10:07:01 +0200 Subject: [PATCH 2/8] fix: restore CRLF line endings --- .../population-density-data.yaml | 1742 ++++++++--------- 1 file changed, 871 insertions(+), 871 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index c74ff1e..f778ddd 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -1,871 +1,871 @@ -openapi: 3.0.3 -info: - title: Population Density Data - description: | - The Population Density Data API provides estimated population density information for a specified geographic area and time interval. - - # Introduction - - The Population Density Data API allows API Consumers to retrieve anonymized estimations of the number of people per square kilometer in the given area in the time interval on an hourly basis. The resulting data is prepared by the API Provider, either derived from historical network data or using prediction algorithms. The API supports both synchronous and asynchronous processing depending on the size and complexity of the request. - - - The defined **area** is either a polygon (a list of geographical coordinates) or a list of geohashes - - The provided **time interval** is either a fully past or a fully future time interval. - - The resulting estimations are derived from anonymized historical device‑based information and predictive models. Returned values include the estimated population density (number of people) for each cell in the requested **area** and each hourly timeslot in the requested **time interval**, as well as an estimation density range [minimum, maximum]. The exact interpretation of minimum and maximum depends on the API Provider's underlying estimation algorithm. - - This API supports a wide range of use cases, including but not limited to: - - - **BVLOS (Beyond Visual Line of Sight) drone operations**, providing information required for SORA 2.5 intrinsic Ground Risk Class (iGRC) assessments. See [Specific Operations Risk Assessment](https://www.easa.europa.eu/en/domains/civil-drones-rpas/specific-category-civil-drones/specific-operations-risk-assessment-sora) - - **Drone flight planning**, enabling to determine whether the ground risk class at a given time is acceptable or whether alternative times should be considered. - - **Sustainable urban planning**, supporting analysis of population distribution patterns. - - **Environmental and safety monitoring** during large events such as concerts, festivals, or public gatherings. - - These examples illustrate typical applications, but the API can be used in many other scenarios where population density estimation is relevant. - - # Relevant Terms and Definitions - - **Population Density** - Number of people at a given time in a given area expressed as an integer value. - - **Area Types** - - **POLYGON**: Area defined by a list of latitude/longitude points forming a simple polygon. The polygon is subdivided into a grid of equal-sized cells. The number of cells in the grid is dependent on the requested precision. - - **GEOHASHLIST**: Area defined as a list of geohash strings. Geohashes may be individual, non‑contiguous geographical areas each with their own (possibly different) precision. - - **Grid Cell** - A subdivision of the requested area. - - - For polygon areas, the API generates equal‑sized grid cells based on the requested precision, by mapping each polygon coordinate to a geohash at the requested precision level. - - For geohash lists, each geohash corresponds to a single cell at the requested precision level. - - **Geohash** - A geohash is a string-encoded representation of a geographical area/point on the globe. The (32-base) geohash model represents the globe as a grid of 32 fixed rectangular areas, referred to as cells. Each cell is identified by a single letter or digit. Zooming in to one cell (recursively) gives a more granular (or higher precision) 32-cell grid at the next level with each cell again identified by a single letter or digit. The geohash is a string that identifies a cell at a given zoom level by concatenating the identifiers of all previous level grid cells selected. The deeper the zoom, the longer the string and the higher the granularity/precision of the cell. The maximum zoom/precision level in this system is 12. The length (number of characters) of the geohash indicates its precision (zoom level/granularity). For examples, see [here](https://esp.info/geohash) or [here](https://www.geohash.es/encode). - - **Precision** - Defines the granularity level of grid cells. - - - **POLYGON**: For polygon areas, the precision level 7 is used by default. I.e. a grid is generated for the polygon by creating a list of geohashes, one for each of the coordinates of the provided polygon at zoom level 7. NOTE: several very close polygon coordinates may map into the same geohash. - - **GEOHASHLIST**: For geohash lists, each geohash’s own length determines its precision. Example: the geohash for Spain is "e" at precision level 1; the geohash for Madrid (2 cell zoom levels deeper) is "ezj" at precision level 3. Further zooming adds more characters to the geohash, each time identifying a smaller rectangular area on the globe. - - **MNO Coverage Area** - The geographic area where the Mobile Network Operator (MNO) provides connectivity services. Cells outside this area are returned with `dataType = NO_DATA`. - - **Population Density Data API call result: DataType** - - **DENSITY_ESTIMATION**: Population density estimation is available. - - **LOW_DENSITY**: Insufficient anonymized data due to k‑anonymity constraints; no density estimation is returned. - - **NO_DATA**: The cell lies outside the MNO coverage area. - - **k‑Anonymity** - A privacy mechanism ensuring that data cannot be attributed to fewer than *k* individuals. If insufficient data exists for a cell/time interval, the API returns `LOW_DENSITY`. - - **Synchronous vs Asynchronous Processing** - - **Synchronous**: The API returns the result immediately in the response. - - **Asynchronous**: For large requests or when explicitly requested via `sink`, the API returns a 202 response with an `operationId` and later delivers the result to the callback URL, including the same `operationId`. - - **OperationId** - A unique identifier correlating an asynchronous request with its callback notification. - - **Callback URL and Token** - A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, the client should also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. - - # API Functionality - - To retrieve population density data, the API consumer specifies: - 1. The area (polygon or geohash list) - 2. The precision (only for polygon areas) - 3. A fully past or fully future time interval - - The API returns a sequence of hourly time slots covering the specified interval (adjusted to the begin and end full hour boundaries). Each time slot contains population density data result for all the grid cells covering the requested area. - - - For polygon areas, the API implementation subdivides the polygon into equal‑sized grid cells based on the precision requested in the API call. If not specified in the request, a default precision level 7 is used. - - For geohash lists, each geohash corresponds to a single cell, and the `precision` property must not be included in the API call. - - Population density values are estimated using historical data, prediction models, and population estimation algorithms. The allowed time interval is constrained: - - The minimum allowed `startTime` is up to 3 months before the request time. - - The maximum allowed `endTime` is up to 3 months after the request time. - - The difference between `startTime` and `endTime` must not exceed 7 days (168 hours). - - Polygon areas must meet certain constraints: - - Maximum polygon area size (implementation‑specific). - - Must have a minimum of 3 and can have a maximum of 15 geographical points defining the polygon. - - Must lie at least partially within the MNO coverage area; otherwise, an empty array is returned. - - For geohash lists: - - Support for `GEOHASHLIST` is optional for MNOs. - - Geohashes may be non‑contiguous and have varying precision. - - Unsupported geohash precisions result in `UNSUPPORTED_PRECISION`. - - Geohashes outside coverage are returned with `NO_DATA`. - - If all geohashes are outside coverage, the response status is `AREA_NOT_SUPPORTED`. - - The API normally behaves synchronously. However, large requests may trigger asynchronous processing. Clients may enforce asynchronous behavior by providing a `sink` callback URL. If asynchronous processing is not supported, the API returns `UNSUPPORTED_ASYNC_RESPONSE`. - - Three mutually exclusive `422` errors indicate why a request cannot be served: - - **UNSUPPORTED_ASYNC_RESPONSE**: Asynchronous processing is not supported. - - **UNSUPPORTED_SYNC_RESPONSE**: Request too large for synchronous processing and asynchronous processing is not enabled. - - **UNSUPPORTED_REQUEST**: Request too large for both synchronous and asynchronous processing. - - If an error occurs during asynchronous processing, the callback includes `status = OPERATION_NOT_COMPLETED` and a `statusInfo` field with additional details. - - **Privacy Note** - To ensure anonymization, if data for a cell/time interval does not meet k‑anonymity requirements, the API returns `LOW_DENSITY` for that cell. - - # Resources and Operations Overview - - The API exposes a single POST endpoint for retrieving population density data for a specified area and time interval. - The API call result is an array of hourly timeslots (`timedPopulationDensityData`), with per timeslot an array of cells (`cellPopulationDensityData`), with for each cell the resulting `DataType` with the density data result. If data is available, the result `DataType` is **DENSITY_ESTIMATION**, and the estimated density data is a number of estimated people in the cell in the timeslot, as well as minimum and maximum estimated values. Other possible results are indicated by different DataTypes. The 3 possible results are as follows: - - - **DENSITY_ESTIMATION**: Population density estimation is available. - - **LOW_DENSITY**: Insufficient anonymized data due to k‑anonymity constraints; no density estimation is returned. - - **NO_DATA**: The cell lies outside the MNO coverage area. - - **Callback URL and token** - Developers may provide a callback URL (`sink`) for receiving an asynchronous response. This is an optional parameter. If `sink` is included, it is RECOMMENDED for the client to provide as well the `sinkCredential` property to protect the notification endpoint. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. - - - When an asynchronous response is requested (using `sink`), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. - - - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the contained provider's `jwksUri` is never conveyed in the response. The `/retrieve` operation creates no resource to read back. The same static `jwksUri` is returned on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. - - - - # Authorization and authentication - - The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. - - The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. - - In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. - - - For this API, only anonymized data is processed, and no personal data is exposed. Therefore, access is granted using the Client Credentials (2‑legged) flow. - - - - # Additional CAMARA error responses - - The list of error codes in this API specification is not exhaustive. Therefore the API specification MAY not document some non-mandatory error statuses as indicated in `CAMARA API Design Guide`. - - Please refer to the `CAMARA_common.yaml` of the Commonalities Release associated to this API version for a complete list of error responses. The applicable Commonalities Release can be identified from the `x-camara-commonalities` field, the changelog and the metadata of the released API version. - - As a specific rule, error `501 - NOT_IMPLEMENTED` can be only a possible error response if it is explicitly documented in the API. - - - - - # Request body strictness - - This API rejects requests with JSON request bodies that contain properties not declared in this specification, at any nesting level. Unknown properties result in a `400 INVALID_ARGUMENT` response. - - - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html - version: wip - - x-camara-commonalities: 0.9.0 -externalDocs: - description: Product documentation at CAMARA. - url: https://github.com/camaraproject/PopulationDensityData - -servers: - - url: '{apiRoot}/population-density-data/vwip' - - variables: - apiRoot: - default: http://localhost:9091 - description: API root -tags: - - name: Population Density Data - description: Operations to retrieve population density information. -paths: - /retrieve: - post: - tags: - - Population Density Data - summary: Retrieves population density information in a specified area - description: >- - Retrieves population density estimations for a specified area (polygon or geohash list) - and time interval. The response is a sequence of hourly time slots, each containing - estimated population density data for the grid cells covering the requested area. - operationId: retrievePopulationDensity - parameters: - - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/PopulationDensityRequest' - example: - area: - areaType: POLYGON - boundary: - - latitude: 45.754114 - longitude: 4.860374 - - latitude: 45.753845 - longitude: 4.863185 - - latitude: 45.75249 - longitude: 4.861876 - - latitude: 45.751224 - longitude: 4.861125 - - latitude: 45.751442 - longitude: 4.859827 - startTime: '2024-04-23T14:44:18.165Z' - endTime: '2024-04-23T14:44:18.165Z' - precision: 7 - required: true - callbacks: - populationDensityDataCallback: - '{$request.body#/sink}': - post: - tags: - - Population Density Data - summary: 'Population Density Data callback' - description: | - Important: this endpoint is to be implemented by the API consumer. - The Population Density Data server will call this endpoint when the request result is ready. - operationId: postNotification - parameters: - - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" - requestBody: - description: Population density data result. - content: - application/json: - schema: - $ref: '#/components/schemas/PopulationDensityAsyncResponse' - examples: - PopulationDensitySupportedAreaAsyncResponseExample: - $ref: '#/components/examples/PopulationDensitySupportedAreaAsyncResponseExample' - PopulationDensityAreaNotSupportedAsyncResponseExample: - $ref: '#/components/examples/PopulationDensityAreaNotSupportedAsyncResponseExample' - PopulationDensityPartOfAreaNotSupportedAsyncResponseExample: - $ref: '#/components/examples/PopulationDensityPartOfAreaNotSupportedAsyncResponseExample' - PopulationDensityOperationNotCompletedExample: - $ref: '#/components/examples/PopulationDensityOperationNotCompletedExample' - responses: - '204': - description: Successful notification - headers: - x-correlator: - $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" - '400': - $ref: '../common/CAMARA_common.yaml#/components/responses/BadRequest400' - '401': - $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' - '403': - $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' - '410': - $ref: '../common/CAMARA_event_common.yaml#/components/responses/SinkGone410' - '429': - $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' - security: - - {} - - notificationsBearerAuth: [] - responses: - '200': - description: Population density data result. - headers: - x-correlator: - $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: '#/components/schemas/PopulationDensityResponse' - examples: - PopulationDensitySupportedAreaResponseExample: - $ref: '#/components/examples/PopulationDensitySupportedAreaResponseExample' - PopulationDensityAreaNotSupportedResponseExample: - $ref: '#/components/examples/PopulationDensityAreaNotSupportedResponseExample' - PopulationDensityPartOfAreaNotSupportedResponseExample: - $ref: '#/components/examples/PopulationDensityPartOfAreaNotSupportedResponseExample' - - '202': - description: Population density data requested. This response is returned when the behaviour of the API is asynchronous. - headers: - x-correlator: - $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: '#/components/schemas/AcceptedAsyncResponse' - '400': - $ref: '#/components/responses/RetrieveLocationBadRequest400' - '401': - $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' - '403': - $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' - '422': - $ref: '#/components/responses/RetrieveLocationUnprocessableContent422' - '429': - $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' - security: - - openId: - - population-density-data:read -components: - securitySchemes: - openId: - $ref: "../common/CAMARA_common.yaml#/components/securitySchemes/openId" - notificationsBearerAuth: - $ref: "../common/CAMARA_event_common.yaml#/components/securitySchemes/notificationsBearerAuth" - schemas: - PopulationDensityRequest: - type: object - description: >- - Request object for retrieving population density data in a - specified area. - **NOTE**: The difference between `startTime` and `endTime` cannot be greater than 7 days. - additionalProperties: false - properties: - area: - $ref: '#/components/schemas/Area' - startTime: - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" - endTime: - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" - precision: - type: integer - format: int32 - description: >- - Precision required of response cells. Precision defines a geohash level and corresponds to the length of the geohash for each cell. More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). - If not included the default precision level 7 is used by default. - Values within the schema range (1–12) that are not supported by the MNO return the error response `422 POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION`. Values outside the schema range are invalid per the OpenAPI definition and return `400 INVALID_ARGUMENT` via request validation. - This property MUST only be set when `area.areaType` is `POLYGON`, if not included the default precision level 7 is used. When `area.areaType` is `GEOHASHLIST`, each requested geohash determines the granularity of its own response cell; if `precision` is sent, the API returns a `400 INVALID_ARGUMENT` error. - minimum: 1 - maximum: 12 - default: 7 - sink: - description: | - The address where the API response will be asynchronously delivered, using the HTTP protocol. - Providing `sink` enforces the asynchronous behaviour of the API. If the API provider does not - support asynchronous processing, the request MUST be rejected with the error response - `422 POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE` and no callback is delivered. - The API consumer can then retry the request without `sink` to obtain a synchronous response. - allOf: - - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Sink" - sinkCredential: - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" - required: - - area - - startTime - - endTime - Area: - description: Base schema for all areas - type: object - properties: - areaType: - $ref: "#/components/schemas/AreaType" - required: - - areaType - discriminator: - propertyName: areaType - mapping: - POLYGON: "#/components/schemas/Polygon" - GEOHASHLIST: "#/components/schemas/GeohashList" - AreaType: - type: string - description: | - Type of this area. - POLYGON - The area is defined as a polygon. - GEOHASHLIST - The area is defined as a list of geohashes. - enum: - - POLYGON - - GEOHASHLIST - Polygon: - description: Polygonal area. The Polygon should be a simple polygon, i.e. should not intersect itself. - allOf: - - $ref: "#/components/schemas/Area" - - type: object - required: - - boundary - properties: - boundary: - $ref: "../common/CAMARA_common.yaml#/components/schemas/PointList" - GeohashList: - description: >- - Area defined as a list of geohashes. Geohashes do not need to be adjacent or contiguous and may have different precision levels (string lengths), as long as the MNO supports all of them. The `precision` request property MUST NOT be set when `areaType` is `GEOHASHLIST`; if set, the API returns a `400 INVALID_ARGUMENT` error. - allOf: - - $ref: "#/components/schemas/Area" - - type: object - required: - - geohashes - properties: - geohashes: - type: array - description: List of geohashes that define the area of interest. - minItems: 1 - maxItems: 1000 - items: - $ref: "#/components/schemas/Geohash" - Geohash: - type: string - description: >- - Geohash string identifying a cell using the [Geohash system](https://en.wikipedia.org/wiki/Geohash), - encoding a geographic location into a short string. Characters are taken from the - base-32 geohash alphabet (`0-9` and `b-z` excluding `a`, `i`, `l`, `o`). - The length of the string determines the cell granularity (precision). - pattern: ^[0-9bcdefghjkmnpqrstuvwxyz]{1,12}$ - maxLength: 12 - example: ezdmemd - PopulationDensityResponse: - type: object - description: >- - Population density data represented as hourly time intervals for the - cells of the requested area. Each element in `timedPopulationDensityData` array corresponds - to a one-hour time interval, containing population density data for the grid cells. - properties: - timedPopulationDensityData: - type: array - description: >- - Time ranges along with the population density data for the cells within it. - The request startTime or the request endTime have to be fully covered by the intervals. - For example, if the intervals are 1-hour long and the input date range were [2024-01-03T11:25:00Z - to 2024-01-03T12:45:00Z] it would contain 2 intervals (Interval from 2024-01-03T11:00:00Z - to 2024-01-03T12:00:00Z and interval from 2024-01-03T12:00:00Z to 2024-01-03T13:00:00Z). - items: - $ref: '#/components/schemas/TimedPopulationDensityData' - maxItems: 168 - status: - $ref: '#/components/schemas/ResponseStatus' - statusInfo: - type: string - maxLength: 512 - description: Information about the status, mandatory when property `status` is `OPERATION_NOT_COMPLETED` for adding extra information about the error. - example: Some error happened during the processing of the request - required: - - timedPopulationDensityData - - status - AcceptedAsyncResponse: - type: object - description: Accepted asynchronous response - properties: - operationId: - $ref: '#/components/schemas/OperationId' - required: - - operationId - PopulationDensityAsyncResponse: - description: Asynchronous population density data response - allOf: - - $ref: '#/components/schemas/PopulationDensityResponse' - - type: object - properties: - operationId: - $ref: '#/components/schemas/OperationId' - required: - - operationId - OperationId: - type: string - maxLength: 256 - description: The unique identifier of the asynchronous operation that is returned when the operation is initiated. - ResponseStatus: - type: string - description: >- - Represents the state of the response for the input polygon defined in the request, the possible values are: - - `SUPPORTED_AREA`: The whole request area is supported. Population density data for the entire requested area is returned. - - `PART_OF_AREA_NOT_SUPPORTED`: Part of the requested area is outside the MNOs coverage area, the cells outside the coverage - area will have property `dataType` with value `NO_DATA`. - - `AREA_NOT_SUPPORTED`: The whole requested area is outside the MNOs coverage area. No data will be returned. - - `OPERATION_NOT_COMPLETED`: An error happened during asynchronous processing of the request. This status will only be returned - in case the asynchronous API behaviour is used. - enum: - - SUPPORTED_AREA - - PART_OF_AREA_NOT_SUPPORTED - - AREA_NOT_SUPPORTED - - OPERATION_NOT_COMPLETED - TimedPopulationDensityData: - type: object - properties: - startTime: - allOf: - - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" - - description: Interval start time. - example: "2023-07-03T10:00:00Z" - endTime: - allOf: - - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" - - description: Interval end time. - example: "2023-07-03T11:00:00Z" - cellPopulationDensityData: - $ref: '#/components/schemas/CellPopulationDensityDataArray' - required: - - startTime - - endTime - - cellPopulationDensityData - CellPopulationDensityDataArray: - type: array - description: >- - Population density data for the different cells in a concrete time range. - items: - $ref: '#/components/schemas/CellPopulationDensityData' - minItems: 1 - maxItems: 10000 - CellPopulationDensityData: - type: object - description: >- - Population density data of a cell in a concrete time range. In case of - insufficient data, to guarantee an anonymized prediction due to the - k-anonymity within a specific cell and time range, no population density - data is returned and the property `dataType` value is "LOW_DENSITY". In - case of a cell not supported `dataType` value is "NO_DATA" - properties: - geohash: - $ref: '#/components/schemas/Geohash' - dataType: - type: string - enum: - - NO_DATA - - LOW_DENSITY - - DENSITY_ESTIMATION - required: - - geohash - - dataType - discriminator: - propertyName: dataType - mapping: - NO_DATA: '#/components/schemas/NoData' - LOW_DENSITY: '#/components/schemas/LowDensity' - DENSITY_ESTIMATION: '#/components/schemas/DensityEstimation' - NoData: - allOf: - - $ref: '#/components/schemas/CellPopulationDensityData' - LowDensity: - allOf: - - $ref: '#/components/schemas/CellPopulationDensityData' - DensityEstimation: - allOf: - - $ref: '#/components/schemas/CellPopulationDensityData' - - type: object - properties: - maxPplDensity: - type: integer - format: int32 - minimum: 0 - maximum: 2147483647 - description: Maximum estimated number of people for the cell. - minPplDensity: - type: integer - format: int32 - minimum: 0 - maximum: 2147483647 - description: Minimum estimated number of people for the cell. - pplDensity: - type: integer - format: int32 - minimum: 0 - maximum: 2147483647 - description: Estimated number of people for the cell. - required: - - maxPplDensity - - minPplDensity - - pplDensity - responses: - RetrieveLocationBadRequest400: - description: >- - Problem with the client request. In addition to generic scenarios of - `INVALID_ARGUMENT`, `INVALID_CREDENTIAL`, `INVALID_TOKEN`, another scenarios may exist: - - The area is not a polygon shape or exceeds supported complexity ("code": "POPULATION_DENSITY_DATA.INVALID_AREA", "message": "The area is not a polygon shape or exceeds supported complexity") - - Indicated `startTime` is greater than the maximum allowed ("code": "POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED", "message": "Indicated startTime is greater than the maximum allowed") - - Indicated `startTime` is earlier than the minimum allowed ("code": "POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED", "message": "Indicated startTime is earlier than the minimum allowed") - - Indicated `endTime` is earlier than the `startTime` ("code": "POPULATION_DENSITY_DATA.INVALID_END_TIME", "message": "Indicated endTime is earlier than the startTime") - - Indicated time period is partially in the past and partially in the future ("code": "POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD", "message": "time period is partially in the past and partially in the future") - - Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime) ("code": "POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED", "message": "Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime)") - headers: - x-correlator: - $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' - content: - application/json: - schema: - allOf: - - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 400 - code: - enum: - - INVALID_ARGUMENT - - INVALID_CREDENTIAL - - INVALID_TOKEN - - INVALID_SINK - - POPULATION_DENSITY_DATA.INVALID_AREA - - POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED - - POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED - - POPULATION_DENSITY_DATA.INVALID_END_TIME - - POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED - - POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD - examples: - GENERIC_400_INVALID_ARGUMENT: - $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_INVALID_ARGUMENT" - GENERIC_400_INVALID_CREDENTIAL: - $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_CREDENTIAL" - GENERIC_400_INVALID_TOKEN: - $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_TOKEN" - GENERIC_400_INVALID_SINK: - $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_SINK" - POPULATION_DENSITY_DATA_400_INVALID_AREA: - value: - status: 400 - code: POPULATION_DENSITY_DATA.INVALID_AREA - message: The area is not a polygon shape or has an arbitrary complexity - POPULATION_DENSITY_DATA_400_MAX_STARTTIME_EXCEEDED: - value: - status: 400 - code: POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED - message: >- - Indicated startTime is greater than the maximum allowed - POPULATION_DENSITY_DATA_400_MIN_STARTTIME_EXCEEDED: - value: - status: 400 - code: POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED - message: >- - Indicated startTime is earlier than the minimum allowed - POPULATION_DENSITY_DATA_400_INVALID_END_TIME: - value: - status: 400 - code: POPULATION_DENSITY_DATA.INVALID_END_TIME - message: Indicated endDate is earlier than the startTime - POPULATION_DENSITY_DATA_400_MAX_TIME_PERIOD_EXCEEDED: - value: - status: 400 - code: POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED - message: >- - Indicated time period is greater than the maximum allowed - (More than maximum hours between startTime and endTime) - POPULATION_DENSITY_DATA_400_INVALID_TIME_PERIOD: - value: - status: 400 - code: POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD - message: >- - Indicated time period is partially in the past and partially in the future - - RetrieveLocationUnprocessableContent422: - description: >- - Problem with the client request. The following scenarios may exist: - - Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing, so providing `sink` does not help ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST", "message": "Indicated combination of area, time interval and precision is too big") - - Indicated cell precision (Geohash level) is not supported ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION", "message": "Indicated cell precision (Geohash level) is not supported") - - Indicated combination of area, time interval and precision is too big for a sync response and asynchronous processing is not enabled ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE", "message": "Indicated combination of area, time interval and precision is too big for a sync response") - - `sink` is provided but the API provider does not support asynchronous processing at all, whatever the size of the request ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE", "message": "The API provider does not support the asynchronous processing") - - The requested `areaType` is not supported by the MNO ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE", "message": "The requested areaType is not supported by the MNO") - - `sinkCredential.credentialType` is set to `PRIVATE_KEY_JWT` but no JWK Set is configured for the API consumer ("code": "PRIVATE_KEY_JWT_NOT_CONFIGURED", "message": "No JWK Set configured for PRIVATE_KEY_JWT authentication.") - headers: - x-correlator: - $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' - content: - application/json: - schema: - allOf: - - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" - - type: object - properties: - status: - enum: - - 422 - code: - enum: - - POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST - - POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION - - POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE - - POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE - - POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE - - PRIVATE_KEY_JWT_NOT_CONFIGURED - examples: - POPULATION_DENSITY_DATA_422_UNSUPPORTED_REQUEST: - description: >- - The request is too big to be processed even asynchronously, so retrying it with sink does not - help. Only a smaller request does - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST - message: Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing - POPULATION_DENSITY_DATA_422_UNSUPPORTED_PRECISION: - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION - message: >- - Indicated cell precision (Geohash length) is not supported - POPULATION_DENSITY_DATA_422_UNSUPPORTED_SYNC_RESPONSE: - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE - message: >- - Indicated combination of area, time interval and precision is too big for synchronous processing - and asynchronous processing is not enabled - POPULATION_DENSITY_DATA_422_UNSUPPORTED_AREA_TYPE: - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE - message: The requested areaType is not supported by the MNO - POPULATION_DENSITY_DATA_422_UNSUPPORTED_ASYNC_RESPONSE: - description: >- - The API consumer requested the asynchronous behaviour by providing sink, but the API provider - does not support asynchronous processing. Unlike UNSUPPORTED_REQUEST, this error does not depend - on the size of the request - value: - status: 422 - code: POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE - message: The API provider does not support the asynchronous processing - GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: - $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED" - examples: - PopulationDensitySupportedAreaResponseExample: - description: Population density supported area response example - value: - status: SUPPORTED_AREA - timedPopulationDensityData: - - startTime: '2024-01-03T10:00:00Z' - endTime: '2024-01-03T11:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 150 - minPplDensity: 30 - pplDensity: 60 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 40 - pplDensity: 90 - - geohash: ezdqemu - dataType: LOW_DENSITY - - startTime: '2024-01-03T11:00:00Z' - endTime: '2024-01-03T12:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 30 - pplDensity: 70 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - - geohash: ezdqemu - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - PopulationDensityPartOfAreaNotSupportedResponseExample: - description: Population density part of area not supported response example - value: - status: PART_OF_AREA_NOT_SUPPORTED - timedPopulationDensityData: - - startTime: '2024-01-03T10:00:00Z' - endTime: '2024-01-03T11:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 150 - minPplDensity: 30 - pplDensity: 60 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 40 - pplDensity: 90 - - geohash: ezdqemu - dataType: NO_DATA - - startTime: '2024-01-03T11:00:00Z' - endTime: '2024-01-03T12:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 30 - pplDensity: 70 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - - geohash: ezdqemu - dataType: NO_DATA - PopulationDensityAreaNotSupportedResponseExample: - description: Population density area not supported response example - value: - status: AREA_NOT_SUPPORTED - timedPopulationDensityData: [] - PopulationDensitySupportedAreaAsyncResponseExample: - description: Population density supported area async response example - value: - status: SUPPORTED_AREA - timedPopulationDensityData: - - startTime: '2024-01-03T10:00:00Z' - endTime: '2024-01-03T11:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 150 - minPplDensity: 30 - pplDensity: 60 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 40 - pplDensity: 90 - - geohash: ezdqemu - dataType: LOW_DENSITY - - startTime: '2024-01-03T11:00:00Z' - endTime: '2024-01-03T12:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 30 - pplDensity: 70 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - - geohash: ezdqemu - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 - PopulationDensityPartOfAreaNotSupportedAsyncResponseExample: - description: Population density part of area not supported async response example - value: - status: PART_OF_AREA_NOT_SUPPORTED - timedPopulationDensityData: - - startTime: '2024-01-03T10:00:00Z' - endTime: '2024-01-03T11:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 150 - minPplDensity: 30 - pplDensity: 60 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 40 - pplDensity: 90 - - geohash: ezdqemu - dataType: NO_DATA - - startTime: '2024-01-03T11:00:00Z' - endTime: '2024-01-03T12:00:00Z' - cellPopulationDensityData: - - geohash: ezdqemf - dataType: DENSITY_ESTIMATION - maxPplDensity: 100 - minPplDensity: 30 - pplDensity: 70 - - geohash: ezdqemg - dataType: DENSITY_ESTIMATION - maxPplDensity: 200 - minPplDensity: 40 - pplDensity: 100 - - geohash: ezdqemu - dataType: NO_DATA - operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 - PopulationDensityAreaNotSupportedAsyncResponseExample: - description: Population density area not supported async response example - value: - status: AREA_NOT_SUPPORTED - timedPopulationDensityData: [] - operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 - PopulationDensityOperationNotCompletedExample: - description: Population density operation not completed example - value: - status: OPERATION_NOT_COMPLETED - timedPopulationDensityData: [] - statusInfo: Some error happened during the processing of the request - operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 +openapi: 3.0.3 +info: + title: Population Density Data + description: | + The Population Density Data API provides estimated population density information for a specified geographic area and time interval. + + # Introduction + + The Population Density Data API allows API Consumers to retrieve anonymized estimations of the number of people per square kilometer in the given area in the time interval on an hourly basis. The resulting data is prepared by the API Provider, either derived from historical network data or using prediction algorithms. The API supports both synchronous and asynchronous processing depending on the size and complexity of the request. + + - The defined **area** is either a polygon (a list of geographical coordinates) or a list of geohashes + - The provided **time interval** is either a fully past or a fully future time interval. + - The resulting estimations are derived from anonymized historical device‑based information and predictive models. Returned values include the estimated population density (number of people) for each cell in the requested **area** and each hourly timeslot in the requested **time interval**, as well as an estimation density range [minimum, maximum]. The exact interpretation of minimum and maximum depends on the API Provider's underlying estimation algorithm. + + This API supports a wide range of use cases, including but not limited to: + + - **BVLOS (Beyond Visual Line of Sight) drone operations**, providing information required for SORA 2.5 intrinsic Ground Risk Class (iGRC) assessments. See [Specific Operations Risk Assessment](https://www.easa.europa.eu/en/domains/civil-drones-rpas/specific-category-civil-drones/specific-operations-risk-assessment-sora) + - **Drone flight planning**, enabling to determine whether the ground risk class at a given time is acceptable or whether alternative times should be considered. + - **Sustainable urban planning**, supporting analysis of population distribution patterns. + - **Environmental and safety monitoring** during large events such as concerts, festivals, or public gatherings. + + These examples illustrate typical applications, but the API can be used in many other scenarios where population density estimation is relevant. + + # Relevant Terms and Definitions + + **Population Density** + Number of people at a given time in a given area expressed as an integer value. + + **Area Types** + - **POLYGON**: Area defined by a list of latitude/longitude points forming a simple polygon. The polygon is subdivided into a grid of equal-sized cells. The number of cells in the grid is dependent on the requested precision. + - **GEOHASHLIST**: Area defined as a list of geohash strings. Geohashes may be individual, non‑contiguous geographical areas each with their own (possibly different) precision. + + **Grid Cell** + A subdivision of the requested area. + + - For polygon areas, the API generates equal‑sized grid cells based on the requested precision, by mapping each polygon coordinate to a geohash at the requested precision level. + - For geohash lists, each geohash corresponds to a single cell at the requested precision level. + + **Geohash** + A geohash is a string-encoded representation of a geographical area/point on the globe. The (32-base) geohash model represents the globe as a grid of 32 fixed rectangular areas, referred to as cells. Each cell is identified by a single letter or digit. Zooming in to one cell (recursively) gives a more granular (or higher precision) 32-cell grid at the next level with each cell again identified by a single letter or digit. The geohash is a string that identifies a cell at a given zoom level by concatenating the identifiers of all previous level grid cells selected. The deeper the zoom, the longer the string and the higher the granularity/precision of the cell. The maximum zoom/precision level in this system is 12. The length (number of characters) of the geohash indicates its precision (zoom level/granularity). For examples, see [here](https://esp.info/geohash) or [here](https://www.geohash.es/encode). + + **Precision** + Defines the granularity level of grid cells. + + - **POLYGON**: For polygon areas, the precision level 7 is used by default. I.e. a grid is generated for the polygon by creating a list of geohashes, one for each of the coordinates of the provided polygon at zoom level 7. NOTE: several very close polygon coordinates may map into the same geohash. + - **GEOHASHLIST**: For geohash lists, each geohash’s own length determines its precision. Example: the geohash for Spain is "e" at precision level 1; the geohash for Madrid (2 cell zoom levels deeper) is "ezj" at precision level 3. Further zooming adds more characters to the geohash, each time identifying a smaller rectangular area on the globe. + + **MNO Coverage Area** + The geographic area where the Mobile Network Operator (MNO) provides connectivity services. Cells outside this area are returned with `dataType = NO_DATA`. + + **Population Density Data API call result: DataType** + - **DENSITY_ESTIMATION**: Population density estimation is available. + - **LOW_DENSITY**: Insufficient anonymized data due to k‑anonymity constraints; no density estimation is returned. + - **NO_DATA**: The cell lies outside the MNO coverage area. + + **k‑Anonymity** + A privacy mechanism ensuring that data cannot be attributed to fewer than *k* individuals. If insufficient data exists for a cell/time interval, the API returns `LOW_DENSITY`. + + **Synchronous vs Asynchronous Processing** + - **Synchronous**: The API returns the result immediately in the response. + - **Asynchronous**: For large requests or when explicitly requested via `sink`, the API returns a 202 response with an `operationId` and later delivers the result to the callback URL, including the same `operationId`. + + **OperationId** + A unique identifier correlating an asynchronous request with its callback notification. + + **Callback URL and Token** + A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, the client should also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. + + # API Functionality + + To retrieve population density data, the API consumer specifies: + 1. The area (polygon or geohash list) + 2. The precision (only for polygon areas) + 3. A fully past or fully future time interval + + The API returns a sequence of hourly time slots covering the specified interval (adjusted to the begin and end full hour boundaries). Each time slot contains population density data result for all the grid cells covering the requested area. + + - For polygon areas, the API implementation subdivides the polygon into equal‑sized grid cells based on the precision requested in the API call. If not specified in the request, a default precision level 7 is used. + - For geohash lists, each geohash corresponds to a single cell, and the `precision` property must not be included in the API call. + + Population density values are estimated using historical data, prediction models, and population estimation algorithms. The allowed time interval is constrained: + - The minimum allowed `startTime` is up to 3 months before the request time. + - The maximum allowed `endTime` is up to 3 months after the request time. + - The difference between `startTime` and `endTime` must not exceed 7 days (168 hours). + + Polygon areas must meet certain constraints: + - Maximum polygon area size (implementation‑specific). + - Must have a minimum of 3 and can have a maximum of 15 geographical points defining the polygon. + - Must lie at least partially within the MNO coverage area; otherwise, an empty array is returned. + + For geohash lists: + - Support for `GEOHASHLIST` is optional for MNOs. + - Geohashes may be non‑contiguous and have varying precision. + - Unsupported geohash precisions result in `UNSUPPORTED_PRECISION`. + - Geohashes outside coverage are returned with `NO_DATA`. + - If all geohashes are outside coverage, the response status is `AREA_NOT_SUPPORTED`. + + The API normally behaves synchronously. However, large requests may trigger asynchronous processing. Clients may enforce asynchronous behavior by providing a `sink` callback URL. If asynchronous processing is not supported, the API returns `UNSUPPORTED_ASYNC_RESPONSE`. + + Three mutually exclusive `422` errors indicate why a request cannot be served: + - **UNSUPPORTED_ASYNC_RESPONSE**: Asynchronous processing is not supported. + - **UNSUPPORTED_SYNC_RESPONSE**: Request too large for synchronous processing and asynchronous processing is not enabled. + - **UNSUPPORTED_REQUEST**: Request too large for both synchronous and asynchronous processing. + + If an error occurs during asynchronous processing, the callback includes `status = OPERATION_NOT_COMPLETED` and a `statusInfo` field with additional details. + + **Privacy Note** + To ensure anonymization, if data for a cell/time interval does not meet k‑anonymity requirements, the API returns `LOW_DENSITY` for that cell. + + # Resources and Operations Overview + + The API exposes a single POST endpoint for retrieving population density data for a specified area and time interval. + The API call result is an array of hourly timeslots (`timedPopulationDensityData`), with per timeslot an array of cells (`cellPopulationDensityData`), with for each cell the resulting `DataType` with the density data result. If data is available, the result `DataType` is **DENSITY_ESTIMATION**, and the estimated density data is a number of estimated people in the cell in the timeslot, as well as minimum and maximum estimated values. Other possible results are indicated by different DataTypes. The 3 possible results are as follows: + + - **DENSITY_ESTIMATION**: Population density estimation is available. + - **LOW_DENSITY**: Insufficient anonymized data due to k‑anonymity constraints; no density estimation is returned. + - **NO_DATA**: The cell lies outside the MNO coverage area. + + **Callback URL and token** + Developers may provide a callback URL (`sink`) for receiving an asynchronous response. This is an optional parameter. If `sink` is included, it is RECOMMENDED for the client to provide as well the `sinkCredential` property to protect the notification endpoint. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. + + - When an asynchronous response is requested (using `sink`), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. + + - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the contained provider's `jwksUri` is never conveyed in the response. The `/retrieve` operation creates no resource to read back. The same static `jwksUri` is returned on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. + + + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. + + The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. + + In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. + + + For this API, only anonymized data is processed, and no personal data is exposed. Therefore, access is granted using the Client Credentials (2‑legged) flow. + + + + # Additional CAMARA error responses + + The list of error codes in this API specification is not exhaustive. Therefore the API specification MAY not document some non-mandatory error statuses as indicated in `CAMARA API Design Guide`. + + Please refer to the `CAMARA_common.yaml` of the Commonalities Release associated to this API version for a complete list of error responses. The applicable Commonalities Release can be identified from the `x-camara-commonalities` field, the changelog and the metadata of the released API version. + + As a specific rule, error `501 - NOT_IMPLEMENTED` can be only a possible error response if it is explicitly documented in the API. + + + + + # Request body strictness + + This API rejects requests with JSON request bodies that contain properties not declared in this specification, at any nesting level. Unknown properties result in a `400 INVALID_ARGUMENT` response. + + + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: wip + + x-camara-commonalities: 0.9.0 +externalDocs: + description: Product documentation at CAMARA. + url: https://github.com/camaraproject/PopulationDensityData + +servers: + - url: '{apiRoot}/population-density-data/vwip' + + variables: + apiRoot: + default: http://localhost:9091 + description: API root +tags: + - name: Population Density Data + description: Operations to retrieve population density information. +paths: + /retrieve: + post: + tags: + - Population Density Data + summary: Retrieves population density information in a specified area + description: >- + Retrieves population density estimations for a specified area (polygon or geohash list) + and time interval. The response is a sequence of hourly time slots, each containing + estimated population density data for the grid cells covering the requested area. + operationId: retrievePopulationDensity + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PopulationDensityRequest' + example: + area: + areaType: POLYGON + boundary: + - latitude: 45.754114 + longitude: 4.860374 + - latitude: 45.753845 + longitude: 4.863185 + - latitude: 45.75249 + longitude: 4.861876 + - latitude: 45.751224 + longitude: 4.861125 + - latitude: 45.751442 + longitude: 4.859827 + startTime: '2024-04-23T14:44:18.165Z' + endTime: '2024-04-23T14:44:18.165Z' + precision: 7 + required: true + callbacks: + populationDensityDataCallback: + '{$request.body#/sink}': + post: + tags: + - Population Density Data + summary: 'Population Density Data callback' + description: | + Important: this endpoint is to be implemented by the API consumer. + The Population Density Data server will call this endpoint when the request result is ready. + operationId: postNotification + parameters: + - $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" + requestBody: + description: Population density data result. + content: + application/json: + schema: + $ref: '#/components/schemas/PopulationDensityAsyncResponse' + examples: + PopulationDensitySupportedAreaAsyncResponseExample: + $ref: '#/components/examples/PopulationDensitySupportedAreaAsyncResponseExample' + PopulationDensityAreaNotSupportedAsyncResponseExample: + $ref: '#/components/examples/PopulationDensityAreaNotSupportedAsyncResponseExample' + PopulationDensityPartOfAreaNotSupportedAsyncResponseExample: + $ref: '#/components/examples/PopulationDensityPartOfAreaNotSupportedAsyncResponseExample' + PopulationDensityOperationNotCompletedExample: + $ref: '#/components/examples/PopulationDensityOperationNotCompletedExample' + responses: + '204': + description: Successful notification + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + '400': + $ref: '../common/CAMARA_common.yaml#/components/responses/BadRequest400' + '401': + $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' + '403': + $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' + '410': + $ref: '../common/CAMARA_event_common.yaml#/components/responses/SinkGone410' + '429': + $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' + security: + - {} + - notificationsBearerAuth: [] + responses: + '200': + description: Population density data result. + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: '#/components/schemas/PopulationDensityResponse' + examples: + PopulationDensitySupportedAreaResponseExample: + $ref: '#/components/examples/PopulationDensitySupportedAreaResponseExample' + PopulationDensityAreaNotSupportedResponseExample: + $ref: '#/components/examples/PopulationDensityAreaNotSupportedResponseExample' + PopulationDensityPartOfAreaNotSupportedResponseExample: + $ref: '#/components/examples/PopulationDensityPartOfAreaNotSupportedResponseExample' + + '202': + description: Population density data requested. This response is returned when the behaviour of the API is asynchronous. + headers: + x-correlator: + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: '#/components/schemas/AcceptedAsyncResponse' + '400': + $ref: '#/components/responses/RetrieveLocationBadRequest400' + '401': + $ref: '../common/CAMARA_common.yaml#/components/responses/Unauthenticated401' + '403': + $ref: '../common/CAMARA_common.yaml#/components/responses/PermissionDenied403' + '422': + $ref: '#/components/responses/RetrieveLocationUnprocessableContent422' + '429': + $ref: '../common/CAMARA_common.yaml#/components/responses/TooManyRequests429' + security: + - openId: + - population-density-data:read +components: + securitySchemes: + openId: + $ref: "../common/CAMARA_common.yaml#/components/securitySchemes/openId" + notificationsBearerAuth: + $ref: "../common/CAMARA_event_common.yaml#/components/securitySchemes/notificationsBearerAuth" + schemas: + PopulationDensityRequest: + type: object + description: >- + Request object for retrieving population density data in a + specified area. + **NOTE**: The difference between `startTime` and `endTime` cannot be greater than 7 days. + additionalProperties: false + properties: + area: + $ref: '#/components/schemas/Area' + startTime: + $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + endTime: + $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + precision: + type: integer + format: int32 + description: >- + Precision required of response cells. Precision defines a geohash level and corresponds to the length of the geohash for each cell. More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). + If not included the default precision level 7 is used by default. + Values within the schema range (1–12) that are not supported by the MNO return the error response `422 POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION`. Values outside the schema range are invalid per the OpenAPI definition and return `400 INVALID_ARGUMENT` via request validation. + This property MUST only be set when `area.areaType` is `POLYGON`, if not included the default precision level 7 is used. When `area.areaType` is `GEOHASHLIST`, each requested geohash determines the granularity of its own response cell; if `precision` is sent, the API returns a `400 INVALID_ARGUMENT` error. + minimum: 1 + maximum: 12 + default: 7 + sink: + description: | + The address where the API response will be asynchronously delivered, using the HTTP protocol. + Providing `sink` enforces the asynchronous behaviour of the API. If the API provider does not + support asynchronous processing, the request MUST be rejected with the error response + `422 POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE` and no callback is delivered. + The API consumer can then retry the request without `sink` to obtain a synchronous response. + allOf: + - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/Sink" + sinkCredential: + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" + required: + - area + - startTime + - endTime + Area: + description: Base schema for all areas + type: object + properties: + areaType: + $ref: "#/components/schemas/AreaType" + required: + - areaType + discriminator: + propertyName: areaType + mapping: + POLYGON: "#/components/schemas/Polygon" + GEOHASHLIST: "#/components/schemas/GeohashList" + AreaType: + type: string + description: | + Type of this area. + POLYGON - The area is defined as a polygon. + GEOHASHLIST - The area is defined as a list of geohashes. + enum: + - POLYGON + - GEOHASHLIST + Polygon: + description: Polygonal area. The Polygon should be a simple polygon, i.e. should not intersect itself. + allOf: + - $ref: "#/components/schemas/Area" + - type: object + required: + - boundary + properties: + boundary: + $ref: "../common/CAMARA_common.yaml#/components/schemas/PointList" + GeohashList: + description: >- + Area defined as a list of geohashes. Geohashes do not need to be adjacent or contiguous and may have different precision levels (string lengths), as long as the MNO supports all of them. The `precision` request property MUST NOT be set when `areaType` is `GEOHASHLIST`; if set, the API returns a `400 INVALID_ARGUMENT` error. + allOf: + - $ref: "#/components/schemas/Area" + - type: object + required: + - geohashes + properties: + geohashes: + type: array + description: List of geohashes that define the area of interest. + minItems: 1 + maxItems: 1000 + items: + $ref: "#/components/schemas/Geohash" + Geohash: + type: string + description: >- + Geohash string identifying a cell using the [Geohash system](https://en.wikipedia.org/wiki/Geohash), + encoding a geographic location into a short string. Characters are taken from the + base-32 geohash alphabet (`0-9` and `b-z` excluding `a`, `i`, `l`, `o`). + The length of the string determines the cell granularity (precision). + pattern: ^[0-9bcdefghjkmnpqrstuvwxyz]{1,12}$ + maxLength: 12 + example: ezdmemd + PopulationDensityResponse: + type: object + description: >- + Population density data represented as hourly time intervals for the + cells of the requested area. Each element in `timedPopulationDensityData` array corresponds + to a one-hour time interval, containing population density data for the grid cells. + properties: + timedPopulationDensityData: + type: array + description: >- + Time ranges along with the population density data for the cells within it. + The request startTime or the request endTime have to be fully covered by the intervals. + For example, if the intervals are 1-hour long and the input date range were [2024-01-03T11:25:00Z + to 2024-01-03T12:45:00Z] it would contain 2 intervals (Interval from 2024-01-03T11:00:00Z + to 2024-01-03T12:00:00Z and interval from 2024-01-03T12:00:00Z to 2024-01-03T13:00:00Z). + items: + $ref: '#/components/schemas/TimedPopulationDensityData' + maxItems: 168 + status: + $ref: '#/components/schemas/ResponseStatus' + statusInfo: + type: string + maxLength: 512 + description: Information about the status, mandatory when property `status` is `OPERATION_NOT_COMPLETED` for adding extra information about the error. + example: Some error happened during the processing of the request + required: + - timedPopulationDensityData + - status + AcceptedAsyncResponse: + type: object + description: Accepted asynchronous response + properties: + operationId: + $ref: '#/components/schemas/OperationId' + required: + - operationId + PopulationDensityAsyncResponse: + description: Asynchronous population density data response + allOf: + - $ref: '#/components/schemas/PopulationDensityResponse' + - type: object + properties: + operationId: + $ref: '#/components/schemas/OperationId' + required: + - operationId + OperationId: + type: string + maxLength: 256 + description: The unique identifier of the asynchronous operation that is returned when the operation is initiated. + ResponseStatus: + type: string + description: >- + Represents the state of the response for the input polygon defined in the request, the possible values are: + - `SUPPORTED_AREA`: The whole request area is supported. Population density data for the entire requested area is returned. + - `PART_OF_AREA_NOT_SUPPORTED`: Part of the requested area is outside the MNOs coverage area, the cells outside the coverage + area will have property `dataType` with value `NO_DATA`. + - `AREA_NOT_SUPPORTED`: The whole requested area is outside the MNOs coverage area. No data will be returned. + - `OPERATION_NOT_COMPLETED`: An error happened during asynchronous processing of the request. This status will only be returned + in case the asynchronous API behaviour is used. + enum: + - SUPPORTED_AREA + - PART_OF_AREA_NOT_SUPPORTED + - AREA_NOT_SUPPORTED + - OPERATION_NOT_COMPLETED + TimedPopulationDensityData: + type: object + properties: + startTime: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + - description: Interval start time. + example: "2023-07-03T10:00:00Z" + endTime: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" + - description: Interval end time. + example: "2023-07-03T11:00:00Z" + cellPopulationDensityData: + $ref: '#/components/schemas/CellPopulationDensityDataArray' + required: + - startTime + - endTime + - cellPopulationDensityData + CellPopulationDensityDataArray: + type: array + description: >- + Population density data for the different cells in a concrete time range. + items: + $ref: '#/components/schemas/CellPopulationDensityData' + minItems: 1 + maxItems: 10000 + CellPopulationDensityData: + type: object + description: >- + Population density data of a cell in a concrete time range. In case of + insufficient data, to guarantee an anonymized prediction due to the + k-anonymity within a specific cell and time range, no population density + data is returned and the property `dataType` value is "LOW_DENSITY". In + case of a cell not supported `dataType` value is "NO_DATA" + properties: + geohash: + $ref: '#/components/schemas/Geohash' + dataType: + type: string + enum: + - NO_DATA + - LOW_DENSITY + - DENSITY_ESTIMATION + required: + - geohash + - dataType + discriminator: + propertyName: dataType + mapping: + NO_DATA: '#/components/schemas/NoData' + LOW_DENSITY: '#/components/schemas/LowDensity' + DENSITY_ESTIMATION: '#/components/schemas/DensityEstimation' + NoData: + allOf: + - $ref: '#/components/schemas/CellPopulationDensityData' + LowDensity: + allOf: + - $ref: '#/components/schemas/CellPopulationDensityData' + DensityEstimation: + allOf: + - $ref: '#/components/schemas/CellPopulationDensityData' + - type: object + properties: + maxPplDensity: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Maximum estimated number of people for the cell. + minPplDensity: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Minimum estimated number of people for the cell. + pplDensity: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Estimated number of people for the cell. + required: + - maxPplDensity + - minPplDensity + - pplDensity + responses: + RetrieveLocationBadRequest400: + description: >- + Problem with the client request. In addition to generic scenarios of + `INVALID_ARGUMENT`, `INVALID_CREDENTIAL`, `INVALID_TOKEN`, another scenarios may exist: + - The area is not a polygon shape or exceeds supported complexity ("code": "POPULATION_DENSITY_DATA.INVALID_AREA", "message": "The area is not a polygon shape or exceeds supported complexity") + - Indicated `startTime` is greater than the maximum allowed ("code": "POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED", "message": "Indicated startTime is greater than the maximum allowed") + - Indicated `startTime` is earlier than the minimum allowed ("code": "POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED", "message": "Indicated startTime is earlier than the minimum allowed") + - Indicated `endTime` is earlier than the `startTime` ("code": "POPULATION_DENSITY_DATA.INVALID_END_TIME", "message": "Indicated endTime is earlier than the startTime") + - Indicated time period is partially in the past and partially in the future ("code": "POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD", "message": "time period is partially in the past and partially in the future") + - Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime) ("code": "POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED", "message": "Indicated time period is greater than the maximum allowed (More than maximum hours between startTime and endTime)") + headers: + x-correlator: + $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - INVALID_CREDENTIAL + - INVALID_TOKEN + - INVALID_SINK + - POPULATION_DENSITY_DATA.INVALID_AREA + - POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED + - POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED + - POPULATION_DENSITY_DATA.INVALID_END_TIME + - POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED + - POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD + examples: + GENERIC_400_INVALID_ARGUMENT: + $ref: "../common/CAMARA_common.yaml#/components/examples/GENERIC_400_INVALID_ARGUMENT" + GENERIC_400_INVALID_CREDENTIAL: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_CREDENTIAL" + GENERIC_400_INVALID_TOKEN: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_TOKEN" + GENERIC_400_INVALID_SINK: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_400_INVALID_SINK" + POPULATION_DENSITY_DATA_400_INVALID_AREA: + value: + status: 400 + code: POPULATION_DENSITY_DATA.INVALID_AREA + message: The area is not a polygon shape or has an arbitrary complexity + POPULATION_DENSITY_DATA_400_MAX_STARTTIME_EXCEEDED: + value: + status: 400 + code: POPULATION_DENSITY_DATA.MAX_STARTTIME_EXCEEDED + message: >- + Indicated startTime is greater than the maximum allowed + POPULATION_DENSITY_DATA_400_MIN_STARTTIME_EXCEEDED: + value: + status: 400 + code: POPULATION_DENSITY_DATA.MIN_STARTTIME_EXCEEDED + message: >- + Indicated startTime is earlier than the minimum allowed + POPULATION_DENSITY_DATA_400_INVALID_END_TIME: + value: + status: 400 + code: POPULATION_DENSITY_DATA.INVALID_END_TIME + message: Indicated endDate is earlier than the startTime + POPULATION_DENSITY_DATA_400_MAX_TIME_PERIOD_EXCEEDED: + value: + status: 400 + code: POPULATION_DENSITY_DATA.MAX_TIME_PERIOD_EXCEEDED + message: >- + Indicated time period is greater than the maximum allowed + (More than maximum hours between startTime and endTime) + POPULATION_DENSITY_DATA_400_INVALID_TIME_PERIOD: + value: + status: 400 + code: POPULATION_DENSITY_DATA.INVALID_TIME_PERIOD + message: >- + Indicated time period is partially in the past and partially in the future + + RetrieveLocationUnprocessableContent422: + description: >- + Problem with the client request. The following scenarios may exist: + - Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing, so providing `sink` does not help ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST", "message": "Indicated combination of area, time interval and precision is too big") + - Indicated cell precision (Geohash level) is not supported ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION", "message": "Indicated cell precision (Geohash level) is not supported") + - Indicated combination of area, time interval and precision is too big for a sync response and asynchronous processing is not enabled ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE", "message": "Indicated combination of area, time interval and precision is too big for a sync response") + - `sink` is provided but the API provider does not support asynchronous processing at all, whatever the size of the request ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE", "message": "The API provider does not support the asynchronous processing") + - The requested `areaType` is not supported by the MNO ("code": "POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE", "message": "The requested areaType is not supported by the MNO") + - `sinkCredential.credentialType` is set to `PRIVATE_KEY_JWT` but no JWK Set is configured for the API consumer ("code": "PRIVATE_KEY_JWT_NOT_CONFIGURED", "message": "No JWK Set configured for PRIVATE_KEY_JWT authentication.") + headers: + x-correlator: + $ref: '../common/CAMARA_common.yaml#/components/headers/x-correlator' + content: + application/json: + schema: + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST + - POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION + - POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE + - POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE + - POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE + - PRIVATE_KEY_JWT_NOT_CONFIGURED + examples: + POPULATION_DENSITY_DATA_422_UNSUPPORTED_REQUEST: + description: >- + The request is too big to be processed even asynchronously, so retrying it with sink does not + help. Only a smaller request does + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST + message: Indicated combination of area, time interval and precision is too big for both synchronous and asynchronous processing + POPULATION_DENSITY_DATA_422_UNSUPPORTED_PRECISION: + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION + message: >- + Indicated cell precision (Geohash length) is not supported + POPULATION_DENSITY_DATA_422_UNSUPPORTED_SYNC_RESPONSE: + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE + message: >- + Indicated combination of area, time interval and precision is too big for synchronous processing + and asynchronous processing is not enabled + POPULATION_DENSITY_DATA_422_UNSUPPORTED_AREA_TYPE: + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE + message: The requested areaType is not supported by the MNO + POPULATION_DENSITY_DATA_422_UNSUPPORTED_ASYNC_RESPONSE: + description: >- + The API consumer requested the asynchronous behaviour by providing sink, but the API provider + does not support asynchronous processing. Unlike UNSUPPORTED_REQUEST, this error does not depend + on the size of the request + value: + status: 422 + code: POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE + message: The API provider does not support the asynchronous processing + GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: + $ref: "../common/CAMARA_event_common.yaml#/components/examples/GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED" + examples: + PopulationDensitySupportedAreaResponseExample: + description: Population density supported area response example + value: + status: SUPPORTED_AREA + timedPopulationDensityData: + - startTime: '2024-01-03T10:00:00Z' + endTime: '2024-01-03T11:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 150 + minPplDensity: 30 + pplDensity: 60 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 40 + pplDensity: 90 + - geohash: ezdqemu + dataType: LOW_DENSITY + - startTime: '2024-01-03T11:00:00Z' + endTime: '2024-01-03T12:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 30 + pplDensity: 70 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + - geohash: ezdqemu + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + PopulationDensityPartOfAreaNotSupportedResponseExample: + description: Population density part of area not supported response example + value: + status: PART_OF_AREA_NOT_SUPPORTED + timedPopulationDensityData: + - startTime: '2024-01-03T10:00:00Z' + endTime: '2024-01-03T11:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 150 + minPplDensity: 30 + pplDensity: 60 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 40 + pplDensity: 90 + - geohash: ezdqemu + dataType: NO_DATA + - startTime: '2024-01-03T11:00:00Z' + endTime: '2024-01-03T12:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 30 + pplDensity: 70 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + - geohash: ezdqemu + dataType: NO_DATA + PopulationDensityAreaNotSupportedResponseExample: + description: Population density area not supported response example + value: + status: AREA_NOT_SUPPORTED + timedPopulationDensityData: [] + PopulationDensitySupportedAreaAsyncResponseExample: + description: Population density supported area async response example + value: + status: SUPPORTED_AREA + timedPopulationDensityData: + - startTime: '2024-01-03T10:00:00Z' + endTime: '2024-01-03T11:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 150 + minPplDensity: 30 + pplDensity: 60 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 40 + pplDensity: 90 + - geohash: ezdqemu + dataType: LOW_DENSITY + - startTime: '2024-01-03T11:00:00Z' + endTime: '2024-01-03T12:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 30 + pplDensity: 70 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + - geohash: ezdqemu + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 + PopulationDensityPartOfAreaNotSupportedAsyncResponseExample: + description: Population density part of area not supported async response example + value: + status: PART_OF_AREA_NOT_SUPPORTED + timedPopulationDensityData: + - startTime: '2024-01-03T10:00:00Z' + endTime: '2024-01-03T11:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 150 + minPplDensity: 30 + pplDensity: 60 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 40 + pplDensity: 90 + - geohash: ezdqemu + dataType: NO_DATA + - startTime: '2024-01-03T11:00:00Z' + endTime: '2024-01-03T12:00:00Z' + cellPopulationDensityData: + - geohash: ezdqemf + dataType: DENSITY_ESTIMATION + maxPplDensity: 100 + minPplDensity: 30 + pplDensity: 70 + - geohash: ezdqemg + dataType: DENSITY_ESTIMATION + maxPplDensity: 200 + minPplDensity: 40 + pplDensity: 100 + - geohash: ezdqemu + dataType: NO_DATA + operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 + PopulationDensityAreaNotSupportedAsyncResponseExample: + description: Population density area not supported async response example + value: + status: AREA_NOT_SUPPORTED + timedPopulationDensityData: [] + operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 + PopulationDensityOperationNotCompletedExample: + description: Population density operation not completed example + value: + status: OPERATION_NOT_COMPLETED + timedPopulationDensityData: [] + statusInfo: Some error happened during the processing of the request + operationId: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 From d0e723e729041880a17f0df6581114bdbc26431c Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Thu, 1 Oct 2026 12:37:54 +0200 Subject: [PATCH 3/8] Clarify population density, geohash handling, errors, and API behavior --- .../population-density-data.yaml | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index d66115f..59a8d99 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -6,11 +6,11 @@ info: # Introduction - The Population Density Data API allows API Consumers to retrieve anonymized estimations of the number of people per square kilometer in the given area in the time interval on an hourly basis. The resulting data is prepared by the API Provider, either derived from historical network data or using prediction algorithms. The API supports both synchronous and asynchronous processing depending on the size and complexity of the request. + The Population Density Data API allows API Consumers to retrieve anonymized estimations of the number of people in each grid cell of in the given area in the time interval on an hourly basis. The resulting data is prepared by the API Provider, either derived from historical network data or using prediction algorithms. The API supports both synchronous and asynchronous processing depending on the size and complexity of the request. - The defined **area** is either a polygon (a list of geographical coordinates) or a list of geohashes - The provided **time interval** is either a fully past or a fully future time interval. - - The resulting estimations are derived from anonymized historical device‑based information and predictive models. Returned values include the estimated population density (number of people) for each cell in the requested **area** and each hourly timeslot in the requested **time interval**, as well as an estimation density range [minimum, maximum]. The exact interpretation of minimum and maximum depends on the API Provider's underlying estimation algorithm. + - The resulting estimations are derived from anonymized historical device‑based information and predictive models. Returned values include the estimated population density (number of people) for each cell in the requested **area** and each hourly timeslot in the requested **time interval**, as well as an estimation density range [minimum, maximum]. The minimum and maximum are the lower and upper bounds of the range within which the actual number of people is expected to be (e.g. a confidence interval), so that minimum <= estimated value <= maximum. The exact statistical method depends on the API Provider's underlying estimation algorithm. This API supports a wide range of use cases, including but not limited to: @@ -24,37 +24,37 @@ info: # Relevant Terms and Definitions **Population Density** - Number of people at a given time in a given area expressed as an integer value. + Estimated number of people in a grid cell during a one-hour time slot, expressed as an integer value. It is a number of people per cell, not a value per square kilometer. **Area Types** - **POLYGON**: Area defined by a list of latitude/longitude points forming a simple polygon. The polygon is subdivided into a grid of equal-sized cells. The number of cells in the grid is dependent on the requested precision. - - **GEOHASHLIST**: Area defined as a list of geohash strings. Geohashes may be individual, non‑contiguous geographical areas each with their own (possibly different) precision. + - **GEOHASHLIST**: Area defined as a list of geohash strings. Geohashes may be individual, non-contiguous geographical areas each with their own (possibly different) precision. **Grid Cell** A subdivision of the requested area. - - For polygon areas, the API generates equal‑sized grid cells based on the requested precision, by mapping each polygon coordinate to a geohash at the requested precision level. + - For polygon areas, the grid is the set of geohash cells, at the applicable precision level, that cover the polygon. All cells have the same precision level and therefore the same size in degrees of latitude and longitude. - For geohash lists, each geohash corresponds to a single cell at the requested precision level. **Geohash** - A geohash is a string-encoded representation of a geographical area/point on the globe. The (32-base) geohash model represents the globe as a grid of 32 fixed rectangular areas, referred to as cells. Each cell is identified by a single letter or digit. Zooming in to one cell (recursively) gives a more granular (or higher precision) 32-cell grid at the next level with each cell again identified by a single letter or digit. The geohash is a string that identifies a cell at a given zoom level by concatenating the identifiers of all previous level grid cells selected. The deeper the zoom, the longer the string and the higher the granularity/precision of the cell. The maximum zoom/precision level in this system is 12. The length (number of characters) of the geohash indicates its precision (zoom level/granularity). For examples, see [here](https://esp.info/geohash) or [here](https://www.geohash.es/encode). + A geohash is a string-encoded representation of a geographical area/point on the globe. The (32-base) geohash model represents the globe as a grid of 32 fixed rectangular areas, referred to as cells. Each cell is identified by a single letter or digit. Zooming in to one cell (recursively) gives a more granular (or higher precision) 32-cell grid at the next level with each cell again identified by a single letter or digit. The geohash is a string that identifies a cell at a given zoom level by concatenating the identifiers of all previous level grid cells selected. The deeper the zoom, the longer the string and the higher the granularity/precision of the cell. The maximum zoom/precision level supported by this API is 12. The length (number of characters) of the geohash indicates its precision (zoom level/granularity). More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). **Precision** Defines the granularity level of grid cells. - - **POLYGON**: For polygon areas, the precision level 7 is used by default. I.e. a grid is generated for the polygon by creating a list of geohashes, one for each of the coordinates of the provided polygon at zoom level 7. NOTE: several very close polygon coordinates may map into the same geohash. - - **GEOHASHLIST**: For geohash lists, each geohash’s own length determines its precision. Example: the geohash for Spain is "e" at precision level 1; the geohash for Madrid (2 cell zoom levels deeper) is "ezj" at precision level 3. Further zooming adds more characters to the geohash, each time identifying a smaller rectangular area on the globe. + - **POLYGON**: For polygon areas, the precision level is given by the `precision` request property. If `precision` is not included, the default precision level 7 is used. I.e. a grid is generated for the polygon with all the geohash cells at that precision level that cover the polygon. As a reference, a cell is approximately 1.2 km x 0.6 km at level 6, 153 m x 153 m at level 7 and 38 m x 19 m at level 8. + - **GEOHASHLIST**: For geohash lists, each geohash's own length determines its precision. Example: the geohash "e" at precision level 1 covers a large area that includes most of Spain; the geohash "ezj" (2 cell zoom levels deeper) at precision level 3 is a cell that contains Madrid. Further zooming adds more characters to the geohash, each time identifying a smaller rectangular area on the globe. **MNO Coverage Area** The geographic area where the Mobile Network Operator (MNO) provides connectivity services. Cells outside this area are returned with `dataType = NO_DATA`. **Population Density Data API call result: DataType** - **DENSITY_ESTIMATION**: Population density estimation is available. - - **LOW_DENSITY**: Insufficient anonymized data due to k‑anonymity constraints; no density estimation is returned. + - **LOW_DENSITY**: Insufficient anonymized data due to k-anonymity constraints; no density estimation is returned. - **NO_DATA**: The cell lies outside the MNO coverage area. - **k‑Anonymity** - A privacy mechanism ensuring that data cannot be attributed to fewer than *k* individuals. If insufficient data exists for a cell/time interval, the API returns `LOW_DENSITY`. + **k-Anonymity** + A privacy mechanism ensuring that data cannot be attributed to fewer than *k* individuals (see [k-anonymity](https://en.wikipedia.org/wiki/K-anonymity)). If insufficient data exists for a cell/time interval, the API returns `LOW_DENSITY`. **Synchronous vs Asynchronous Processing** - **Synchronous**: The API returns the result immediately in the response. @@ -64,7 +64,7 @@ info: A unique identifier correlating an asynchronous request with its callback notification. **Callback URL and Token** - A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, the client should also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. + A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, it is RECOMMENDED for the client to also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. # API Functionality @@ -75,7 +75,7 @@ info: The API returns a sequence of hourly time slots covering the specified interval (adjusted to the begin and end full hour boundaries). Each time slot contains population density data result for all the grid cells covering the requested area. - - For polygon areas, the API implementation subdivides the polygon into equal‑sized grid cells based on the precision requested in the API call. If not specified in the request, a default precision level 7 is used. + - For polygon areas, the API implementation subdivides the polygon into equal-sized grid cells based on the precision requested in the API call. If not specified in the request, a default precision level 7 is used. - For geohash lists, each geohash corresponds to a single cell, and the `precision` property must not be included in the API call. Population density values are estimated using historical data, prediction models, and population estimation algorithms. The allowed time interval is constrained: @@ -84,28 +84,28 @@ info: - The difference between `startTime` and `endTime` must not exceed 7 days (168 hours). Polygon areas must meet certain constraints: - - Maximum polygon area size (implementation‑specific). + - Maximum polygon area size (implementation-specific). - Must have a minimum of 3 and can have a maximum of 15 geographical points defining the polygon. - - Must lie at least partially within the MNO coverage area; otherwise, an empty array is returned. + - Must lie at least partially within the MNO coverage area; otherwise, the response has `status` set to `AREA_NOT_SUPPORTED` and no population density data is returned. For geohash lists: - - Support for `GEOHASHLIST` is optional for MNOs. - - Geohashes may be non‑contiguous and have varying precision. - - Unsupported geohash precisions result in `UNSUPPORTED_PRECISION`. + - Support for `POLYGON` is mandatory for all MNOs, while support for `GEOHASHLIST` is optional. If the MNO does not support `GEOHASHLIST`, the API returns `422 POPULATION_DENSITY_DATA.UNSUPPORTED_AREA_TYPE`. + - Geohashes may be non-contiguous and have varying precision. + - Unsupported geohash precisions result in `422 POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION`. - Geohashes outside coverage are returned with `NO_DATA`. - If all geohashes are outside coverage, the response status is `AREA_NOT_SUPPORTED`. - The API normally behaves synchronously. However, large requests may trigger asynchronous processing. Clients may enforce asynchronous behavior by providing a `sink` callback URL. If asynchronous processing is not supported, the API returns `UNSUPPORTED_ASYNC_RESPONSE`. + The API normally behaves synchronously. However, large requests may trigger asynchronous processing. Clients may enforce asynchronous behavior by providing a `sink` callback URL. If asynchronous processing is not supported, the API returns `422 POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE`. - Three mutually exclusive `422` errors indicate why a request cannot be served: - - **UNSUPPORTED_ASYNC_RESPONSE**: Asynchronous processing is not supported. - - **UNSUPPORTED_SYNC_RESPONSE**: Request too large for synchronous processing and asynchronous processing is not enabled. - - **UNSUPPORTED_REQUEST**: Request too large for both synchronous and asynchronous processing. + Three mutually exclusive `422` errors indicate why a request cannot be served. They are evaluated in this order: + - **POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE**: `sink` is provided but asynchronous processing is not supported at all. It does not depend on the size of the request; the API consumer can retry the same request without `sink` to obtain a synchronous response. + - **POPULATION_DENSITY_DATA.UNSUPPORTED_SYNC_RESPONSE**: Request too large for synchronous processing and asynchronous processing is not enabled. A smaller request would succeed. + - **POPULATION_DENSITY_DATA.UNSUPPORTED_REQUEST**: Request too large for both synchronous and asynchronous processing. Retrying with `sink` does not help; only a smaller request does. If an error occurs during asynchronous processing, the callback includes `status = OPERATION_NOT_COMPLETED` and a `statusInfo` field with additional details. **Privacy Note** - To ensure anonymization, if data for a cell/time interval does not meet k‑anonymity requirements, the API returns `LOW_DENSITY` for that cell. + To ensure anonymization, if data for a cell/time interval does not meet k-anonymity requirements, the API returns `LOW_DENSITY` for that cell. # Resources and Operations Overview @@ -113,7 +113,7 @@ info: The API call result is an array of hourly timeslots (`timedPopulationDensityData`), with per timeslot an array of cells (`cellPopulationDensityData`), with for each cell the resulting `DataType` with the density data result. If data is available, the result `DataType` is **DENSITY_ESTIMATION**, and the estimated density data is a number of estimated people in the cell in the timeslot, as well as minimum and maximum estimated values. Other possible results are indicated by different DataTypes. The 3 possible results are as follows: - **DENSITY_ESTIMATION**: Population density estimation is available. - - **LOW_DENSITY**: Insufficient anonymized data due to k‑anonymity constraints; no density estimation is returned. + - **LOW_DENSITY**: Insufficient anonymized data due to k-anonymity constraints; no density estimation is returned. - **NO_DATA**: The cell lies outside the MNO coverage area. **Callback URL and token** @@ -121,7 +121,7 @@ info: - When an asynchronous response is requested (using `sink`), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. - - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the contained provider's `jwksUri` is never conveyed in the response. The `/retrieve` operation creates no resource to read back. The same static `jwksUri` is returned on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. + - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the API provider's `jwksUri` is never conveyed in the response. Unlike an event subscription, the `/retrieve` operation creates no resource to read back, the same static `jwksUri` would be repeated on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. @@ -134,7 +134,7 @@ info: In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. - For this API, only anonymized data is processed, and no personal data is exposed. Therefore, access is granted using the Client Credentials (2‑legged) flow. + For this API, only anonymized data is processed, and no personal data is exposed. Therefore, access is granted using the Client Credentials (2-legged) flow. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the latest detailed specification of this authentication/authorization flow. From d9377f3c0a3a84c9686e60c8246d61b96adc52e3 Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Tue, 6 Oct 2026 13:26:47 +0200 Subject: [PATCH 4/8] Apply batched suggestions from code review Co-authored-by: Tanja de Groot <87864067+tanjadegroot@users.noreply.github.com> --- code/API_definitions/population-density-data.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index 59a8d99..4409157 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -6,7 +6,7 @@ info: # Introduction - The Population Density Data API allows API Consumers to retrieve anonymized estimations of the number of people in each grid cell of in the given area in the time interval on an hourly basis. The resulting data is prepared by the API Provider, either derived from historical network data or using prediction algorithms. The API supports both synchronous and asynchronous processing depending on the size and complexity of the request. + The Population Density Data API allows API Consumers to retrieve anonymized estimations of the number of people in each grid cell of the given area in the time interval on an hourly basis. The resulting data is prepared by the API Provider, either derived from historical network data or using prediction algorithms. The API supports both synchronous and asynchronous processing depending on the size and complexity of the request. - The defined **area** is either a polygon (a list of geographical coordinates) or a list of geohashes - The provided **time interval** is either a fully past or a fully future time interval. @@ -27,7 +27,7 @@ info: Estimated number of people in a grid cell during a one-hour time slot, expressed as an integer value. It is a number of people per cell, not a value per square kilometer. **Area Types** - - **POLYGON**: Area defined by a list of latitude/longitude points forming a simple polygon. The polygon is subdivided into a grid of equal-sized cells. The number of cells in the grid is dependent on the requested precision. + - **POLYGON**: Area defined by a list of latitude/longitude points forming a simple polygon. The polygon is subdivided into a grid of cells. The set of cells for the polygon correspond to the geohashes covering the polygon obtained by applying the requested precision. - **GEOHASHLIST**: Area defined as a list of geohash strings. Geohashes may be individual, non-contiguous geographical areas each with their own (possibly different) precision. **Grid Cell** @@ -117,7 +117,7 @@ info: - **NO_DATA**: The cell lies outside the MNO coverage area. **Callback URL and token** - Developers may provide a callback URL (`sink`) for receiving an asynchronous response. This is an optional parameter. If `sink` is included, it is RECOMMENDED for the client to provide as well the `sinkCredential` property to protect the notification endpoint. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. + API Consumers may provide a callback URL (`sink`) for receiving an asynchronous response. This is an optional parameter. If `sink` is included, it is RECOMMENDED for the API Consumer to provide as well the `sinkCredential` property to protect the callback endpoint. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. - When an asynchronous response is requested (using `sink`), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. @@ -405,9 +405,9 @@ components: PopulationDensityResponse: type: object description: >- - Population density data represented as hourly time intervals for the + Population density data represented as hourly time slots covering the requested time interval for the cells of the requested area. Each element in `timedPopulationDensityData` array corresponds - to a one-hour time interval, containing population density data for the grid cells. + to a one-hour time slot, containing population density data for all the grid cells of the requested ares. properties: timedPopulationDensityData: type: array From 5279f074c9ea92cf7c7fdf39b53471bed61310be Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Tue, 6 Oct 2026 15:43:12 +0200 Subject: [PATCH 5/8] fix: address review comments and align schemas with CAMARA common --- .../population-density-data.yaml | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index 4409157..01d3a4a 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -10,7 +10,7 @@ info: - The defined **area** is either a polygon (a list of geographical coordinates) or a list of geohashes - The provided **time interval** is either a fully past or a fully future time interval. - - The resulting estimations are derived from anonymized historical device‑based information and predictive models. Returned values include the estimated population density (number of people) for each cell in the requested **area** and each hourly timeslot in the requested **time interval**, as well as an estimation density range [minimum, maximum]. The minimum and maximum are the lower and upper bounds of the range within which the actual number of people is expected to be (e.g. a confidence interval), so that minimum <= estimated value <= maximum. The exact statistical method depends on the API Provider's underlying estimation algorithm. + - The resulting estimations are derived from anonymized historical device-based information and predictive models. Returned values include the estimated population density (number of people) for each cell in the requested **area** and each hourly timeslot in the requested **time interval**, as well as an estimation density range [minimum, maximum]. The minimum and maximum are the lower and upper bounds of the range within which the actual number of people is expected to be (e.g. a confidence interval), so that minimum <= estimated value <= maximum. The exact statistical method depends on the API Provider's underlying estimation algorithm. This API supports a wide range of use cases, including but not limited to: @@ -24,16 +24,16 @@ info: # Relevant Terms and Definitions **Population Density** - Estimated number of people in a grid cell during a one-hour time slot, expressed as an integer value. It is a number of people per cell, not a value per square kilometer. + Estimated number of people in a grid cell during a one-hour time slot, expressed as an integer value. **Area Types** - - **POLYGON**: Area defined by a list of latitude/longitude points forming a simple polygon. The polygon is subdivided into a grid of cells. The set of cells for the polygon correspond to the geohashes covering the polygon obtained by applying the requested precision. + - **POLYGON**: Area defined by a list of latitude/longitude points forming a simple polygon. The polygon is subdivided into a grid of cells. The set of cells corresponds to the geohashes, at the requested precision, that cover the polygon. - **GEOHASHLIST**: Area defined as a list of geohash strings. Geohashes may be individual, non-contiguous geographical areas each with their own (possibly different) precision. **Grid Cell** A subdivision of the requested area. - - For polygon areas, the grid is the set of geohash cells, at the applicable precision level, that cover the polygon. All cells have the same precision level and therefore the same size in degrees of latitude and longitude. + - For polygon areas, the grid is the set of geohash cells, at the applicable precision level, that cover the polygon. All cells have the same precision level. - For geohash lists, each geohash corresponds to a single cell at the requested precision level. **Geohash** @@ -61,10 +61,10 @@ info: - **Asynchronous**: For large requests or when explicitly requested via `sink`, the API returns a 202 response with an `operationId` and later delivers the result to the callback URL, including the same `operationId`. **OperationId** - A unique identifier correlating an asynchronous request with its callback notification. + A unique identifier generated by the API Provider to correlate an asynchronous request with its callback notification. It is mandatory in the 202 response and in the callback payload. It differs from `x-correlator` (which is optional, supplied by the API Consumer, and not guaranteed to be present or unique). **Callback URL and Token** - A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, it is RECOMMENDED for the client to also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. + A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, it is RECOMMENDED for the API Consumer to also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. # API Functionality @@ -95,7 +95,7 @@ info: - Geohashes outside coverage are returned with `NO_DATA`. - If all geohashes are outside coverage, the response status is `AREA_NOT_SUPPORTED`. - The API normally behaves synchronously. However, large requests may trigger asynchronous processing. Clients may enforce asynchronous behavior by providing a `sink` callback URL. If asynchronous processing is not supported, the API returns `422 POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE`. + The API normally behaves synchronously. However, large requests may trigger asynchronous processing. API Consumers may enforce asynchronous behavior by providing a `sink` callback URL. If asynchronous processing is not supported, the API returns `422 POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE`. Three mutually exclusive `422` errors indicate why a request cannot be served. They are evaluated in this order: - **POPULATION_DENSITY_DATA.UNSUPPORTED_ASYNC_RESPONSE**: `sink` is provided but asynchronous processing is not supported at all. It does not depend on the size of the request; the API consumer can retry the same request without `sink` to obtain a synchronous response. @@ -110,18 +110,11 @@ info: # Resources and Operations Overview The API exposes a single POST endpoint for retrieving population density data for a specified area and time interval. - The API call result is an array of hourly timeslots (`timedPopulationDensityData`), with per timeslot an array of cells (`cellPopulationDensityData`), with for each cell the resulting `DataType` with the density data result. If data is available, the result `DataType` is **DENSITY_ESTIMATION**, and the estimated density data is a number of estimated people in the cell in the timeslot, as well as minimum and maximum estimated values. Other possible results are indicated by different DataTypes. The 3 possible results are as follows: + The API call result is an array of hourly timeslots (`timedPopulationDensityData`), with per timeslot an array of cells (`cellPopulationDensityData`), with for each cell the resulting `DataType` with the density data result (see the DataType values defined in the Relevant Terms and Definitions section above). - - **DENSITY_ESTIMATION**: Population density estimation is available. - - **LOW_DENSITY**: Insufficient anonymized data due to k-anonymity constraints; no density estimation is returned. - - **NO_DATA**: The cell lies outside the MNO coverage area. - - **Callback URL and token** - API Consumers may provide a callback URL (`sink`) for receiving an asynchronous response. This is an optional parameter. If `sink` is included, it is RECOMMENDED for the API Consumer to provide as well the `sinkCredential` property to protect the callback endpoint. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. - - - When an asynchronous response is requested (using `sink`), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. + When an asynchronous response is requested (using `sink`, see Callback URL and Token in the Relevant Terms and Definitions section above), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload, correlating the asynchronous response with its corresponding request. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. - - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the API provider's `jwksUri` is never conveyed in the response. Unlike an event subscription, the `/retrieve` operation creates no resource to read back, the same static `jwksUri` would be repeated on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. + Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the API provider's `jwksUri` is never conveyed in the response. Unlike an event subscription, the `/retrieve` operation creates no resource to read back, the same static `jwksUri` would be repeated on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. @@ -313,7 +306,7 @@ components: additionalProperties: false properties: area: - $ref: '#/components/schemas/Area' + $ref: '#/components/schemas/GeoArea' startTime: $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" endTime: @@ -324,7 +317,7 @@ components: description: >- Precision required of response cells. Precision defines a geohash level and corresponds to the length of the geohash for each cell. More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). When `area.areaType` is `POLYGON`, if not included the default precision level 7 is used. - Values within the schema range (1–12) that are not supported by the MNO return the error response `422 POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION`. Values outside the schema range are invalid per the OpenAPI definition and return `400 INVALID_ARGUMENT` via request validation. + Values within the schema range (1-12) that are not supported by the MNO return the error response `422 POPULATION_DENSITY_DATA.UNSUPPORTED_PRECISION`. Values outside the schema range are invalid per the OpenAPI definition and return `400 INVALID_ARGUMENT` via request validation. This property MUST only be set when `area.areaType` is `POLYGON`. When `area.areaType` is `GEOHASHLIST`, each requested geohash determines the granularity of its own response cell; if `precision` is sent, the API returns a `400 INVALID_ARGUMENT` error. minimum: 1 maximum: 12 @@ -344,20 +337,20 @@ components: - area - startTime - endTime - Area: + GeoArea: description: Base schema for all areas type: object properties: areaType: - $ref: "#/components/schemas/AreaType" + $ref: "#/components/schemas/GeoAreaType" required: - areaType discriminator: propertyName: areaType mapping: - POLYGON: "#/components/schemas/Polygon" + POLYGON: "#/components/schemas/GeoPolygon" GEOHASHLIST: "#/components/schemas/GeohashList" - AreaType: + GeoAreaType: type: string description: | Type of this area. @@ -366,10 +359,10 @@ components: enum: - POLYGON - GEOHASHLIST - Polygon: - description: Polygonal area. The Polygon should be a simple polygon, i.e. should not intersect itself. + GeoPolygon: + description: Polygonal area. The polygon should be a simple polygon, i.e. should not intersect itself. allOf: - - $ref: "#/components/schemas/Area" + - $ref: "#/components/schemas/GeoArea" - type: object required: - boundary @@ -380,7 +373,7 @@ components: description: >- Area defined as a list of geohashes. Geohashes do not need to be adjacent or contiguous and may have different precision levels (string lengths), as long as the MNO supports all of them. The `precision` request property MUST NOT be set when `areaType` is `GEOHASHLIST`; if set, the API returns a `400 INVALID_ARGUMENT` error. allOf: - - $ref: "#/components/schemas/Area" + - $ref: "#/components/schemas/GeoArea" - type: object required: - geohashes @@ -407,7 +400,7 @@ components: description: >- Population density data represented as hourly time slots covering the requested time interval for the cells of the requested area. Each element in `timedPopulationDensityData` array corresponds - to a one-hour time slot, containing population density data for all the grid cells of the requested ares. + to a one-hour time slot, containing population density data for all the grid cells of the requested area. properties: timedPopulationDensityData: type: array @@ -421,11 +414,11 @@ components: $ref: '#/components/schemas/TimedPopulationDensityData' maxItems: 168 status: - $ref: '#/components/schemas/ResponseStatus' + $ref: '#/components/schemas/ResponseQualityInfo' statusInfo: type: string maxLength: 512 - description: Information about the status, mandatory when property `status` is `OPERATION_NOT_COMPLETED` for adding extra information about the error. + description: Additional context about the `status` value. Mandatory when `status` is `OPERATION_NOT_COMPLETED`, providing details about why the asynchronous operation could not be completed. example: Some error happened during the processing of the request required: - timedPopulationDensityData @@ -454,14 +447,14 @@ components: description: The unique identifier of the asynchronous operation that is returned when the operation is initiated. pattern: ^[a-zA-Z0-9-_:;.\/<>{}]{1,256}$ example: 2322f362-eaab-4cf3-86d2-efcbdf3a7cb4 - ResponseStatus: + ResponseQualityInfo: type: string description: >- - Represents the state of the response for the input area defined in the request, the possible values are: + This is not an HTTP error indicator - it characterises how completely the API was able to fulfil the request. The possible values are: - `SUPPORTED_AREA`: The whole request area is supported. Population density data for the entire requested area is returned. - - `PART_OF_AREA_NOT_SUPPORTED`: Part of the requested area is outside the MNOs coverage area, the cells outside the coverage + - `PART_OF_AREA_NOT_SUPPORTED`: Part of the requested area is outside the MNO's coverage area, the cells outside the coverage area will have property `dataType` with value `NO_DATA`. - - `AREA_NOT_SUPPORTED`: The whole requested area is outside the MNOs coverage area. No data will be returned. + - `AREA_NOT_SUPPORTED`: The whole requested area is outside the MNO's coverage area. No data will be returned. - `OPERATION_NOT_COMPLETED`: An error happened during asynchronous processing of the request. This status will only be returned in case the asynchronous API behaviour is used. enum: @@ -543,7 +536,7 @@ components: - $ref: '#/components/schemas/CellPopulationDensityData' DensityEstimation: description: >- - Cell with a population density estimation, expressed in people/km2, together with the estimation + Cell with a population density estimation (estimated number of people), together with the estimation range [minimum, maximum]. allOf: - $ref: '#/components/schemas/CellPopulationDensityData' From 0299bb67b961e1d71230e509ca3709c197441737 Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Tue, 6 Oct 2026 18:07:03 +0200 Subject: [PATCH 6/8] fix: align ResponseQualityInfo and statusInfo descriptions with PCD --- .../population-density-data.yaml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index 01d3a4a..ea70dc9 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -34,7 +34,7 @@ info: A subdivision of the requested area. - For polygon areas, the grid is the set of geohash cells, at the applicable precision level, that cover the polygon. All cells have the same precision level. - - For geohash lists, each geohash corresponds to a single cell at the requested precision level. + - For geohash lists, each geohash corresponds to a single cell at its own precision level. **Geohash** A geohash is a string-encoded representation of a geographical area/point on the globe. The (32-base) geohash model represents the globe as a grid of 32 fixed rectangular areas, referred to as cells. Each cell is identified by a single letter or digit. Zooming in to one cell (recursively) gives a more granular (or higher precision) 32-cell grid at the next level with each cell again identified by a single letter or digit. The geohash is a string that identifies a cell at a given zoom level by concatenating the identifiers of all previous level grid cells selected. The deeper the zoom, the longer the string and the higher the granularity/precision of the cell. The maximum zoom/precision level supported by this API is 12. The length (number of characters) of the geohash indicates its precision (zoom level/granularity). More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). @@ -42,7 +42,7 @@ info: **Precision** Defines the granularity level of grid cells. - - **POLYGON**: For polygon areas, the precision level is given by the `precision` request property. If `precision` is not included, the default precision level 7 is used. I.e. a grid is generated for the polygon with all the geohash cells at that precision level that cover the polygon. As a reference, a cell is approximately 1.2 km x 0.6 km at level 6, 153 m x 153 m at level 7 and 38 m x 19 m at level 8. + - **POLYGON**: For polygon areas, the precision level is given by the `precision` request property. If `precision` is not included, the default precision level 7 is used. I.e. a grid is generated for the polygon with all the geohash cells at that precision level that cover the polygon. - **GEOHASHLIST**: For geohash lists, each geohash's own length determines its precision. Example: the geohash "e" at precision level 1 covers a large area that includes most of Spain; the geohash "ezj" (2 cell zoom levels deeper) at precision level 3 is a cell that contains Madrid. Further zooming adds more characters to the geohash, each time identifying a smaller rectangular area on the globe. **MNO Coverage Area** @@ -75,7 +75,7 @@ info: The API returns a sequence of hourly time slots covering the specified interval (adjusted to the begin and end full hour boundaries). Each time slot contains population density data result for all the grid cells covering the requested area. - - For polygon areas, the API implementation subdivides the polygon into equal-sized grid cells based on the precision requested in the API call. If not specified in the request, a default precision level 7 is used. + - For polygon areas, the API implementation subdivides the polygon into grid cells based on the precision requested in the API call. If not specified in the request, a default precision level 7 is used. - For geohash lists, each geohash corresponds to a single cell, and the `precision` property must not be included in the API call. Population density values are estimated using historical data, prediction models, and population estimation algorithms. The allowed time interval is constrained: @@ -418,7 +418,7 @@ components: statusInfo: type: string maxLength: 512 - description: Additional context about the `status` value. Mandatory when `status` is `OPERATION_NOT_COMPLETED`, providing details about why the asynchronous operation could not be completed. + description: Provides additional context about `status`. Mandatory when `status` is `OPERATION_NOT_COMPLETED`, to convey the reason the asynchronous processing could not be completed. example: Some error happened during the processing of the request required: - timedPopulationDensityData @@ -450,13 +450,11 @@ components: ResponseQualityInfo: type: string description: >- - This is not an HTTP error indicator - it characterises how completely the API was able to fulfil the request. The possible values are: + Provides additional information about the quality and coverage of the included response data for the requested area. This is not an HTTP error indicator - it characterises how completely the API was able to fulfil the request: - `SUPPORTED_AREA`: The whole request area is supported. Population density data for the entire requested area is returned. - - `PART_OF_AREA_NOT_SUPPORTED`: Part of the requested area is outside the MNO's coverage area, the cells outside the coverage - area will have property `dataType` with value `NO_DATA`. - - `AREA_NOT_SUPPORTED`: The whole requested area is outside the MNO's coverage area. No data will be returned. - - `OPERATION_NOT_COMPLETED`: An error happened during asynchronous processing of the request. This status will only be returned - in case the asynchronous API behaviour is used. + - `PART_OF_AREA_NOT_SUPPORTED`: Part of the requested area is outside the MNO's coverage area. Cells outside coverage have property `dataType` with value `NO_DATA`. + - `AREA_NOT_SUPPORTED`: The whole requested area is outside the MNO's coverage area. No population density data is returned. + - `OPERATION_NOT_COMPLETED`: The asynchronous processing of the request could not be completed. This value is only used in asynchronous callbacks. See `statusInfo` for details. enum: - SUPPORTED_AREA - PART_OF_AREA_NOT_SUPPORTED From 8d131bf9f134d8c8a3378ed647ab70e46b4bccec Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Tue, 6 Oct 2026 18:16:52 +0200 Subject: [PATCH 7/8] fix: align Geohash definition and Callback section structure with PCD --- code/API_definitions/population-density-data.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index ea70dc9..b1aeeac 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -37,7 +37,7 @@ info: - For geohash lists, each geohash corresponds to a single cell at its own precision level. **Geohash** - A geohash is a string-encoded representation of a geographical area/point on the globe. The (32-base) geohash model represents the globe as a grid of 32 fixed rectangular areas, referred to as cells. Each cell is identified by a single letter or digit. Zooming in to one cell (recursively) gives a more granular (or higher precision) 32-cell grid at the next level with each cell again identified by a single letter or digit. The geohash is a string that identifies a cell at a given zoom level by concatenating the identifiers of all previous level grid cells selected. The deeper the zoom, the longer the string and the higher the granularity/precision of the cell. The maximum zoom/precision level supported by this API is 12. The length (number of characters) of the geohash indicates its precision (zoom level/granularity). More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). + A string-encoded representation of a geographical area using the [Geohash system](https://en.wikipedia.org/wiki/Geohash). The length (number of characters) of the geohash indicates its precision (zoom level/granularity). The maximum precision level supported by this API is 12. **Precision** Defines the granularity level of grid cells. @@ -63,9 +63,6 @@ info: **OperationId** A unique identifier generated by the API Provider to correlate an asynchronous request with its callback notification. It is mandatory in the 202 response and in the callback payload. It differs from `x-correlator` (which is optional, supplied by the API Consumer, and not guaranteed to be present or unique). - **Callback URL and Token** - A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, it is RECOMMENDED for the API Consumer to also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. - # API Functionality To retrieve population density data, the API consumer specifies: @@ -112,9 +109,12 @@ info: The API exposes a single POST endpoint for retrieving population density data for a specified area and time interval. The API call result is an array of hourly timeslots (`timedPopulationDensityData`), with per timeslot an array of cells (`cellPopulationDensityData`), with for each cell the resulting `DataType` with the density data result (see the DataType values defined in the Relevant Terms and Definitions section above). - When an asynchronous response is requested (using `sink`, see Callback URL and Token in the Relevant Terms and Definitions section above), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload, correlating the asynchronous response with its corresponding request. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. + **Callback URL and Token** + API Consumers may provide a callback URL (`sink`) for receiving an asynchronous response. This is an optional parameter. If `sink` is included, it is RECOMMENDED for the API Consumer to provide as well the `sinkCredential` property to protect the callback endpoint. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. + + - When an asynchronous response is requested (using `sink`), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the API provider's `jwksUri` is never conveyed in the response. Unlike an event subscription, the `/retrieve` operation creates no resource to read back, the same static `jwksUri` would be repeated on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. + - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the API provider's `jwksUri` is never conveyed in the response. Unlike an event subscription, the `/retrieve` operation creates no resource to read back, the same static `jwksUri` would be repeated on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. From 32e6be5624b194301dce55965a6b12fb13b6e7af Mon Sep 17 00:00:00 2001 From: Alberto Ramos Monagas Date: Tue, 6 Oct 2026 18:25:57 +0200 Subject: [PATCH 8/8] fix: realign Geohash definition and Callback structure with PCD --- code/API_definitions/population-density-data.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/API_definitions/population-density-data.yaml b/code/API_definitions/population-density-data.yaml index b1aeeac..ea70dc9 100644 --- a/code/API_definitions/population-density-data.yaml +++ b/code/API_definitions/population-density-data.yaml @@ -37,7 +37,7 @@ info: - For geohash lists, each geohash corresponds to a single cell at its own precision level. **Geohash** - A string-encoded representation of a geographical area using the [Geohash system](https://en.wikipedia.org/wiki/Geohash). The length (number of characters) of the geohash indicates its precision (zoom level/granularity). The maximum precision level supported by this API is 12. + A geohash is a string-encoded representation of a geographical area/point on the globe. The (32-base) geohash model represents the globe as a grid of 32 fixed rectangular areas, referred to as cells. Each cell is identified by a single letter or digit. Zooming in to one cell (recursively) gives a more granular (or higher precision) 32-cell grid at the next level with each cell again identified by a single letter or digit. The geohash is a string that identifies a cell at a given zoom level by concatenating the identifiers of all previous level grid cells selected. The deeper the zoom, the longer the string and the higher the granularity/precision of the cell. The maximum zoom/precision level supported by this API is 12. The length (number of characters) of the geohash indicates its precision (zoom level/granularity). More information at [Geohash system](https://en.wikipedia.org/wiki/Geohash). **Precision** Defines the granularity level of grid cells. @@ -63,6 +63,9 @@ info: **OperationId** A unique identifier generated by the API Provider to correlate an asynchronous request with its callback notification. It is mandatory in the 202 response and in the callback payload. It differs from `x-correlator` (which is optional, supplied by the API Consumer, and not guaranteed to be present or unique). + **Callback URL and Token** + A callback URL (`sink`) may be provided to receive asynchronous results. When `sink` is used, it is RECOMMENDED for the API Consumer to also provide `sinkCredential` to secure the callback endpoint. Supported credential types are `ACCESSTOKEN` and `PRIVATE_KEY_JWT`. + # API Functionality To retrieve population density data, the API consumer specifies: @@ -109,12 +112,9 @@ info: The API exposes a single POST endpoint for retrieving population density data for a specified area and time interval. The API call result is an array of hourly timeslots (`timedPopulationDensityData`), with per timeslot an array of cells (`cellPopulationDensityData`), with for each cell the resulting `DataType` with the density data result (see the DataType values defined in the Relevant Terms and Definitions section above). - **Callback URL and Token** - API Consumers may provide a callback URL (`sink`) for receiving an asynchronous response. This is an optional parameter. If `sink` is included, it is RECOMMENDED for the API Consumer to provide as well the `sinkCredential` property to protect the callback endpoint. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. - - - When an asynchronous response is requested (using `sink`), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload. The purpose of the `operationId` is to correlate an asynchronous response with its corresponding request. + When an asynchronous response is requested (using `sink`, see Callback URL and Token in the Relevant Terms and Definitions section above), the 202 response of the API will include an `operationId` property. This `operationId` property will also be sent in the callback payload, correlating the asynchronous response with its corresponding request. If provided, `sinkCredential.credentialType` MUST be set to `ACCESSTOKEN` or `PRIVATE_KEY_JWT`. - - Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the API provider's `jwksUri` is never conveyed in the response. Unlike an event subscription, the `/retrieve` operation creates no resource to read back, the same static `jwksUri` would be repeated on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`. + Using `credentialType: PRIVATE_KEY_JWT` requires the JWT authentication parameters (a.k.a. JWK Set) to be pre-configured by an agreement between the API consumer and the API provider as part of the onboarding process. The API never returns `sinkCredential`, so the API provider's `jwksUri` is never conveyed in the response. Unlike an event subscription, the `/retrieve` operation creates no resource to read back, the same static `jwksUri` would be repeated on every `202` response, and the callback may be delivered before the API consumer has processed that response. If `PRIVATE_KEY_JWT` is provided and no JWK Set is configured for the API consumer, the API returns the error response `422 PRIVATE_KEY_JWT_NOT_CONFIGURED`. A failure to authenticate against the API consumer's authorization server when the callback is delivered cannot be detected while the request is being processed, and is therefore reported in the callback with property `status` set to `OPERATION_NOT_COMPLETED`.