OpenAPI specification for the Platform API of Empire, the allocation and nomination platform of BritNed
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:
- π§ API Navigator - the recommended way of exploring the API
- π openapi.yaml - the latest specification in OpenAPI 3.0.3 format
- π©βπ« Wiki - demonstration of various API use-cases to ease the integration
- with supporting business logic including Auctions, Nominations, etc
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:
- First visit an available environment of Empire through its Web Frontend URL
- Click Login and use your your email address, password and 2FA token to authenticate
- When logged in click on your name in the top-right corner
- Select API Keys from the pop-up menu
- Click on the New API Key button
- Choose a unique name to your API Key and click the Generate API Key button
- 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.
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.
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 protected]",
"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.
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.
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 |
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 (β¬).
β
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 thehost
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
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