API documentation

Introduction

Line Rating Forecast API Documentation

This guide explains how to use the Line Rating Forecast API to retrieve forecasted line ratings and weather data.

The documentation is designed to provide useful examples for a user who is familiar with Python and who wants to create a simple integration to explore the API, for professional use, we recommend to generate integration from the Open API spec (details at the end of the guide)

Overview

  • Lines: List all power lines, optionally filtered by status.
  • Line Rating Forecasts: Get forecasted ratings for a specific power line up to 10 days ahead.
  • Weather Sites: List all available sites with their details.
  • Weather Forecasts: Retrieve weather forecasts for specific sites.

Base URLs

  • Test: https://dev-claw.gridraven.com/api/public
  • Production: https://claw.gridraven.com/api/public

Authentication

API Key is used in Bearer token for authentication.

Key can be obtained from https://claw.gridraven.com/claw-api after logging in.

python
1import http.client
2
3conn = http.client.HTTPSConnection("claw.gridraven.com")
4
5headers = { 'Authorization': "Bearer YOUR_SECRET_TOKEN" }
6
7conn.request("GET", "/api/public/xxx", headers=headers)

Endpoints

1. Get All Lines

Endpoint: /lines

Method: GET

Description: Lists all lines, optionally filtered by status.

Parameters:

  • status (optional, query): Filter by line status (active, inactive, draft).

Example Request:

python
1requests.get(
2 "https://claw.gridraven.com/api/public/lines",
3 headers={
4 "Authorization": "Bearer YOUR_SECRET_TOKEN"
5 },
6 params={
7 "status": "active"
8 }
9)

Example Response:

json
1{
2 "status_code": 200,
3 "lines": [
4 {
5 "id": "eb8647ac-0aec-42c5-b1f5-0fc39fc864a9",
6 "external_id": "L007",
7 "name": "Line from A to B",
8 "status": "active"
9 },
10 {
11 "id": "019cddd3-a4e9-79eb-a18c-1123d27c4a9e",
12 "external_id": "L008",
13 "name": "Line from C to D",
14 "status": "active"
15 }
16 ]
17}

Errors:

Errors return a JSON object with:

  • status_code: HTTP status (e.g., 400, 404).
  • code: Machine-readable error code (e.g., "NOT_FOUND").
  • message: Human-readable error message.

Example Error:

json
1{
2 "status_code": 404,
3 "code": "NOT_FOUND",
4 "message": "Line '12345ABC' not found"
5}

2. Get the latest line rating forecast

Endpoint: /lines/{line_id}/rating-forecasts

Method: GET

Description: Retrieves the latest forecast for a specific power line, including dynamic line ratings (DLR), ambient adjusted ratings (AAR), and seasonal ratings (SR).

The length of forecast depends on the forecast configuration and available data.

Parameters:

  • line_id (required, in path): The ID of the line (e.g., "eb8647ac-0aec-42c5-b1f5-0fc39fc864a9").

Example Request:

python
1requests.get(
2 "https://claw.gridraven.com/api/public/lines/{line_id}/rating-forecasts",
3 headers={
4 "Authorization": "Bearer YOUR_SECRET_TOKEN"
5 }
6)

Example Response:

json
1{
2 "status_code": 200,
3 "line_id": "eb8647ac-0aec-42c5-b1f5-0fc39fc864a9",
4 "line_external_id": "12345ABC",
5 "line_name": "Main Transmission Line",
6 "created_at": "2025-11-11T10:30:00Z",
7 "scheme": "V1",
8 "reference_time": "2023-10-23T13:00:00Z",
9 "results": [
10 {
11 "valid_start": "2023-10-23T13:00:00Z",
12 "valid_end": "2023-10-23T14:00:00Z",
13 "step": "PT1H",
14 "duration": "PT1H",
15 "ratings": {
16 "sr": 100.1,
17 "mean_dlr": 150.1,
18 "dlr": {
19 "50": 150.1,
20 "75": 200.2,
21 "90": 250.2
22 },
23 "aar": 140.2
24 }
25 }
26 ],
27 "recalculation_id": null
28}

Errors:

javascript
1{
2 "status_code": 404,
3 "code": "NOT_FOUND",
4 "message": "Line '12345ABC' not found"
5}

3. Get past line rating forecast series

Returns past line rating forecast results within the specified valid time and adjusted step. Valid results are available for the time period the line was active.

How step adjustment works: The from and to parameters specify the valid time range (when the forecast prediction applies). The system finds forecasts whose reference time plus the step falls within this range. For example, with step=24 and valid time range 2025-02-15 to 2025-02-16, the system retrieves forecasts made on 2025-02-14 to 2025-02-15 (24 hours earlier), because those forecasts predicted the requested valid time range.

JSON format is limited to 7 days of data. Parquet format is limited to 60 days.

Path Parameters:

  • line_id string required

    Line ID or external ID.

Query Parameters:

  • from Type:string Format:date-time required

    Start of valid time range (ISO-8601 with timezone required). This is when the forecast prediction applies, not when the forecast was made. E.g. 2023-10-23T13:00:00Z

  • to Type:string Format:date-time required

    End of valid time range (ISO-8601 with timezone required). This is when the forecast prediction applies, not when the forecast was made. E.g. 2023-10-25T17:00:00Z

  • format

    Response format. JSON is limited to 7 days, Parquet to 60 days.

  • step Type:integer min: 0 max: 240 required

    Forecast horizon in hours (e.g., 0=nowcast, 24=24-hour-ahead). The system returns the rating prediction at this step from each forecast. The step determines how far ahead the forecast was predicting: step=0 means the forecast for the current hour (nowcast), step=24 means the 24-hour-ahead prediction.

Example Request:

javascript
1requests.get(
2 "https://claw.gridraven.com/api/public/lines/{line_id}/rating-forecast-series",
3 headers={
4 "Authorization": "Bearer YOUR_SECRET_TOKEN"
5 },
6 params={
7 "from": "",
8 "to": "",
9 "format": "json",
10 "step": "0"
11 }
12)

Example Responses

  1. 200 List of Rating Forecasts
javascript
1{
2 "line_id": "eb8647ac-0aec-42c5-b1f5-0fc39fc864a9",
3 "line_external_id": "L001",
4 "line_name": "Main Transmission Line",
5 "step": "PT24H",
6 "duration": "PT1H",
7 "results": [
8 {
9 "reference_time": "2023-10-23T13:00:00Z",
10 "created_at": "2023-10-23T13:43:21Z",
11 "valid_start": "2023-10-24T13:00:00Z",
12 "valid_end": "2023-10-24T14:00:00Z",
13 "ratings": {
14 "sr": 100.1,
15 "mean_dlr": 150.1,
16 "dlr": {
17 "50": 150.1,
18 "75": 200.2,
19 "90": 250.2
20 },
21 "aar": 140.2
22 }
23 }
24 ]
25}
  1. 400, 404 Error for client statuses 4xx
javascript
1{
2 "status_code": 400,
3 "code": "NOT_FOUND",
4 "message": "Line '12345ABC' not found"
5}

4. Get seasonal rating for a line over a time period

Returns seasonal rating values for the given line over the specified time period. Time period can be up to multiple years. Results are returned as unique rating segments where consecutive periods with the same rating value are merged.

Path Parameters:

  • line_id string required

    Line ID or external ID.

Query Parameters:

  • start Type:string, Format:date-time required

    UTC start timestamp in ISO 8601 format (e.g., '2025-11-11T00:00:00Z')

  • end Type:string, Format:date-time required

    UTC end timestamp in ISO 8601 format (e.g., '2025-11-12T00:00:00Z')

Example Request:

javascript
1requests.get(
2 "https://claw.gridraven.com/api/public/lines/{line_id}/rating-seasonal",
3 headers={
4 "Authorization": "Bearer YOUR_SECRET_TOKEN"
5 },
6 params={
7 "start": "",
8 "end": ""
9 }
10)

Example Responses

  1. 200 Seasonal ratings retrieved successfully
javascript
1{
2 "status_code": 200,
3 "line_id": "eb8647ac-0aec-42c5-b1f5-0fc39fc864a9",
4 "line_external_id": "12345ABC",
5 "line_name": "Main Transmission Line",
6 "created_at": "2025-11-11T10:30:00Z",
7 "scheme": "V1",
8 "results": [
9 {
10 "valid_start": "2023-10-23T13:00:00Z",
11 "valid_end": "2023-10-23T14:00:00Z",
12 "step": "PT1H",
13 "duration": "PT1H",
14 "ratings": {
15 "sr": 100.1,
16 "mean_dlr": 150.1,
17 "dlr": {
18 "50": 150.1,
19 "75": 200.2,
20 "90": 250.2
21 },
22 "aar": 140.2
23 }
24 }
25 ]
26}
  1. 400, 404 Error for client statuses 4xx
javascript
1{
2 "status_code": 400,
3 "code": "NOT_FOUND",
4 "message": "Line '12345ABC' not found"
5}

5. Get all available sites

Endpoint: /sites

Method: GET

Description: Lists all sites with their IDs, latitude, longitude, and status.

Query Parameters

  • type array SiteType[]

    Filter sites by type. Supports multiple values.

Example Request:

python
1requests.get(
2 "https://claw.gridraven.com/api/public/sites",
3 headers={
4 "Authorization": "Bearer YOUR_SECRET_TOKEN"
5 },
6 params={
7 "type": "line"
8 }
9)

Example Response:

json
1{
2 "status_code": 200,
3 "items": [
4 {
5 "id": "-20.12345_-40.12345",
6 "lat": -20.12345,
7 "lon": -40.12345,
8 "status": "active"
9 }
10 ]
11}

6. Get weather stations

Endpoint: /weather-stations

Method: GET

Description: Returns a paginated list of weather stations for the organization. Usually, EPSG:4326 (WGS84) is used for crs.

Query Parameters:

  • page Type:integer, min:1, default:1

    Page index (1-based) for pagination

  • page_size Type:integer, min:1, default: 1000

    Number of items per page for pagination

Example Request:

javascript
1requests.get(
2 "https://claw.gridraven.com/api/public/weather-stations",
3 headers={
4 "Authorization": "Bearer YOUR_SECRET_TOKEN"
5 },
6 params={
7 "page": "1",
8 "page_size": "1000"
9 }
10)

Example Response:

javascript
1{
2 "status_code": 200,
3 "page": 1,
4 "pageSize": 50,
5 "totalItems": 157,
6 "totalPages": 3,
7 "items": [
8 {
9 "id": "019401f9-5c4e-71a3-86c9-aef1d95f12a3",
10 "external_id": "WS-001",
11 "name": "Main Weather Station",
12 "site_id": "55.04979_-24.15618",
13 "lat": 55.04979,
14 "lon": -24.15618,
15 "crs": "EPSG:4326",
16 "status": "active"
17 }
18 ]
19}

7. Get the latest weather forecast for sites

Endpoint: /weather-forecasts

Method: GET

Description: Retrieves weather forecasts for specific sites, including wind speed, direction, temperature, and solar irradiance. Requires at least one query parameter (site_ids or all).

Parameters:

  • site_ids (optional, query): Comma-separated site IDs (e.g., "-20.12345_-40.12345,-21.12345_-41.12345").
  • all (optional, query): Set to true to include all sites.
  • page (optional, query): Page number (default: 1).
  • page_size (optional, query): Items per page (default: 1000).

Example Request:

python
1requests.get(
2 "https://claw.gridraven.com/api/public/weather-forecasts",
3 headers={
4 "Authorization": "Bearer YOUR_SECRET_TOKEN"
5 },
6 params={
7 "page": "1",
8 "page_size": "1000",
9 "site_ids": "",
10 "all": "true"
11 }
12)

Example Response:

json
1{
2 "status_code": 200,
3 "page": 1,
4 "pageSize": 50,
5 "totalItems": 157,
6 "totalPages": 3,
7 "items": [
8 {
9 "site_id": "-20.12345_-40.12345",
10 "created_at": "2023-10-23T13:43:21Z",
11 "reference_time": "2023-10-23T13:00:00Z",
12 "scheme": "V1",
13 "results": [
14 {
15 "valid_start": "2023-10-23T13:00:00Z",
16 "valid_end": "2023-10-23T14:00:00Z",
17 "step": "PT1H",
18 "duration": "PT1H",
19 "ratings": {
20 "wind_speed": 4.4,
21 "wind_direction": 180.3,
22 "temperature": 10.3,
23 "solar_irradiance": 22.2,
24 "confidence_intervals": {
25 "50": {
26 "l_wind_speed": 3.3,
27 "u_wind_speed": 9.9,
28 "l_wind_direction": 180.3,
29 "r_wind_direction": 270.6
30 },
31 "75": {
32 "l_wind_speed": 3.3,
33 "u_wind_speed": 9.9,
34 "l_wind_direction": 180.3,
35 "r_wind_direction": 270.6
36 },
37 "90": {
38 "l_wind_speed": 3.3,
39 "u_wind_speed": 9.9,
40 "l_wind_direction": 180.3,
41 "r_wind_direction": 270.6
42 },
43 "95": {
44 "l_wind_speed": 3.3,
45 "u_wind_speed": 9.9,
46 "l_wind_direction": 180.3,
47 "r_wind_direction": 270.6
48 },
49 "98": {
50 "l_wind_speed": 3.3,
51 "u_wind_speed": 9.9,
52 "l_wind_direction": 180.3,
53 "r_wind_direction": 270.6
54 },
55 "99": {
56 "l_wind_speed": 3.3,
57 "u_wind_speed": 9.9,
58 "l_wind_direction": 180.3,
59 "r_wind_direction": 270.6
60 }
61 }
62 }
63 }
64 ]
65 }
66 ]
67}

Errors:

javascript
1{
2 "status_code": 200,
3 "code": "NOT_FOUND",
4 "message": "Line '12345ABC' not found"
5}

Tips for Beginners

  • Check Responses: Always check response.status_code to handle errors.

This API is straightforward to use with Python and provides valuable data for managing power lines and sites. Start with the example code above and explore the endpoints!

Minimal Weather API Example

python
1import json
2from urllib.request import Request, urlopen
3from urllib.error import HTTPError
4
5# Replace with your API key
6API_KEY = "xxx"
7
8BASE_URL = "https://claw.gridraven.com/api/public"
9
10
11def api_get(path):
12 req = Request(f"{BASE_URL}{path}", headers={"Authorization": f"Bearer {API_KEY}"})
13 return json.loads(urlopen(req).read())
14
15
16def get_weather_forecasts():
17 # Get list of available sites
18 sites = api_get("/sites")["items"]
19
20 # Use first site (join all site IDs with commas to query all sites)
21 site_id = sites[0]["id"]
22
23 # Get weather forecasts
24 try:
25 forecast = api_get(f"/weather-forecasts?site_ids={site_id}")
26 print(json.dumps(forecast, indent=4))
27 except HTTPError as e:
28 detail = json.loads(e.read())["detail"]
29 print(f"Error {e.code}: {detail}")

Full Example

This implementation can be used as follows

python
1import json
2import logging
3from urllib.request import Request, urlopen
4from urllib.error import HTTPError
5from urllib.parse import urlencode
6
7# 3rd party library that needs to be installed separately
8import pandas
9
10logger = logging.getLogger(__name__)
11
12API_KEY = "xxx"
13BASE_URL = "https://claw.gridraven.com/api/public"
14
15
16def api_get(path, params=None):
17 url = f"{BASE_URL}{path}"
18 if params:
19 url += f"?{urlencode(params)}"
20 req = Request(url, headers={"Authorization": f"Bearer {API_KEY}"})
21 return json.loads(urlopen(req).read())
22
23
24def get_all_lines():
25 try:
26 return pandas.DataFrame(api_get("/lines")["lines"])
27 except HTTPError as e:
28 logger.error(f"Failed to get lines: {e.code}")
29 return None
30
31
32def get_line_rating(line_id_list, period_start=None, period_end=None):
33 # If input is string, assume single line and convert to list
34 if isinstance(line_id_list, str):
35 line_id_list = [line_id_list]
36
37 # Convert inputs to datetime if provided
38 if period_start:
39 period_start = pandas.to_datetime(period_start)
40 if period_end:
41 period_end = pandas.to_datetime(period_end)
42
43 line_data_list = []
44
45 for line_id in line_id_list:
46 try:
47 raw_data = api_get(f"/lines/{line_id}/rating-forecasts")
48 logger.debug(raw_data)
49
50 data = pandas.json_normalize(raw_data["results"])
51 data["line_id"] = raw_data["line_id"]
52 data["line_name"] = raw_data["line_name"]
53 data["line_external_id"] = raw_data["line_external_id"]
54 data["created_at"] = raw_data["created_at"]
55
56 line_data_list.append(data)
57 except HTTPError:
58 logger.warning(f"Could not get rating for line: {line_id}")
59
60 if not line_data_list:
61 logger.error("No line data available")
62 return None
63
64 rates = pandas.concat(line_data_list, ignore_index=True)
65
66 rates["start"] = pandas.to_datetime(rates["valid_start"])
67 rates["end"] = pandas.to_datetime(rates["valid_end"])
68
69 # All periods that start after or at given time
70 if period_start and not period_end:
71 rates = rates[rates["start"] >= period_start]
72
73 # All periods that end before or at given time
74 if period_end and not period_start:
75 rates = rates[rates["end"] <= period_end]
76
77 # All periods that overlap with given start and end
78 if period_start and period_end:
79 rates = rates[
80 (rates["start"] < period_end) & # Period starts before query ends
81 (rates["end"] > period_start) # Period ends after query starts
82 ]
83
84 return rates
85
86
87def get_all_weather_sites():
88 try:
89 return pandas.DataFrame(api_get("/sites")["items"])
90 except HTTPError as e:
91 logger.error(f"Failed to get sites: {e.code}")
92 return None
93
94
95def get_weather_forecast(site_id_list=None):
96 if isinstance(site_id_list, str):
97 site_id_list = [site_id_list]
98
99 current_page = 1
100 total_pages = 1
101 items_list = []
102
103 while current_page <= total_pages:
104 params = {}
105
106 if site_id_list:
107 params["site_ids"] = ",".join(site_id_list)
108 else:
109 params["page"] = current_page
110 params["page_size"] = 100
111 params["all"] = "true"
112
113 logger.debug(f"Making query {params} to {BASE_URL}/weather-forecasts")
114 raw_data = api_get("/weather-forecasts", params=params)
115
116 current_page = int(raw_data["page"])
117 total_pages = int(raw_data["totalPages"])
118
119 if items := raw_data.get("items"):
120 items_list.extend(items)
121
122 current_page += 1
123
124 logger.debug(f"Converting {len(items_list)} items to dataframe")
125 results_list = []
126
127 for item in items_list:
128 if results := item.get("results"):
129 results_data = pandas.json_normalize(results)
130 results_data["site_id"] = item.get("site_id")
131 results_data["created_at"] = item.get("created_at")
132 results_data["reference_time"] = item.get("reference_time")
133 results_list.append(results_data)
134
135 if results_list:
136 data = pandas.concat(results_list)
137 logger.debug(f"Converted {len(items_list)} items to {len(data)} results")
138 return data
139
140 logger.debug(f"No results for {site_id_list}")
141 return None
142
143
144if __name__ == "__main__":
145 logging.basicConfig(
146 level=logging.DEBUG,
147 format="%(asctime)s.%(msecs)03d [%(levelname)s] %(name)s: %(message)s",
148 datefmt="%Y-%m-%dT%H:%M:%S",
149 )
150
151 # Get all Lines
152 line_data = get_all_lines()
153
154 # Get Line Ratings
155 line_id = "L001" # Single ID as string
156 line_id = ["L001", "L002"] # Or list of IDs
157 line_id = line_data.query("status == 'active'").id.to_list() # Or all "active" lines
158 line_id = line_data.id.to_list() # Or all lines
159
160 rates = get_line_rating(line_id) # optionally: period_start="2025-05-13T10:00Z", period_end="2025-05-13T12:00Z"
161 print(rates[["line_external_id", "start", "end", "ratings.dlr.50"]])
162
163 # Get all Weather Sites
164 all_sites = get_all_weather_sites()
165
166 # Get Weather Forecasts
167 site_id = "ID1" # Single ID as string
168 site_id = ["ID1", "ID2", "ID3"] # Or list of IDs
169 site_id = all_sites.id.to_list() # Or all available sites
170
171 forecast_data = get_weather_forecast(site_id)

OpenAPI Specification

The OpenAPI Specifications provide a formal standard for describing HTTP APIs, allowing clients to inspect the endpoints and generate API clients using tools.

Inspecting OpenAPI Endpoints using Swagger

The public api endpoints have an OpenAPI spec which can be used to inspect the endpoints using a Swagger editor: https://editor.swagger.io/

Generating Python client from OpenAPI

Instead of writing your own client code with requests package, you can use openapi-generator-cli to generate the client library. This also creates the response domain objects in Python.

uv is required in order for this script to work.

javascript
1#!/bin/bash
2GEN_VERSION=7.10.0
3
4# Generate Python client
5PYTHON_CLIENT_DIR="claw_client"
6rm -rf $PYTHON_CLIENT_DIR
7mkdir -p $PYTHON_CLIENT_DIR
8
9uvx openapi-generator-cli@"$GEN_VERSION" generate \
10 -i ./gridraven-public-api.yaml \
11 -g python \
12 --global-property apis,supportingFiles,models,apiTests=false,modelTests=false \
13 --additional-properties=packageName=claw_client,basePath=/api/public \
14 -o $PYTHON_CLIENT_DIR