openapi: '3.0.1'

info:
  title: IoT Time Series API
  description:
    Create, update, and query time series data with a precision of 1 millisecond.
  version: "3.8.0"
  x-visibility: "external"

servers:
  - url: https://api.eu1.siemens.app/iottimeseries-1000001700/v3
    description: Xcelerator compliant URL

tags:
  - name: Time Series Operations
    description: Create, update, delete and retrieve time series data

paths:
  /timeseries:
    put:
      summary: Create or update time series data for mutiple unique asset-aspect (entity-property set) combinations.
      tags:
        - Time Series Operations
      description: |
        Create or update time series data for multiple unique combinations of assets (entities) and aspects (property sets).
        In case of an update of data at an already existing time, all properties at that time will be replaced by the ones provided in the request. All asset-aspect (entity-property set) combinations need to belong to the same tenant.

        Request body limitations:
        1. A maximum of 5  asset-aspect (entity-property set) combinations can be provided
        2. The request body size must be equal or less than 100 kb
        3. A maximum of 100 time series data items can be provided overall
      operationId: createOrUpdateTimeseries
      security:
        - timeseries:
            - iot.tim.w
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TimeSeries'
      responses:
        '202':
          description: |
            Accepted. For each asset-aspect (entity-property set) pair a validation error can occur. In case an error is returned for an asset-aspect (entity-property set) pair, time series data for that pair is not considered. Possible validation errors are
             - 400: bad request schema for asset-aspect (entity-property set) pair
             - 404: asset (entity) and/or aspect(proprety set) not found
             - 429: asset-aspect (entity-property set) pair could not be processed due to too many requests
             - default: unexpected error while processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MultiStatusError'
        '400':
          description: |
            Bad request, in case the resource is invalid.
            Few of the validations as below -
            - Total number of records for all assets (entites) and aspects (property sets) should not be more than 100 per PUT request.
            - Total size of the payload should not be more than 100 kb per PUT request.
            - Payload cannot have more than 5 asset (entity)/aspect (property set) combinations.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MultiTimeseiresBadRequest'
        '401':
          description: unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenMultiTimeSeries'
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceUnavailableMultiTimeSeries'
        default:
          description: Other error with any status code and response body format.

  /timeseries/{entityId}/{propertySetName}:
    parameters:
      - name: entityId
        in: path
        description: unique identifier of the asset (entity)
        required: true
        schema:
          type: string
          minLength: 32
          maxLength: 32
          pattern: "[a-f0-9]{32}"
      - name: propertySetName
        in: path
        description: Name of the aspect (property set).
        required: true
        schema:
          type: string
    get:
      summary: Retrieve time series data
      tags:
        - Time Series Operations
      description: |
        Retrieve time series data for one combination of an asset (entity) and an(a) aspect (property set). The maximum number of time series data items returned per request is defined by parameter <i>limit</i>. In case more time series data items are present in the requested time range, only a subset of data items will be returned and a header <i>link</i> is added to the response. The header value contains the request URL to fetch the next set of  time series data items, by increasing the <i>from</i> parameter accordingly. Returns the latest available timestamp record if no range is provided. 
        Note: 
          > If no range is provided, Based on Customer data ingestion timestamp record, it may not contain all variables of aspect. For example, an Aspect has 5 variables; but latest timeseries record has only 3 variables with values. Only latest timeseries record will be returned in response with values of 3 variables only. It will not fetch latest value of all 5 variables of aspect.
      operationId: retrieveTimeseries
      security:
        - timeseries:
            - iot.tim.r
      parameters:
        - name: from
          in: query
          description: Beginning of the time range to be retrieved (exclusive).
          required: false
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          description: End of the time range to be retrieved (inclusive).
          required: false
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          description: Maximum number of time series data items to be retrieved.
          required: false
          schema:
            type: integer
            default: 2000
            maximum: 2000
        - name: select
          in: query
          description: Comma-separated list of properties to be returned. By default all properties of an(a) aspect (property set) are considered.
          required: false
          schema:
            type: string
        - name: sort
          in: query
          description: Define sorting order of returned data. Sorting can be chronologically ascending (<i>asc</i>) or descending (<i>desc</i>).
          required: false
          schema:
            type: string
            enum: [asc, desc]
            default: asc
        - name: latestValue
          in: query
          description: If true, only the latest value of each property is returned. Latest values must be at least 5 Minutes old and at maximum 90 days old, in order to be considered. The returned values might be co-located or spread over multiple timestamps. Each property appears at max once in the response. The select parameter can be used to limit the properties to be considered. Parameters from, to, and limit must not be used in conjunction with latest. The response only includes latest value with good and uncertain quality codes
          required: false
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: array of time series
          headers:
            link:
              description: Contains a link to the next page, if there is a next page
              schema:
                type: string
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TimeSeriesDataItem'
        '400':
          description: bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequest'
        '401':
          description: unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forbidden'
        '404':
          description: asset (entity) not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
        '429':
          description: |
            Too many requests that can be arised based on subsequent case:
            - User has sent too many requests in a given amount of time. 
            
            A Retry-After header might be included to this response indicating how long in 'seconds' to wait before making a new request.
          headers:
            Retry-After:
              description: Time in seconds to wait before making a new request
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimiter'
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceUnavailable'
        default:
          description: Other error with any status code and response body format.

    put:
      summary: Create or update time series data
      tags:
        - Time Series Operations
      description: |
        Create or update time series data for one combination of an asset (entity) and an(a) aspect (property set). In case of an update of data at an already existing time, all properties at that time will be replaced by the ones provided in the request.
      operationId: createOrUpdateTimeseriesData
      security:
        - timeseries:
            - iot.tim.w
      requestBody:
        description: time series data array
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                $ref: '#/components/schemas/TimeSeriesDataItem'
      responses:
        '204':
          description: timeseries written
        '400':
          description: bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequest'
        '401':
          description: unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forbidden'
        '404':
          description: asset (entity) not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
        '429':
          description: |
            too many requests
             A Retry-After header might be included to this response indicating how long in 'seconds' to wait before making a new request.
          headers:
            Retry-After:
              description: Time in seconds to wait before making a new request
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TooManyRequests'
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceUnavailable'
        default:
          description: Other error with any status code and response body format.

    patch:
      summary: Create or merge time series data
      tags:
        - Time Series Operations
      description: |
        Create or merge time series data for one combination of an asset (entity) and an(a) aspect (property set). This api creates or merges the data when different devices Or 3rd party apps write to different variables but within one aspect (property set) and same timestamp. Only those properties will be replaced by the ones provided in the request.

        Request body limitations:
        1. It may take several minutes after response until the provided changes are fully merged.
        2. The number of updates being processed simultaneously by the service is limited.
        3. The number of requests being accepted for processing is limited per time frame.
        4. The maximum size of acceptable request bodies is 600 KB.
        5. The maximum time range for PATCH request can't be older than 24 hours from current time. For example, if customer want to patch some timeseries record ingested for current time T; it needs to be patched maximum within T+24 hours
        6. The PATCH will not work on Future timestamp at the time of execution.
        7. The merge functionality does not support to create or update the variable value having data type as BigString.
        8. The maximum number of records supported in one request is 10.
        9. In case of errors, none of the changes for the provided time stamps will be applied.

        **Example**
        
        *Example 1: If we have asset (entity) which can send two sensor values say 'pressure' & 'temperature'. Then the asset (entity) can send two separate calls to IoT for same device timesamp as below:*
        
            Call-1: This is a put request
              TS record for tenant1\asset1\aspect1
              {
                  "_time" : "2020-01-01T23:00:00.000Z",
                  "pressure" : 42.56
              }

            Call-2: This is a patch request
              TS record for tenant1\asset1\aspect1
              {
                "_time" : "2020-01-01T23:00:00.000Z",
                "temperature" : 73.23
              }

        After above two TimeSeries ingest calls, if we make GET call for this tenant-asset-aspect combination and for the same device timestamp, then expected output should have merged results from both the calls. This means the output should look as below:

            TS record for tenant1\asset1\aspect1
            {
              "_time" : "2020-01-01T23:00:00.000Z",
              "pressure" : 42.56,
              "temperature" : 73.23
            }

      operationId: createOrMergeTimeseries
      security:
        - timeseries:
            - iot.tim.w
      requestBody:
        description: time series data array
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                $ref: '#/components/schemas/TimeSeriesDataItem'
      responses:
        '204':
          description: |
            No Content.
        '400':
          description: |
            Bad request, in case the resource is invalid.
            Few of the validations as below -
            - The maximum time range of time series data acceptable is one day from current time
            - The provided time stamps must be not later than the currently latest time stamp in the time series
            - The maximum size of acceptable request bodies is 1 MB
            - Request payload date should be in ISO format
            - The maximum number of records supported in one request is 10
            - The specified date is outside the acceptable range
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequest'
        '401':
          description: unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
        '403':
          description: forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forbidden'
        '404':
          description: |
            Not Found, in case the resource is not found.
            Few of the validations as below -
            - Unable to find the tenant
            - Unable to find the asset
            - Unable to find the aspect
            - Unable to find the asset type
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
        '429':
          description: |
            Too many requests that can be arised based on subsequent case:
            - User has sent too many requests in a given amount of time.

            A Retry-After header might be included to this response indicating how long in 'seconds' to wait before making a new request.
          headers:
            Retry-After:
              description: Time in seconds to wait before making a new request
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TooManyRequests'
        '500':
          description: Internal service error.
        '503':
          description: Service unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceUnavailable'
        default:
          description: Other error with any status code and response body format.

    delete:
      summary: Delete time series data
      tags:
        - Time Series Operations
      description: |
        Delete time series data for one combination of an asset (entity) and an(a) aspect (property set). All property values within the given time range are deleted.
      operationId: deleteTimeseries
      security:
        - timeseries:
            - iot.tim.d
      parameters:
        - name: from
          in: query
          description: beginning of the timerange to delete (exclusive)
          required: true
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          description: end of the timerange to delete (inclusive)
          required: true
          schema:
            type: string
            format: date-time
      responses:
        '204':
          description: deleted
        '400':
          description: bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BadRequest'
        '401':
          description: unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forbidden'
        '404':
          description: asset (entity) not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceUnavailable'
        default:
          description: Other error with any status code and response body format.

components:
  schemas:
    TimeSeriesDataItem:
      type: object
      required: [_time]
      properties:
        _time:
          type: string
          description: Timestamp of the data points.
          format: date-time
      additionalProperties:
        description: Time series aspect (property set) variable with value. 
            The property's key name is given by the corresponding variable name.
            The property's value type is given according to the variable type.

            <table>
                  <tr>
                  <td> Variable Type </td>
                  <td> JSON Type </td>
                  </tr>
                  <tr>
                  <td>int/ long/ double
                  </td>
                  <td>number</td>
                  </tr>
                  <tr>
                  <td>boolean</td>
                  <td>boolean</td>
                  </tr>
                  <tr>
                  <td>timestamp/ string/ bigstring</td>
                  <td>string</td>
                  </tr>
            </table>
      example:
        _time: "2019-02-10T23:01:00Z"
        exampleproperty0: examplepropertyValue
        exampleproperty0_qc: exampleproperty0_qc_Value
        exampleproperty1: exampleproperty1Value

    TimeSeriesItem:
      type: object
      required: [entityId, propertySetName, data]
      properties:
        entityId:
          type: string
          description: asset (entity) Id of timeseries data.
        propertySetName:
          type: string
          description: aspect (property set) name of timeseries data.
        data:
          type: array
          description: Timeseries data for corresponsding asset (entity) Id and aspect (property set) name.
          items:
            $ref: '#/components/schemas/TimeSeriesDataItem'

    TimeSeries:
      description: Time series of a set of asset-aspect (entity-property set) combinations.
      type: object
      properties:
        timeseries:
          type: array
          items:
            $ref: '#/components/schemas/TimeSeriesItem'
          example:
            - entityId: entityId1
              propertySetName: propertySetName1
              data:
                - _time: "2019-02-10T23:00:00Z"
                  rpm: rpmValue1
                  rpm_qc: rpm_qcValue1
                  enginetemperature: enginetemperatureValue1
                - time: "2019-02-10T23:01:00Z"
                  rpm: rpmValue2
                  rpm_qc: rpm_qcValue2
                  enginetemperature: enginetemperatureValue2
            - entityId: entityId2
              propertySetName: propertySetName2
              data:
                - _time: "2019-02-10T23:00:00Z"
                  height: heightValue
                  height_qc: height_qcValue
                  carmanual: carmanualValue
            - entityId: entityId3
              propertySetName: propertySetName3
              data:
                - _time: "2019-02-10T23:00:00Z"
                  speed: speedValue
                  speed_qc: speed_qcValue
                  width: widthValue

    MultiStatusError:
      description: a (errors, errorObject).
      type: object
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/MultiStatusErrorItem'

    MultiStatusErrorItem:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
          example: 2019-04-08T06:32:01.261+0000
        status:
          type: number
          example: 404
        error:
          type: string
          example: 'Not Found'
        exception:
          type: string
          example: 'com.siemens.mindsphere.iot.exception.IotException'
        message:
          type: string
          example: '[6007] Invalid value for request param - propertysetname'
        entityId:
          type: string
          example: 'entityId2'
        propertySetName:
          type: string
          example: 'propertySetName2'
        path:
          type: string
          example: '/api/iottimeseries/v3/timeseries'

    BadRequest:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: number
        error:
          type: string
        exception:
          type: string
        message:
          type: string
        path:
          type: string
      example:
        timestamp: "2019-04-08T06:32:01.261+0000"
        status: 400
        error: "Bad Request"
        exception: "com.siemens.mindsphere.iot.exception.IotException"
        message: "[6008] Invalid date format '2018-10-16T00:00:00Z111' for request param - from"
        path: "/api/iottimeseries/v3/timeseries/entityId/propertySetName"

    MultiTimeseiresBadRequest:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: number
        error:
          type: string
        exception:
          type: string
        message:
          type: string
        path:
          type: string
      example:
        timestamp: "2019-04-08T06:32:01.261+0000"
        status: 400
        error: "Bad Request"
        exception: "com.siemens.mindsphere.iot.exception.IotException"
        message: "Size of payload should not be more than 100 kb"
        path: "/api/iottimeseries/v3/timeseries"

    NotFound:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: number
        error:
          type: string
        exception:
          type: string
        message:
          type: string
        path:
          type: string
      example:
        timestamp: "2019-04-08T06:32:01.261+0000"
        status: 404
        error: "Not Found"
        exception: "com.siemens.mindsphere.iot.exception.IotException"
        message: "[6408] Unable to find the entity - entityId"
        path: "/api/iottimeseries/v3/timeseries/entityId/propertySetName"

    TooManyRequests:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: number
        error:
          type: string
        exception:
          type: string
        message:
          type: string
        path:
          type: string
      example:
        timestamp: "2019-04-08T06:32:01.261+0000"
        status: 429
        error: "Too Many Requests"
        exception: 'com.siemens.mindsphere.iot.exception.IotException'
        message: "[429] Your request rate is too high, all calls will be rejected for a while"
        path: "/api/iottimeseries/v3/timeseries/entityId/propertySetName"

    RateLimiter:
      type: object
      properties:
        message:
          type: string
      example:
        message: "API rate limit exceeded"

    Forbidden:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: number
        error:
          type: string
        exception:
          type: string
        message:
          type: string
        path:
          type: string
      example:
        timestamp: "2019-04-08T06:32:01.261+0000"
        status: 403
        error: "Forbidden"
        message: "[6552] User is not having required access to perform this operation on given Asset/Entity {assetId}. Consult tenant admin for appropriate access."
        path: "/api/iottimeseries/v3/timeseries/entityId/propertySetName"

    ForbiddenMultiTimeSeries:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: number
        error:
          type: string
        exception:
          type: string
        message:
          type: string
        path:
          type: string
      example:
        errors:
          - timestamp: "2019-04-08T06:32:01.261+0000"
            status: 403
            error: "Forbidden"
            exception: "class com.siemens.mindsphere.iot.exception.IotException"
            message: "[6552] User is not having required access to perform this operation on given Asset/Entity fc6040ce94934f2dba35cc82235210c3. Consult tenant admin for appropriate access."
            entityId: "fc6040ce94934f2dba35cc82235210c3"
            propertysetName: "aspectName"
            path: "/api/iottimeseries/v3/timeseries"

    ServiceUnavailable:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: number
        error:
          type: string
        exception:
          type: string
        message:
          type: string
        path:
          type: string
      example:
        timestamp: "2019-04-08T06:32:01.261+0000"
        status: 503
        error: "Service Unavailable"
        message: "Service not available."
        path: "/api/iottimeseries/v3/timeseries/entityId/propertySetName"

    ServiceUnavailableMultiTimeSeries:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: number
        error:
          type: string
        exception:
          type: string
        message:
          type: string
        path:
          type: string
      example:
        timestamp: "2019-04-08T06:32:01.261+0000"
        status: 503
        error: "Service Unavailable"
        message: "Service not available."
        path: "/api/iottimeseries/v3/timeseries"

    Unauthorized:
      type: object
      properties:
        id:
          type: string
          format: uuid
        message:
          type: string
          example: Not authorized to access this resource.

  securitySchemes:
    timeseries:
      type: oauth2
      description: |
        For **Xcelerator** compliance, please use **authorizationUrl** = https://1000001700.eu1.sws.siemens.com/oauth/authorize and **tokenUrl** = https://1000001700.eu1.sws.siemens.com/oauth/token

      flows:
        authorizationCode:
          authorizationUrl: 'https://1000001700.eu1.sws.siemens.com/oauth/authorize'
          tokenUrl: 'https://1000001700.eu1.sws.siemens.com/oauth/token'
          scopes:
            iot.tim.r: read timeseries
            iot.tim.w: write timeseries
            iot.tim.d: delete timeseries
