Quickstart
Verify your key, create a site with assets, upload production, and read it back.
This walkthrough takes a fresh workspace to its first chart-ready dataset in four calls. It assumes the BASE and HEADERS setup from Authentication.
1. Verify the key
r = requests.get(f"{BASE}/objects", headers=HEADERS)
r.raise_for_status()
print([t["name"] for t in r.json()["items"]])If this returns ['sites', 'assets'] (plus any custom types), you are authenticated and talking to the right workspace.
2. Create a site with its assets
Every record is written as name plus values. Sites need coordinates in values; assets can be included inline and are created atomically with the site.
r = requests.post(f"{BASE}/objects/sites", headers=HEADERS, json={
"name": "Utsira",
"values": {
"description": "Small island wind site",
"latitude": 59.3068,
"longitude": 4.8896,
"assets": [
{"name": "Enercon E-40 x2", "values": {"type": "wind_turbine", "capacity_kw": 1200}},
],
},
})
r.raise_for_status()
site = r.json()
print(site["id"], site["stats"]["total_capacity_kw"])
print(site["values"]["latitude"], [a["name"] for a in site["values"]["assets"]])The response is the full site record: the envelope (id, object, name, timestamps, stats) and values with the coordinates and the assets inlined as whole records, each with its own id and a parent_id pointing back at the site.
{
"id": "01a07fd7-01bc-7de7-9b63-c0310318cbac",
"object": "sites",
"name": "Utsira",
"created_at": "2024-06-01T09:12:44Z",
"updated_at": "2024-06-01T09:12:44Z",
"parent_id": null,
"parent_name": null,
"stats": {"total_capacity_kw": 1200.0},
"values": {
"description": "Small island wind site",
"latitude": 59.3068,
"longitude": 4.8896,
"assets": [
{
"id": "01a07fd7-01c0-7a3e-8f10-6a2d5b8e9c11",
"object": "assets",
"name": "Enercon E-40 x2",
"created_at": "2024-06-01T09:12:44Z",
"updated_at": "2024-06-01T09:12:44Z",
"parent_id": "01a07fd7-01bc-7de7-9b63-c0310318cbac",
"parent_name": "Utsira",
"stats": {},
"values": {
"type": "wind_turbine",
"capacity_kw": 1200.0,
"description": null,
"latitude": 59.3068,
"longitude": 4.8896
}
}
]
}
}Asset values.type is one of wind_turbine, solar_panel, or battery. Assets can also be created on their own with POST /objects/assets, passing parent_id to make them a part of a site. An asset without its own coordinates inherits the site's. GET /objects/sites/{id}/assets lists a site's assets.
3. Upload hourly production
Measurements are singleindex series: one value per valid_time. The series is created on first upload with the type, shape, and unit you give it.
r = requests.post(f"{BASE}/objects/sites/{site['id']}/timeseries", headers=HEADERS, json={
"type": "power-production",
"shape": "singleindex",
"unit": "MW",
"points": [
{"valid_time": "2024-06-01T00:00:00Z", "value": 0.62},
{"valid_time": "2024-06-01T01:00:00Z", "value": 0.71},
],
})
r.raise_for_status()
print(r.json()["points_written"]){
"target_id": "01a07fd7-01bc-7de7-9b63-c0310318cbac",
"type": "power-production",
"shape": "singleindex",
"unit": "MW",
"columns": [],
"points_written": 2,
"points_skipped": 0
}Uploads are safe to retry: re-sending the same points stores nothing (points_skipped: 2), and sending a changed value makes it the current one while the previous value stays in the series' history.
A singleindex series can also carry several named columns, for example a met mast measuring wind speed at two heights: declare "columns": ["wind_speed_100m", "wind_speed_10m"] and give each point one field per column instead of value. A type keeps the form of its first upload. See Upload / read timeseries.
4. Read it back
r = requests.get(
f"{BASE}/objects/sites/{site['id']}/timeseries/power-production",
headers=HEADERS,
params={"max_points": 2000},
)
r.raise_for_status()
data = r.json()
print(len(data["points"]), data["start"], data["end"])The response carries points (a list of {valid_time, value}), the effective start/end window, and the series' overall extent as series_first/series_last. With no window given, the response covers the last week of available data. max_points caps the response for charting; the server only downsamples when the window holds more points than the cap.
Next steps
- Objects and records: the record shape and the generic endpoints in full.
- Upload / read timeseries: forecasts, upload options, history, deleting points.
- Many series at once: write and read a whole fleet in one call.
- Custom object types: add your own kinds of records alongside sites and assets.