openapi: 3.0.0
servers:
  - url: https://api.test.enode.io/
info:
  description: |+
    Download [OpenAPI 3.0 Specification](/OpenAPI-Enode-v1.4.0.json)

    Download [Postman Collection](/Postman-Enode-v1.4.0.json)

    The Enode API is designed to make smart charging applications easy to develop. We provide an abstraction layer that reduces the complexity when extracting vehicle data and sending commands to vehicles from a variety of manufacturers.

    The API has a RESTful architecture and utilizes OAuth2 authorization.

    We are always available to handle any issues or just answer your questions. Feel free to reach out on post@enode.io


    ## Registration for API access
    In order to use the API you will need a `client_id` and `client_secret`. Please contact us if you are interested in using our API in production, and we will provide these credentials.

    # Authorization
    Vehicle / hardware access via the Enode API is granted to your application by the User in a standard OAuth `Authorization Code` flow.

    > The authorization scheme documented here is the recommended approach for most situations. However, it is also possible to user other OAuth flows, non-confidential clients, and temporary users. Please feel free to contact us if you have any questions about your use-case or the integration of your existing infrastructure.

    ### Preparation: Configure your OAuth client

    Because Enode API implements the OAuth 2.0 spec completely and without modifications, you can avoid rolling your own OAuth client implementation and instead use a well-supported and battle-tested implementation. This is strongly recommended. Information on available OAuth clients for many languages is available [here](https://oauth.net/code/)

    To configure your chosen OAuth client, you will need these details:
    - Your `client_id`
    - Your `client_secret`
    - Authorization URL: `https://link.test.enode.io/oauth2/auth`
    - Token URL: `https://link.test.enode.io/oauth2/token`

    ```javascript
    // Node.js + openid-client example
    const enodeIssuer = await Issuer.discover('https://link.test.enode.io');
    const client = new enodeIssuer.Client({
      client_id: 'xyz',
      client_secret: 'shhhhh',
      redirect_uris: ['http://localhost:5000/callback'],
      response_types: ['code'],
    });
    ```


    ### Preparation: Obtain a client access token via OAuth Client Credentials Grant
    Your OAuth client will have a method for using the `OAuth 2.0 Client Credentials Grant` to obtain an access token.

    ```javascript
    // Node.js + openid-client example
    const clientAccessToken = await client.grant({grant_type: "client_credentials"});
    ```

    This access token belongs to your client and is used for administrative actions, such as the next step.

    This token should be cached by your server and reused until it expires, at which point your server should request a new one.



    ### Step 1. Generate an Enode Link session for your User and launch the OAuth flow

    When your User indicates that they want to connect their hardware to your app, your server must call [Link User](#operation/postUsersUseridLink) to generate an Enode Link session for your User. The User ID can be any string that uniquely identifies the User, but it is recommended that you use the primary key by which you identify the User within your application.

    Example Request:
    ```
    POST /users/{userId}/link HTTP/1.1
    Authorization: Bearer {access_token}
    {
      "forceLanguage": "nb-NO",
      "vendor": "Tesla",
    }
    ```

    Example Response:
    ```
    {
        "linkState": "ZjE2MzMxMGFiYmU4MzcxOTU1ZmRjMTU5NGU2ZmE4YTU3NjViMzIwY2YzNG",
    }
    ```

    The returned linkState must be stored by your server, attached to the session of the authenticated user for which it was generated.

    Your OAuth client will provide a method to construct an authorization URL for your user. That method will require these details:
    - Redirect URI - The URI to which your user should be redirected when the Oauth flow completes
    - Scope - The OAuth scope(s) you wish to request access to (see list of valid values [here](#section/Authentication/AccessTokenBearer))
    - State - The value of `linkState` from the request above

    To launch the OAuth flow, send your user to the authorization URL constructed by your OAuth client. This can be done in an embedded webview within a native iOS/Android app, or in the system's default browser.

    ```javascript
    // Node.js + openid-client + express example

    // Construct an OAuth authorization URL
    const authorizationUrl = client.authorizationUrl({
      scope: "offline_access all",
      state: linkState
    });

    // Redirect user to authorization URL
    res.redirect(authorizationUrl);
    ```


    ### Step 2. User grants consent
    In the Link UI webapp the user will follow 3 steps:

    1. Choose their hardware from a list of supported manufacturers (EVs and charging boxes). For certain EV makes it will be necessary to also select a charge box.
    2. For each selection, the user will be presented with the login screen for that particular hardware. The user must successfully log in.
    3. A summary of the requested scopes will be presented to the user. The user must choose whether to grant access to your application.


    ### Step 3. OAuth flow concludes with a callback
    When the user has completed their interactions, they will be redirected to the `Redirect URI` you provided in Step 1, with various metadata appended as query parameters.

    Your OAuth client will have a method to parse and validate that metadata, and fetch the granted access and refresh tokens.

    Among that metadata will be a `state` value - you must verify that it is equal to the `linkState` value persisted in Step 1, as [a countermeasure against CSRF attacks](https://tools.ietf.org/html/rfc6819#section-4.4.1.8).

    ```javascript
    // Node.js + openid-client + express example

    // Fetch linkState from user session
    const linkState = get(req, 'session.linkState');

    // Parse relevant parameters from request URL
    const params = client.callbackParams(req);

    // Exchange authorization code for access and refresh tokens
    // In this example, openid-client does the linkState validation check for us
    const tokenSet = await client.oauthCallback('http://localhost:5000/callback', params, {state: linkState})
    ```

    With the access token in hand, you can now access resources on behalf of the user.


    # Errors And Problems
    ## OAuth Authorization Request

    When the User has completed the process of allowing/denying access in Enode Link, they will be redirected to your configured redirect URI. If something has gone wrong, query parameters `error` and `error_description` will be set as documented in [Section 4.1.2.1](https://tools.ietf.org/html/rfc6749#section-4.1.2.1) of the OAuth 2.0 spec:

    |error                      |error_description|
    |---------------------------|-----------------|
    |invalid_request            |The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.|
    |unauthorized_client        |The client is not authorized to request an authorization code using this method.|
    |access_denied              |The resource owner or authorization server denied the request.|
    |unsupported_response_type  |The authorization server does not support obtaining an authorization code using this method.|
    |invalid_scope              |The requested scope is invalid, unknown, or malformed.|
    |server_error               |The authorization server encountered an unexpected condition that prevented it from fulfilling the request.|
    |temporarily_unavailable    |The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server|

    Example:
    ```
    https://website.example/oauth_callback?state=e0a86fe5&error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.
    ```


    ## Errors when accessing a User's resources

    When using an `access_token` to access a User's resources, the following HTTP Status Codes in the 4XX range may be encountered:

    |HTTP Status Code           |Explanation      |
    |---------------------------|-----------------|
    |400 Bad Request            |The request payload has failed schema validation / parsing
    |401 Unauthorized           |Authentication details are missing or invalid
    |403 Forbidden              |Authentication succeeded, but the authenticated user doesn't have access to the resource
    |404 Not Found              |A non-existent resource is requested
    |429 Too Many Requests      |Rate limiting by the vendor has prevented us from completing the request


    In all cases, an [RFC7807 Problem Details](https://tools.ietf.org/html/rfc7807) body is returned to aid in debugging.

    Example:
    ```
    HTTP/1.1 400 Bad Request
    Content-Type: application/problem+json
    {
      "type": "https://docs.enode.io/problems/payload-validation-error",
      "title": "Payload validation failed",
      "detail": "\"authorizationRequest.scope\" is required",
    }
    ```

  title: Enode API
  version: 1.3.10
  x-apisguru-categories:
    - location
  x-logo:
    url: https://api.apis.guru/v2/cache/logo/https_assets.website-files.com_5f32f25e947c8a1f62356ec1_5f4a941e3a9d743428afb799_Enode%20Logo2.png
  x-origin:
    - format: openapi
      url: https://docs.enode.io/OpenAPI-Enode-v1.3.10.json
      version: "3.0"
  x-providerName: enode.io
tags:
  - description: Charging Locations are created by a user to denote locations where they pay for the power used to charge their vehicle. Smart Charging is active at these locations only.
    name: Charging Locations
  - description: |
      Webhooks are a mechanism that allows your server to recieve notifications of events from the Enode system.

      Currently, there is only one webhook available - a preconfigured webhook called `Firehose` that reports all supported events ocurring within the system. You can configure it using the [Update Firehose Webhook](#operation/putWebhooksFirehose) endpoint.

      ## Supported events
      | Name                        | Description                 |
      |-----------------------------|-----------------------------|
      |user:vehicle:updated         | One or more of a vehicle's properties (as listed in [Get Vehicle](#operation/getVehiclesVehicleid)) has been updated |
      |user:vehicle:discovered      | A new vehicle has been discovered attached to a user |
      |user:vehicle:deleted         | A vehicle has been deleted |


      ## Implementing your Webhook endpoint
      Your webhook endpoint should expect to receive `POST` requests bearing the following headers:

      | Header            | Description                                                       |
      |-------------------|-------------------------------------------------------------------|
      |X-Enode-Delivery   | Unique ID identifying the delivered payload                       |
      |X-Enode-Signature  | Signature authenticating that Enode is the author of the delivery |


      And an `application/json` body containing an array of Events, with the following schema:

      ```json
      [
        {
          "event": "user:vehicle:updated", // String - name of the event
          "createdAt": "2020-04-07T17:04:26Z", // UTC ISO 8601 - time at which the event was triggered
        },
        ...
      ]
      ```

      Each Event object may contain additional properties, depending on the event.

      ## Generating a Secret
      A cryptographically secure secret should be generated and persisted on your server.

      You will provide it when configuring a webhook, such as [Update Firehose Webhook](#operation/putWebhooksFirehose), and you will again use it when verifying the signature of incoming webhook requests.

      It should be a pseudorandom value of at least 128 bits, produced by a secure generator.

      ```javascript
      // Node.js example - 256 bits
      const crypto = require("crypto");
      const secret = crypto.randomBytes(32).toString("hex");
      ```

      ## Verifying a Payload Signature
      Requests made to your endpoint will bear a `X-Enode-Signature` header verifying that the request has come from us.

      The signature is the HMAC hex digest of the payload, where:
      - algorithm = `sha1`
      - key = your `secret` provided during webhook configuration
      - payload = The request body (a UTF-8 encoded string containing JSON - be sure to not deserialize it before signature computation)

      The signature is then prefixed with "sha1="

      In Javascript, the signature may be verified as follows:

      ```javascript
      // Node.js + Express example

      // Read signature from request HTTP header
      const enodeSignature = Buffer.from(req.get("X-Enode-Signature"), "utf8");

      // Compute signature using your secret and the request payload
      const payload = req.body;
      const hmac = crypto.createHmac("sha1", <your secret>);
      const digest = Buffer.from("sha1=" + hmac.update(payload).digest("hex"), "utf8");

      // Check whether they match, using timing-safe equality (don't use ==)
      if (!crypto.timingSafeEqual(digest, enodeSignature)) {
        throw new Error("Signature invalid");
      }
      ```


      ## Example Payload
      `user:vehicle:updated` payload containing 1 event:

      ```json
      [
        {
          "event": "user:vehicle:updated",
          "createdAt": "2020-04-07T17:04:26Z",
          "user": { // the user whose vehicle was updated
            "id": "8d90101b-3f2f-462a-bbb4-1ed320d33bbe"
          },
          "vehicle": { // the vehicle whose properties were updated
            "id": "e8af7ddf-01ce-4ff7-b850-45888708cc0a",
            "lastSeen": "2020-04-07T17:04:26Z",
            "chargeState": {
              "batteryLevel": "38",
              "range": "127.5",
            },
            "location": {
              "longitude": 10.757933,
              "latitude": 59.911491,
              "lastUpdated": "2020-04-07T17:04:26Z"
            },
          },
        }
      ]
      ```

      The `vehicle` property follows the same schema as [Get Vehicle](#operation/getVehiclesVehicleid), and only changed fields will be populated.
    name: Webhooks
  - description: The `Me` endpoint returns metadata about the authenticated User.
    name: Me
paths:
  /chargers:
    get:
      operationId: getChargers
      parameters:
        - description: |-
            An optional array of Charger fields that should be included in the response, for example: `?field[]=information&field[]=chargeState` 

            By default, no optional fields are included and only the Charger ID will be returned. Response time will generally be slower the more fields you request.
          explode: true
          in: query
          name: field[]
          schema:
            items:
              enum:
                - chargeState
                - location
              type: string
            type: array
      responses:
        "200":
          content:
            application/json:
              schema:
                items:
                  $ref: "#/paths/~1chargers~1%7BchargerId%7D/get/responses/200/content/application~1json/schema"
                type: array
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - charger:charge_state
        - UserAccessToken:
            - charger:information
      summary: List Chargers
      tags:
        - Chargers
  "/chargers/{chargerId}":
    get:
      operationId: getCharger
      parameters:
        - description: ID of the Charger
          in: path
          name: chargerId
          required: true
          schema:
            minLength: 1
            type: string
        - $ref: "#/paths/~1chargers/get/parameters/0"
      responses:
        "200":
          content:
            application/json:
              schema:
                properties:
                  chargeState:
                    properties:
                      chargeRate:
                        description: |-
                          The current charge rate in kW.

                          This property is only available when the charger is actively charging a vehicle, and is `null` any other time.
                        example: 40.1
                        minimum: 0
                        type: number
                      isCharging:
                        description: Current charging status
                        example: false
                        type: boolean
                      isPluggedIn:
                        description: Indicates whether the charger has a vehicle plugged into it (regardless of whether that vehicle is actually charging)
                        example: true
                        type: boolean
                    type: object
                  id:
                    description: Charger ID
                    type: string
                  information:
                    description: Descriptive information about the Charger
                    properties:
                      brand:
                        description: Charger brand
                        example: Easee
                        type: string
                      id:
                        description: Charger ID
                        example: 8d90101b-3f2f-462a-bbb4-1ed320d33bbe
                        type: string
                      model:
                        description: Charger model
                        example: Home
                        type: string
                      year:
                        description: Charger production year
                        example: 2020
                        type: integer
                    type: object
                  isReachable:
                    description: Is the charger currently reachable?
                    type: boolean
                  lastSeen:
                    description: The last time the charger was successfully communicated with
                    format: date
                    type: string
                type: object
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - charger:charge_state
        - UserAccessToken:
            - charger:information
      summary: Get Charger
      tags:
        - Chargers
  "/chargers/{chargerId}/charging":
    post:
      description: Instruct the charger to start or stop charging
      operationId: controlChargerCharging
      parameters:
        - description: ID of the Charger
          in: path
          name: chargerId
          required: true
          schema:
            minLength: 1
            type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                action:
                  description: Charging action to perform
                  enum:
                    - START
                    - STOP
                  example: START
                  type: string
              required:
                - action
              type: object
      responses:
        "204":
          content: {}
          description: No Content
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - control:charger:charging
      summary: Control Charging
      tags:
        - Chargers
  /charging-locations:
    get:
      description: Returns a list of Charging Locations registered to the User
      operationId: getCharginglocations
      responses:
        "200":
          content:
            application/json:
              schema:
                items:
                  $ref: "#/paths/~1charging-locations/post/requestBody/content/application~1json/schema"
                type: array
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - charging_location
      summary: List Charging Locations
      tags:
        - Charging Locations
    post:
      operationId: postCharginglocations
      requestBody:
        content:
          application/json:
            schema:
              properties:
                id:
                  description: Charging Location ID
                  example: 8d90101b-3f2f-462a-bbb4-1ed320d33bbe
                  format: uuid
                  readOnly: true
                  type: string
                latitude:
                  description: Latitude in degrees
                  example: 59.911491
                  type: number
                longitude:
                  description: Longitude in degrees
                  example: 10.757933
                  type: number
                name:
                  description: User-supplied name for the Charging Location
                  example: Home
                  type: string
              required:
                - id
              type: object
      responses:
        "201":
          content:
            application/json:
              schema:
                $ref: "#/paths/~1charging-locations/post/requestBody/content/application~1json/schema"
          description: Created
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - charging_location
      summary: Create Charging Location
      tags:
        - Charging Locations
  "/charging-locations/{chargingLocationId}":
    delete:
      description: Delete a Charging Location
      operationId: deleteCharginglocationsCharginglocationid
      parameters:
        - description: ID of the Charging Location
          in: path
          name: chargingLocationId
          required: true
          schema:
            type: string
          x-format:
            guid: true
      responses:
        "204":
          content: {}
          description: No Content
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - charging_location
      summary: Delete Charging Location
      tags:
        - Charging Locations
    get:
      operationId: getCharginglocationsCharginglocationid
      parameters:
        - description: ID of the Charging Location
          in: path
          name: chargingLocationId
          required: true
          schema:
            type: string
          x-format:
            guid: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/paths/~1charging-locations/post/requestBody/content/application~1json/schema"
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - charging_location
      summary: Get Charging Location
      tags:
        - Charging Locations
    put:
      description: Updates a charging location with new configuration
      operationId: putCharginglocationsCharginglocationid
      parameters:
        - description: ID of the Charging Location
          in: path
          name: chargingLocationId
          required: true
          schema:
            type: string
          x-format:
            guid: true
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/paths/~1charging-locations/post/requestBody/content/application~1json/schema"
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/paths/~1charging-locations/post/requestBody/content/application~1json/schema"
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - charging_location
      summary: Update Charging Location
      tags:
        - Charging Locations
  /health/ready:
    get:
      description: Gets the combined health status of the service and all functionalities and dependencies.
      operationId: getHealthReady
      responses:
        "204":
          content: {}
          description: All functionalities are operating nominally
        "503":
          content:
            application/json:
              schema:
                description: At least one functionality of the system is not operating nominally
                type: string
          description: At least one functionality of the system is not operating nominally
      summary: Check Service Readiness
      tags:
        - Service Health
  /health/vendors:
    get:
      description: List the supported vendors and their current status.
      operationId: getHealthVendors
      responses:
        "200":
          content:
            application/json:
              schema:
                example:
                  - displayName: Tesla
                    status: READY
                    vendor: TESLA
                  - displayName: BMW
                    status: READY
                    vendor: BMW
                  - displayName: Audi
                    status: READY
                    vendor: AUDI
                items:
                  description: Vendor status and metadata
                  properties:
                    displayName:
                      description: Displayable name of the Vendor
                      example: Tesla
                      type: string
                    status:
                      description: Ready-state of the Vendor
                      enum:
                        - READY
                        - ELEVATED_ERROR_RATE
                        - OUTAGE
                      example: READY
                      type: string
                    vendor:
                      $ref: "#/paths/~1me~1vendors~1%7Bvendor%7D/delete/parameters/0/schema"
                  type: object
                type: array
          description: Successful
      summary: Check Available Vendors
      tags:
        - Service Health
  /me:
    get:
      description: Returns metadata about the authenticated User, including a list of vendors for which the user has provided credentials.
      operationId: getMe
      responses:
        "200":
          content:
            application/json:
              schema:
                properties:
                  id:
                    example: 123456789-ABc
                    minLength: 1
                    type: string
                  linkedVendors:
                    items:
                      properties:
                        isValid:
                          description: Whether the provided credentials are currently valid. A `false` value here indicates that a credential has become invalidated, and [Link User](#operation/postUsersUseridLink) should be used to get new credentials from this user.
                          type: boolean
                        vendor:
                          $ref: "#/paths/~1me~1vendors~1%7Bvendor%7D/delete/parameters/0/schema"
                      type: object
                    type: array
                type: object
          description: Successful
      security:
        - UserAccessToken: []
      summary: Get My User
      tags:
        - Me
  "/me/vendors/{vendor}":
    delete:
      description: |-
        Disconnect a single Vendor from the User's account.

        All stored data about their Vendor account will be deleted, and any vehicles that were provided by that Vendor will disappear from the system.
      operationId: disconnectVendor
      parameters:
        - description: Vendor to be unlinked
          in: path
          name: vendor
          required: true
          schema:
            description: Vendor ID
            enum:
              - TESLA
              - BMW
              - AUDI
              - VOLKSWAGEN
              - HYUNDAI
              - PEUGEOT
              - NISSAN
            example: TESLA
            type: string
      responses:
        "204":
          content: {}
          description: No Content
      security:
        - UserAccessToken: []
      summary: Disconnect Vendor
      tags:
        - Me
  /statistics/charging:
    get:
      description: Returns a normalized timeseries of statistics about power consumption and price for the User.
      operationId: getStatisticsCharging
      parameters:
        - description: The unit of time the data will be cut into before aggregate statistics are applied. For instance if you choose DAY, then each item in the returned array will cover 1 day.
          in: query
          name: resolution
          schema:
            default: DAY
            enum:
              - HOUR
              - DAY
              - WEEK
              - MONTH
              - YEAR
            type: string
        - description: Earliest date to include in the response
          in: query
          name: startDate
          required: true
          schema:
            format: date
            type: string
        - description: Latest date to include in the response (defaults to current date/time)
          in: query
          name: endDate
          schema:
            format: date
            type: string
        - description: Filter statistics to only include this vehicle
          in: query
          name: vehicleId
          schema:
            minLength: 1
            type: string
        - description: Filter statistics to only include this charging location
          in: query
          name: chargingLocationId
          schema:
            type: string
          x-format:
            guid: true
      responses:
        "200":
          content:
            application/json:
              schema:
                example:
                  - costSum: 3.14
                    date: 2021-01-19T09:37:36.845Z
                    kw:
                      max: 78
                      mean: 61
                      min: 0
                    kwhSum: 120
                    price:
                      max: 14.4
                      mean: 14.1
                      min: 13.8
                items:
                  properties:
                    costSum:
                      description: Total cost in <CURRENCY>
                      example: 3.14
                      type: number
                    date:
                      description: The start date of this sample within the timeseries
                      format: date
                      type: string
                    kw:
                      description: Aggregate statistics for charge rate in kW
                      properties:
                        max:
                          example: 78
                          type: number
                        mean:
                          example: 61
                          type: number
                        min:
                          example: 0
                          type: number
                      required:
                        - min
                        - max
                        - mean
                      type: object
                    kwhSum:
                      description: Total power consumption in kWh
                      example: 120
                      type: number
                    price:
                      description: Aggregate statistics for power price (<CURRENCY> per kWh)
                      properties:
                        max:
                          example: 78
                          type: number
                        mean:
                          example: 61
                          type: number
                        min:
                          example: 0
                          type: number
                      required:
                        - min
                        - max
                        - mean
                      type: object
                  required:
                    - kw
                    - kwhSum
                    - price
                    - costSum
                    - date
                  type: object
                type: array
          description: Successful
      security:
        - UserAccessToken: []
      summary: Get User Charging Statistics
      tags:
        - Statistics
  "/users/{userId}":
    delete:
      description: Deletes a User and all of their data permanently, and invalidates any associated sessions, authorization codes, and access/refresh tokens
      operationId: deleteUsersUserid
      parameters:
        - description: ID of the User
          in: path
          name: userId
          required: true
          schema:
            minLength: 1
            type: string
      responses:
        "204":
          content: {}
          description: No Content
      security:
        - ClientAccessToken: []
      summary: Unlink User
      tags:
        - User Management
  "/users/{userId}/authorization":
    delete:
      description: |-
        Deletes the User's stored vendor authorizations and credentials, invalidates any associated sessions, authorization codes, and access/refresh tokens.

        All other User data is retained, and if the User is sent through the Link User flow in the future their account will be just as they left it.

        No webhook events will be generated for a deauthorized user.
      operationId: deleteUsersUseridAuthorization
      parameters:
        - description: ID of the User
          in: path
          name: userId
          required: true
          schema:
            minLength: 1
            type: string
      responses:
        "204":
          content: {}
          description: No Content
      security:
        - ClientAccessToken: []
      summary: Deauthorize User
      tags:
        - User Management
  "/users/{userId}/link":
    post:
      description: Creates an Enode Link session attached to the provided User ID. If this User does not exist, it will be created. The returned `linkState` gives the user short-lived access to Enode Link.
      operationId: postUsersUseridLink
      parameters:
        - description: ID of the User
          in: path
          name: userId
          required: true
          schema:
            minLength: 1
            type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                forceLanguage:
                  description: BCP47 language code - Force the Link UI to prefer the specified language. If omitted, the UI will default to the user's browser default language.
                  example: nb-NO
                  type: string
                linkMultiple:
                  default: false
                  description: Allow multiple car vendors to be linked during a single Link session. Automatically disabled if `vendor` is set.
                  type: boolean
                userImage:
                  description: Full URL to an image that the user would recognize as being their own. This URL is only stored for the duration of the Link session, and is displayed to the user to reduce the effectiveness of phishing attacks.
                  example: https://cdn.website.example/user/x/profile.jpg
                  type: string
                userName:
                  description: The User's first name, full name, or other identifier that the user would recognize as being their own. This name is only stored for the duration of the Link session, and is displayed to the user to reduce the effectiveness of phishing attacks.
                  example: Ola
                  type: string
                vendor:
                  description: Automatically skip to the credential input screen for this vendor, skipping the Vendor selection menu.
                  enum:
                    - TESLA
                    - BMW
                    - AUDI
                    - VOLKSWAGEN
                    - HYUNDAI
                    - PEUGEOT
                    - NISSAN
                  example: TESLA
                  type: string
              type: object
      responses:
        "200":
          content:
            application/json:
              schema:
                properties:
                  linkState:
                    example: ZjE2MzMxMGFiYmU4MzcxOTU1ZmRjMTU5NGU2ZmE4YTU3NjViMzIwY2YzNG
                    type: string
                type: object
          description: Successful
      security:
        - ClientAccessToken: []
      summary: Link User
      tags:
        - User Management
  /vehicles:
    get:
      operationId: getVehicles
      parameters:
        - description: |-
            An optional array of Vehicle fields that should be included in the response, for example: `?field[]=information&field[]=location` 

            By default, no fields are included and only the Vehicle ID will be returned. Response time may be impacted by which fields you request.
          explode: true
          in: query
          name: field[]
          schema:
            items:
              $ref: "#/paths/~1vehicles~1%7BvehicleId%7D/get/parameters/1"
            type: array
          style: form
      responses:
        "200":
          content:
            application/json:
              schema:
                items:
                  $ref: "#/paths/~1vehicles~1%7BvehicleId%7D/get/responses/200/content/application~1json/schema"
                type: array
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:location
        - UserAccessToken:
            - vehicle:odometer
        - UserAccessToken:
            - vehicle:information
        - UserAccessToken:
            - vehicle:charge_state
        - UserAccessToken:
            - vehicle:smart_charging_policy
      summary: List Vehicles
      tags:
        - Vehicles
  "/vehicles/{vehicleId}":
    get:
      operationId: getVehiclesVehicleid
      parameters:
        - description: ID of the Vehicle
          in: path
          name: vehicleId
          required: true
          schema:
            minLength: 1
            type: string
        - description: |-
            An optional array of Vehicle fields that should be included in the response, for example: `?field[]=information&field[]=location` 

            By default, no fields are included and only the Vehicle ID will be returned. Response time may be impacted by which fields you request.
          explode: true
          in: query
          name: field[]
          schema:
            items:
              enum:
                - smartChargingPolicy
                - chargeState
                - location
                - information
                - odometer
              type: string
            type: array
      responses:
        "200":
          content:
            application/json:
              schema:
                properties:
                  chargeState:
                    $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1charge-state/get/responses/200/content/application~1json/schema"
                  chargingLocationId:
                    description: Id of the charging location the vehicle is currently positioned at (if any)
                    example: 8d90101b-3f2f-462a-bbb4-1ed320d33bbe
                    type: string
                    x-format:
                      guid: true
                  id:
                    description: Vehicle ID
                    type: string
                  information:
                    $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1information/get/responses/200/content/application~1json/schema"
                  isReachable:
                    description: Is the vehicle currently reachable?
                    type: boolean
                  lastSeen:
                    description: The last time vehicle was successfully communicated with
                    format: date
                    type: string
                  location:
                    $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1location/get/responses/200/content/application~1json/schema"
                  odometer:
                    $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1odometer/get/responses/200/content/application~1json/schema"
                  smartChargingPolicy:
                    $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1smart-charging-policy/put/requestBody/content/application~1json/schema"
                required:
                  - id
                  - lastSeen
                  - isReachable
                  - chargingLocationId
                type: object
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:location
        - UserAccessToken:
            - vehicle:odometer
        - UserAccessToken:
            - vehicle:information
        - UserAccessToken:
            - vehicle:charge_state
        - UserAccessToken:
            - vehicle:smart_charging_policy
      summary: Get Vehicle
      tags:
        - Vehicles
  "/vehicles/{vehicleId}/charge-state":
    get:
      operationId: getVehicleChargestate
      parameters:
        - $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1watch/post/parameters/0"
      responses:
        "200":
          content:
            application/json:
              schema:
                properties:
                  batteryCapacity:
                    description: Vehicle's maximum physical battery capacity in kWh. This number slowly decreases/degrades over time.
                    example: 73.21
                    minimum: 0
                    type: number
                  batteryLevel:
                    description: Remaining battery in percent
                    example: "38"
                    maximum: 100
                    minimum: 0
                    type: number
                  chargeLimit:
                    description: Charge limit, as a percent of `batteryCapacity`.
                    example: 80
                    maximum: 100
                    minimum: 0
                    type: number
                  chargeRate:
                    description: |-
                      The current charge rate in kW.

                      This property is only available when the vehicle is charging, and is `null` any other time.
                    example: 40.1
                    minimum: 0
                    type: number
                  chargeTimeRemaining:
                    description: |-
                      Estimated time until the current charging intent is completed, in minutes.

                      This property is only available when the vehicle is charging, and is `null` any other time.
                    example: 319
                    type: number
                  isCharging:
                    description: Current charging status of the vehicle
                    example: false
                    type: boolean
                  isChargingReasons:
                    description: |-
                      Array of string constants that explain why the car is or is not charging. May contain multiple values.

                      **Any:**
                      - DEFAULT - the car is not being controlled by Enode

                      **Not Charging:**
                      - NOT_PLUGGED_IN - because the car is not plugged into a charger
                      - FULLY_CHARGED - because the car is fully charged
                      - MANUALLY_STOPPED - because the car has been manually commanded to stop charging
                      - SMART_CHARGING_DELAY - because Smart Charging has identified an opportunity to delay charging until prices are lower

                      **Charging:**
                      - MANUALLY_STARTED - because the car has been manually commanded to start charging
                      - SMART_CHARGING_ACTIVE - because Smart Charging has identified that this is an optimal time to charge
                      - SMART_CHARGING_DEADLINE - because, regardless of price, charging must be active to meet the configured deadline
                    example:
                      - SMART_CHARGING_DELAY
                    items:
                      enum:
                        - override: true
                        - DEFAULT
                      type: string
                    type: array
                  isPluggedIn:
                    description: Indicates whether the vehicle is connected to a charging box (regardless of whether it is actually charging)
                    example: true
                    type: boolean
                  range:
                    description: Estimated remaining kilometers
                    example: "127.5"
                    minimum: 0
                    type: number
                type: object
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:charge_state
      summary: Get Vehicle Charge State
      tags:
        - Vehicles
  "/vehicles/{vehicleId}/charging":
    post:
      description: |-
        Instruct the vehicle to start or stop charging. 

        #### Precedence over smart charging
        If the vehicle is at a charging location where smart charging is activated:
        - a request to `start` charging will override smart charging and charging will stay on until fully charged. 
        - a request to `stop` charging will override smart charging and charging will be kept off for the duration of the current smart charging cycle.

        The smart charging settings are not altered by these actions.
      operationId: postVehiclesVehicleidCharging
      parameters:
        - $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1watch/post/parameters/0"
      responses:
        "204":
          content: {}
          description: No Content
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - control:vehicle:charging
      summary: Start / Stop Charging
      tags:
        - Vehicles
  "/vehicles/{vehicleId}/information":
    get:
      operationId: getVehiclesVehicleidInformation
      parameters:
        - $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1watch/post/parameters/0"
      responses:
        "200":
          content:
            application/json:
              schema:
                description: Descriptive information about the Vehicle
                properties:
                  brand:
                    description: Vehicle brand
                    example: Tesla
                    type: string
                  id:
                    description: Vehicle ID
                    example: 8d90101b-3f2f-462a-bbb4-1ed320d33bbe
                    type: string
                  model:
                    description: Vehicle model
                    example: Model S P85
                    type: string
                  year:
                    description: Vehicle production year
                    example: 2020
                    type: integer
                type: object
          description: Descriptive information about the Vehicle
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:information
      summary: Get Vehicle Information
      tags:
        - Vehicles
  "/vehicles/{vehicleId}/location":
    get:
      operationId: getVehiclesVehicleidLocation
      parameters:
        - $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1watch/post/parameters/0"
      responses:
        "200":
          content:
            application/json:
              schema:
                description: Vehicle's GPS coordinates with timestamp
                properties:
                  lastUpdated:
                    description: ISO8601 UTC timestamp of last received location
                    example: 2020-04-07T17:04:26Z
                    format: date
                    type: string
                  latitude:
                    description: Latitude in degrees
                    example: 59.911491
                    type: number
                  longitude:
                    description: Longitude in degrees
                    example: 10.757933
                    type: number
                type: object
          description: Vehicle's GPS coordinates with timestamp
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:location
      summary: Get Vehicle Location
      tags:
        - Vehicles
  "/vehicles/{vehicleId}/odometer":
    get:
      operationId: getVehiclesVehicleidOdometer
      parameters:
        - $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1watch/post/parameters/0"
      responses:
        "200":
          content:
            application/json:
              schema:
                description: Vehicle's odometer with timestamp
                properties:
                  distance:
                    description: Odometer in kilometers
                    example: 24650
                    type: number
                  lastUpdated:
                    description: ISO8601 UTC timestamp of last received odometer update
                    example: 2020-01-07T16:21:76Z
                    format: date
                    type: string
                type: object
          description: Vehicle's odometer with timestamp
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:odometer
      summary: Get Vehicle Odometer
      tags:
        - Vehicles
  "/vehicles/{vehicleId}/smart-charging-policy":
    get:
      operationId: getVehiclesVehicleidSmartchargingpolicy
      parameters:
        - $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1watch/post/parameters/0"
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1smart-charging-policy/put/requestBody/content/application~1json/schema"
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:smart_charging_policy
      summary: Get Vehicle Smart Charging Policy
      tags:
        - Vehicles
    put:
      description: Updates the Smart Charging settings for a vehicle
      operationId: putVehiclesVehicleidSmartchargingpolicy
      parameters:
        - description: ID of the Vehicle
          in: path
          name: vehicleId
          required: true
          schema:
            minLength: 1
            type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                deadline:
                  description: The deadline for fully charging the vehicle. Smart charging does not work without setting a deadline. The deadline is expressed as a time on a 24h clock in UTC
                  example: 08:00
                  pattern: \d{2}:\d{2}
                  type: string
                isEnabled:
                  description: When enabled, this vehicle's charging status may be controlled by Smart Charging.
                  example: true
                  type: boolean
              type: object
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1smart-charging-policy/put/requestBody/content/application~1json/schema"
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:smart_charging_policy
      summary: Update Vehicle Smart Charging Policy
      tags:
        - Vehicles
  "/vehicles/{vehicleId}/watch":
    post:
      description: |
        Temporarily triggers high-rate updates of the vehicle's properties, and this state expires automatically. This gives you a way to tell us that user may be interacting with your application and are expecting as-fast-as-possible updates on the status of their vehicle in your UI.

        Any data changes resulting from this high-rate updating are reflected everywhere, whether you pull data from the `Vehicles` endpoint, or recieve it via the [Firehose Webhook](#tag/Webhooks)

        The specifics of the expiration times, watch behaviors, and change thresholds are tuned by us to make sure that they work as expected, without causing undue interruption to the vehicle. For many vendors, it is not appropriate to let the high-rate monitoring last indefinitely, as it will keep systems within the car awake that should be allowed to fall into low-power/standby modes.
      operationId: postVehiclesVehicleidWatch
      parameters:
        - description: ID of the Vehicle
          in: path
          name: vehicleId
          required: true
          schema:
            minLength: 1
            type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                properties:
                  description: Array of vehicle properties to watch
                  enum:
                    - BATTERY_LEVEL
                    - RANGE
                    - IS_PLUGGED_IN
                    - IS_CHARGING
                    - IS_CHARGING_REASONS
                    - LOCATION
                  example:
                    - LOCATION
                    - BATTERY_LEVEL
                  type: string
              type: object
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/paths/~1vehicles~1%7BvehicleId%7D~1watch/post/requestBody/content/application~1json/schema"
          description: Successful
      security:
        - UserAccessToken:
            - all
        - UserAccessToken:
            - vehicle:location
        - UserAccessToken:
            - vehicle:charge_state
      summary: Start Watching Vehicle
      tags:
        - Vehicles
  /webhooks/firehose:
    put:
      operationId: putWebhooksFirehose
      requestBody:
        content:
          application/json:
            schema:
              properties:
                secret:
                  description: A cryptographically secure secret, generated and provided by your client
                  example: 0Kvs1tAUQ69FOMBiWlt5XJSrruXMhWDiVbyrWaNm
                  type: string
                url:
                  description: The HTTPS url to which Enode should POST the event payload when a watched property changes
                  example: https://brainpower.co/enode-webhooks/firehose
                  type: string
                  x-format:
                    uri: true
              type: object
      responses:
        "204":
          content: {}
          description: No Content
      security:
        - ClientAccessToken: []
      summary: Update Firehose Webhook
      tags:
        - Webhooks 🧪
  /webhooks/firehose/test:
    post:
      description: Trigger a test payload to be sent to your configured Firehose Webhook url.
      operationId: postWebhooksFirehoseTest
      responses:
        default:
          content:
            application/json:
              schema:
                type: string
          description: Successful
      security:
        - ClientAccessToken: []
      summary: Test Firehose Webhook
      tags:
        - Webhooks 🧪
components:
  securitySchemes:
    ClientAccessToken:
      description: |
        A `ClientAccessToken` access token is obtained via the [OAuth 2.0 Client Credentials grant](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/)

        When accessing protected resources, the token should be provided in a Bearer authorization header as specified in [RFC6750](https://tools.ietf.org/html/rfc6750#section-2.1)

        Example:
        ```
        DELETE /users/xyz HTTP/1.1
        Authorization: Bearer yQ89j3LAnqBx42gWGUl4v-jxoS1mfTAH3Q52WTGrExw.zgRcRrE6KRKUgVQEVr2Pifub8Z7trCZrobKjvhGIOTI
        ```

        You can read more about obtaining this token in the [Authorization](#section/Authorization) section
      flows:
        clientCredentials:
          scopes: {}
          tokenUrl: https://link.test.enode.io/oauth2/token
      type: oauth2
    UserAccessToken:
      description: |
        A `UserAccessToken` access token is obtained via the [OAuth 2.0 Authorization Code grant](https://www.oauth.com/oauth2-servers/access-tokens/authorization-code-request/)

        This token represents the authorization for the bearer to access resources on behalf of the user who authorized it. This authorization is further limited by scopes. When relevant, the `scope` required by each endpoint is listed in the documentation for that endpoint.

        When accessing protected resources, the token should be provided in a Bearer authorization header as specified in [RFC6750](https://tools.ietf.org/html/rfc6750#section-2.1)

        Example:
        ```
        GET /vehicles HTTP/1.1
        Authorization: Bearer yQ89j3LAnqBx42gWGUl4v-jxoS1mfTAH3Q52WTGrExw.zgRcRrE6KRKUgVQEVr2Pifub8Z7trCZrobKjvhGIOTI
        ```

        You can read more about obtaining this token in the [Authorization](#section/Authorization) section
      flows:
        authorizationCode:
          authorizationUrl: https://link.test.enode.io/oauth2/auth
          scopes:
            all: Read and write all resources
            charger:charge_state: Read charger charge state
            charger:information: Read charger information
            charging_location: Read & write user's charging locations
            control:charger:charging: Control charger charging
            control:vehicle:charging: Control vehicle charging
            vehicle:charge_state: Read vehicle charge state
            vehicle:information: Read vehicle information
            vehicle:location: Read vehicle location
            vehicle:odometer: Read vehicle odometer
            vehicle:smart_charging_policy: Read & write vehicle smart charging policy
          tokenUrl: https://link.test.enode.io/oauth2/token
      type: oauth2
