rebase.energy

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

On this page