Skip to content

britned/empire-platform-api

Repository files navigation

Empire

OpenAPI specification for the Platform API of Empire, the allocation and nomination platform of BritNed

GitHub - Version PyPI - Version


The Platform API is a REST-style HTTP API operating mostly with JSON payloads. The OpenAPI specification contains every endpoint that is available for Participants to consume. Endpoints are identified and referred to by their Operation ID e.g. getTimescaleNominations throughout the documentation, the terms "endpoint" and "operation" used interchangeably.

Empire is being developed in an API-first approach. The semantically versioned specification is used internally to generate code in order to make sure that the API contract is matched with the backend implementation. Consumers of the API are also encouraged to utilise code generation to achieve consistent communication using each version of the contract.

⚠️ Usage of the Platform API is subject to our API Terms of Use which you can find as a PDF file in this repository as well!

Resouces:

Table of Contents

πŸƒ Getting Started

In order to programmatically use the Platform API Participants must have a valid user account and need to obtain an API Key. Follow these steps to generate one:

  1. First visit an available environment of Empire through its Web Frontend URL
  2. Click Login and use your your email address, password and 2FA token to authenticate
  3. When logged in click on your name in the top-right corner
  4. Select API Keys from the pop-up menu
  5. Click on the New API Key button
  6. Choose a unique name to your API Key and click the Generate API Key button
  7. Copy and save your API Key, the string starting with emp_

As described in the AuthToken security scheme, the API Key-based authentication is using the X-API-Key request header.

In order to test the newly generated API Key you can try to execute the getProfile operation by replacing <API_BASE_URL> and <API_KEY> with the respective values and should receive a 200 OK HTTP response.

curl -X 'GET' \
  '<API_BASE_URL>/v1/profile' \
  -H 'accept: application/json' \
  -H 'X-API-Key: <API_KEY>'

⚠️ Please always make sure you test your API Key on the environment that you generated your key on as API Keys are NOT shared between the different environments!

πŸ’‘ Users that are not registered with BritNed are able to use the endpoints prefixed with /v1/public/... for fetching publicly available data from Empire. See the API Navigator for more information. Please also refer to the relevant Public Data page on the Wiki for more information.

πŸ”Œ Environments

Empire offers two environments for the Participants to use:

Environment Web Frontend URL API Base URL
PRODUCTION https://empire.britned.com https://api.empire.britned.com
TRAINING https://training.empire.britned.com https://api.training.empire.britned.com

The PRODUCTION environment means the all-time live deployment of Empire. Interacting with it through the API will result in submitting "real" bids, nominations, etc with all their consequences.

The TRAINING environment however can be used to onboard new members of your Organisations and test your API integrations in a testing environment. Changes in the Platform API (bug fixes, new features, breaking changes) are also made available on the TRAINING environment in a pre-determined schedule.

πŸ’‘ You can use the 🧭 API Navigator to determine which version of the Platform API is currently deployed on each environment. Just open the version selector dropdown in the top-right corner of the page.

πŸŽ“ General Concepts

❓ What is Participant ID

Many endpoints require submitting a so-called Participant ID in its parameters, for example getDefaultBids, submitDefaultBids, getDefeaultNominations etc.

Empire handles different types of Organisations in the system, and one of these types are Participants. A Participant ID is essentially the ID of a Participant-type Organisation. To determine your Participant ID you can use the getProfile operation:

curl -X 'GET' \
  '<API_BASE_URL>/v1/profile' \
  -H 'accept: application/json' \
  -H 'X-API-Key: <API_KEY>'

which will return the following data structure:

{
  "user": {
    "id": "64f8c88a-6fbd-4fda-8bda-d579f87b13d3",
    "name": "Example User",
    "email": "email@example.com",
    "role": "PART_ADMIN",
    "organisation": {
      "id": "5c6a088a-93b6-433c-8538-b7488207df39",     <<< Participant ID
      "name": "Test Participant",
      "authMethod": "PLATFORM"
    }
  },
  "permissions": [
    "VIEW_PUBLISHED_AUCTIONS",
    "MANAGE_LT_AUCTION_BIDS",
    "MANAGE_DA_ID_AUCTION_BIDS",
    ...
  ],
  "appearance": "DEFAULT",
  "impersonatedBy": null
}

As highlighted in the JSON response, the Participant ID is the value in the user.organisation.id field - the ID of the Organisation that the owner of the API Key belongs to.

The Partcipant ID can be treated as a constant in your integrations, it won't ever change in Empire.

πŸ’‘ To ease the testing process Participant IDs are kept in sync between environments, which is generally NOT true for other IDs (e.g. User IDs, Auction IDs, etc), those are all unique and different on each environment.

πŸ‘₯ Roles and Permissions

In Empire each individual User is assigned a Role which encapsulates a set of Permissions. This information can be retrieved using the getProfile operation as seen previously in the What is Participant ID section (fields user.role and permissions[]).

In the API each endpoint is annotated with a list of Permissions documented in the x-permissions field, the values being validated against the #/components/schemas/Permission enum:

  /v1/attachments:
    post:
      operationId: uploadAttachment
      description: |
        ...
      tags:
        - attachment
      security:
        - ApiKey: []
        - AuthToken: []
      x-permissions:
        - MANAGE_CRISIS_ACTIONS
        - INVITE_USERS
        - MANAGE_OWN_MANUAL_FILE_UPLOAD_BIDS
        - MANAGE_OWN_MANUAL_FILE_UPLOAD_NOMINATIONS
        - MANAGE_ANY_MANUAL_FILE_UPLOAD
        - MANAGE_ANY_ORGANISATION_DOCUMENTS
        - MANAGE_OWN_ORGANISATION_DOCUMENTS
      requestBody:
        ...

The first line of authorization is implemented based on these attached Permissions. In the example above the uploadAttachment operation can be executed if at least one of the listed seven Permissions is granted to the User. If none of the listed Permissions is granted, the endpoint will return a HTTP 403 status with the FORBIDDEN error code.

Naturally additional authorization logic can be added to individual operations. Take the getDefaultBids operation as an example:

  /v1/default-bids:
    get:
      operationId: getDefaultBids
      description: |
        ...
      tags:
        - default-bid
      security:
        - ApiKey: []
        - AuthToken: []
      x-permissions:
        - VIEW_OWN_DEFAULT_BIDS
        - VIEW_ANY_DEFAULT_BIDS
      parameters:
        ...
        - $ref: '#/components/parameters/ParticipantId'
        ...
      responses:
        ...

In this case the getDefaultBids operation can be called with either VIEW_OWN_DEFAULT_BIDS or VIEW_ANY_DEFAULT_BIDS. However if the User has the VIEW_OWN_DEFAULT_BIDS Permission, they MUST send their own Participant ID in the request. Failing to do so will also result in a 403 FORBIDDEN error response from the API.

β›” Errors and Validations

Each endpoint in the Platform API can be a subject of a set of Validations, like validating User authentication or authorization, or applying different complex business on validations on requests.

When any of these validations happens to fail, Empire will respond with a semantically correct HTTP Status (e.g HTTP 404 for non-existing entities in the system) and an Error Code to be able to tell apart the different errors that could have happened during execution.

πŸ’‘ With PUT/POST/DELETE-type operations (Bid submission, Nomination submission, etc) when no errors were detected and there is no point in returning any response body, Empire generally returns the "204 No Content" response status to act as a positive acknowledgement.

Errors are documented for the different status codes under the x-errors field. The values of x-errors[*].code is validated against the #/components/schemas/ErrorCode schema.

Below is a full example taken from the submitTimescaleNominations opreation:

  /v1/nominations/timescale:
      operationId: submitTimescaleNominations
      ...
      responses:
        '204':
          $ref: '#/components/responses/NoContent'
        '400':
          ...
          x-errors:
            - code: INVALID_PARTICIPANT_ID
              description: specified Participant not found in the system
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          ...
          x-errors:
            - code: MTU_LIST_MISALIGNED
              description: |
                - one or more MTU start times are not aligned to MTU borders (considering MTU size)
                - the number of MTUs defined does not match the required number (pay special attention to daylight saving changes!)
            - code: MTU_NOT_EDITABLE
              description: |
                - only MTUs that are in `mtuStatus = EDITABLE` can contain not-empty values
                - an MTU can be non-editable because:
                  - the MTU nomination window for the selected timescale is closed
                  - has already FIRM or LOCKED nominations
            ...
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

There are several standard HTTP Status and Error Code combinations which are always used in the following pairs:

HTTP Status Error Code Description
401 Unauthorized UNAUTHORIZED failed to authenticate, e.g problem with API Key
403 Forbidden FORBIDDEN authorization failed, e.g insufficient Permissions
404 Not Found NOT_FOUND entity with the given ID is not found in the system

On top of the above Empire generally utilises three other HTTP Statuses to handle custom business validations:

HTTP Status Error Code Description Example
400 Bad Request vary request is "conceptually" wrong the getLongTermAuction endpoint is called with an ID of a Day-Ahead Auction
422 Unprocessable Entity vary some value in request failed validations the User want to nominate more Capacity than the amount of TRs they have in submitLongTermAuctions
409 Conflict vary conflicting internal state results is not (yet) available as Clearing has not happened in getLongTermAuctionResults

πŸ“Š Data Formats

Date/Time handling

The System Time of Empire is Europe/Amsterdam. The "delivery days" are interpreted in this time, following the regular DST changes between the CET and CEST timezones.

Absolute points in time are represented with the #/components/schemas/DateTime schema in the specification. These values are always returned and required to be sent in UTC (a.k.a "Zulu time") in ISO 8601 format e.g 2023‐08‐24T15:17:54.123Z.

Capacity values

Capacity values throughout the Platform API are represented with the #/components/schemas/Capacity schema. It defines that capacity values are to be sent and will be received as integers interpreted in kilowatt (kW) units.

Currency values

Currency values (as seen in #/components/schemas/Currency) are defined as decimal numbers with a precision of maximum 2 decimal places, and interpreted in Euros (€).

🐍 Python Client SDK

​ A Python Client SDK is automatically generated from the OpenAPI specification and published to PyPi under the empire-platform-api-public-client project.

In order use the Python Client SDK with the authenticated API endpoints you will need to generate an API Key in Empire, see more in the Getting Started section. ​ After installing the package you will be able to use the client by first instantiating a Configuration class and creating an ApiClient instance: ​

configuration = Configuration(
    api_key={"ApiKey": "<your empire api key>"},
    host="https://api.training.empire.britned.com"
)
client = ApiClient(configuration=configuration)

The ApiClient instance then can be used to construct individual clients for the different API categories. ​

⚠️ Please make sure you use the right API Base URL of the environment you wish to use in the host parameter!

An example for retrieving ten Auctions ordered by the start of their bidding periods: ​

auction_api = AuctionApi(api_client=client)
auctions = auction_api.get_auctions(
    limit=10,
    offset=0,
    sort_by=AuctionSortBy.BIDDING_PERIOD_START_DESC
)
print(auctions)

❗ When dealing with datetime objects, please do NOT use "naive" objects, always stick to "aware" ones, which include timezone information, otherwise your request will fail.

Example of correct datetime handling:

from datetime import datetime, timezone

beginning_of_year = datetime(2023, 1, 1, 0, 0, 0, 0, timezone.utc)
beginning_of_year.isoformat()

now = datetime.now(timezone.utc)
now.isoformat()

# notice the correct `+00:00` timezone suffixes

πŸ“– Changelog

Changes in particular versions of the API Specification (in the πŸ“š openapi.yaml file) are automatically tracked in CHANGELOG.md.

  • 2023-08-24 Improve API documentation and formatting
  • 2023-08-14 Added changelog generation for API changes
  • 2023-08-10 Access multiple versions of the API spec on GitHub Pages
  • 2023-07-19 Published a new version of the API spec and added instructions to use the python client
  • 2023-04-04 Web-based navigation of the API spec, through GitHub Pages added, updated the README accordingly.
  • 2023-04-03 Added Readme and open up the repository to the public internet
  • 2023-03-27 API Terms of Use v1 published, effective 31.3.2023
  • 2022-03-21 Place holder for Terms of Use