Skip to the content.

API

Overview

Elsignal provides a versioned API for electricity price data, smart time windows, practical energy recommendations and automation-friendly energy signals.

The API is designed for:

The API should be stable, documented and easy to use.

Elsignal should not only expose raw electricity price data. It should help users and systems understand when it is a good time to use flexible electricity.

Examples:

Elsignal provides signals, recommendations and time windows.

The user, local system, connected product or external integration decides what action to take.


Base URL

During development:

http://localhost:8000/api/v1

Future production example:

https://api.elsignal.se/api/v1

Current implementation status

Elsignal currently has a working public API backed by real Swedish electricity price data.

The backend fetches electricity prices from Elpriset just nu and normalizes the data into Elsignal’s own API format.

Current supported electricity areas:

SE1
SE2
SE3
SE4

Current price resolution:

PT15M

This means that price data is handled as 15-minute periods.

The current MVP API supports:

GET /api/v1/public/prices/{area}/summary
GET /api/v1/public/plans/{area}/today
GET /api/v1/public/plans/{area}/tomorrow

Example:

curl "http://localhost:8000/api/v1/public/plans/SE3/today"

The API returns price periods with fields such as:

{
  "start": "2026-05-21T00:00:00+02:00",
  "end": "2026-05-21T00:15:00+02:00",
  "spot_price": 0.94012,
  "currency": "SEK",
  "price_level": "normal",
  "price_score": 58,
  "estimated_total_price": 1.1751,
  "total_price": 1.1751
}

Spot price and total price

spot_price is the raw electricity market price.

estimated_total_price and total_price include user-provided price settings when available, for example:

If no custom price settings are provided, the total price may be based on default or query-provided values depending on the endpoint.

Thresholds

The API returns threshold values for price classification.

Example:

{
  "thresholds": {
    "p30": 1.909,
    "p80": 2.6534,
    "spot_p30": 0.808195,
    "spot_p80": 1.40375
  }
}

Meaning:

Field Meaning
p30 P30 threshold using the same price basis as the returned graph/period price
p80 P80 threshold using the same price basis as the returned graph/period price
spot_p30 P30 threshold based on raw spot prices
spot_p80 P80 threshold based on raw spot prices

The frontend should normally use thresholds.p30 and thresholds.p80 when drawing reference lines in graphs that display total_price.

The spot_p30 and spot_p80 fields are kept so clients can still access raw spot-price thresholds when needed.

Data status

Daily plan responses should include status information such as:

data_status
resolution
generated_at

Possible data_status values may include:

complete
pending
partial
stale
error

For tomorrow’s plan, data_status may indicate that tomorrow’s prices are not available yet.


API principles

1. Versioned endpoints

All endpoints should include an API version.

Example:

/api/v1/public/prices/SE3/summary

Future breaking changes should be introduced under a new version.

Example:

/api/v2/...

2. JSON first

All API responses should use JSON.


3. Public data should be easy to access

Basic electricity price data and simple recommendations should be available without requiring a user account.


4. User-specific data requires authentication

Saved homes, personal settings, API keys, notification settings and personalized signals require authentication.


5. Partner access uses API keys

Manufacturers and commercial integrations should use API keys with scopes and rate limits.


6. API first

The API is the core product.

The public website, mobile apps, Home Assistant, Homey, MQTT, webhooks, scripts and partner products should all use the same core API and signal logic.


7. Data first

Elsignal should primarily provide structured data, signals, recommendations and time windows.

In the first versions, Elsignal should not directly control private user equipment.

Actual control should happen in:


8. User stays in control

Automation should always be optional.

A user should be able to use Elsignal only as a recommendation service.

Advanced users should later be able to use the same signals for automation.


Recommendation and automation model

Elsignal should translate electricity data into practical recommendations that are easy to understand.

The API should not only answer what the electricity price is. It should also help answer questions such as:

Elsignal should support both simple recommendations and advanced automation.

For ordinary users, the API can support:

For advanced users and integrations, the same signals can later be used by:

Automation should always be optional.

Elsignal provides:

The user, local system, connected product or external integration decides what action to take.


Usage levels

Elsignal should support different levels of usage.

Planned values:

recommendation
notification
api
webhook
mqtt
integration
script

Meaning:

Value Description
recommendation User only sees advice in the website, app or API
notification User receives a notification, for example email, app notification or another channel
api External system reads the API
webhook Elsignal or a connected service triggers a webhook
mqtt Signals are published to MQTT
integration Used by Home Assistant, Homey or similar systems
script Used by custom scripts or local automation

Automation is optional and should not be required for basic use.


Areas

Supported Swedish electricity areas:

SE1
SE2
SE3
SE4

Public API

The Public API provides basic electricity price data, common signals and simple recommendations.

These endpoints are intended for:


Get supported electricity areas

GET /api/v1/public/areas

Example response:

{
  "areas": [
    {
      "id": "SE1",
      "name": "Luleå",
      "country": "SE"
    },
    {
      "id": "SE2",
      "name": "Sundsvall",
      "country": "SE"
    },
    {
      "id": "SE3",
      "name": "Stockholm",
      "country": "SE"
    },
    {
      "id": "SE4",
      "name": "Malmö",
      "country": "SE"
    }
  ]
}

Get today’s prices

GET /api/v1/public/prices/{area}/today

Example:

GET /api/v1/public/prices/SE3/today

Example response:

{
  "area": "SE3",
  "date": "2026-05-18",
  "timezone": "Europe/Stockholm",
  "currency": "SEK",
  "resolution": "PT15M",
  "prices": [
    {
      "start": "2026-05-18T00:00:00+02:00",
      "end": "2026-05-18T00:15:00+02:00",
      "spot_price": 0.82,
      "unit": "SEK/kWh",
      "price_level": "normal"
    }
  ]
}

Get tomorrow’s prices

GET /api/v1/public/prices/{area}/tomorrow

Example:

GET /api/v1/public/prices/SE3/tomorrow

If tomorrow’s prices are not available yet, the API should return a clear response.

Example response when available:

{
  "area": "SE3",
  "date": "2026-05-19",
  "timezone": "Europe/Stockholm",
  "currency": "SEK",
  "resolution": "PT15M",
  "available": true,
  "prices": [
    {
      "start": "2026-05-19T00:00:00+02:00",
      "end": "2026-05-19T00:15:00+02:00",
      "spot_price": 0.74,
      "unit": "SEK/kWh",
      "price_level": "normal"
    }
  ]
}

Example response when not available:

{
  "area": "SE3",
  "date": "2026-05-19",
  "available": false,
  "message": "Tomorrow prices are not available yet."
}

Get current price

GET /api/v1/public/prices/{area}/current

Example:

GET /api/v1/public/prices/SE3/current

Example response:

{
  "area": "SE3",
  "timezone": "Europe/Stockholm",
  "current": {
    "start": "2026-05-18T14:00:00+02:00",
    "end": "2026-05-18T14:15:00+02:00",
    "spot_price": 1.24,
    "unit": "SEK/kWh",
    "price_level": "normal",
    "rank_today": 48
  }
}

Get cheapest periods

GET /api/v1/public/prices/{area}/cheapest?duration=PT3H

Query parameters:

Parameter Type Required Description
duration string no Total duration to return. ISO 8601 duration. Default: PT3H
date string no Date in YYYY-MM-DD format
include_tomorrow boolean no Include tomorrow if available. Default: false

Example:

GET /api/v1/public/prices/SE3/cheapest?duration=PT3H

Example response:

{
  "area": "SE3",
  "duration": "PT3H",
  "timezone": "Europe/Stockholm",
  "cheapest_periods": [
    {
      "rank": 1,
      "start": "2026-05-18T02:00:00+02:00",
      "end": "2026-05-18T02:15:00+02:00",
      "spot_price": 0.42,
      "unit": "SEK/kWh"
    },
    {
      "rank": 2,
      "start": "2026-05-18T02:15:00+02:00",
      "end": "2026-05-18T02:30:00+02:00",
      "spot_price": 0.45,
      "unit": "SEK/kWh"
    }
  ]
}

Get most expensive periods

GET /api/v1/public/prices/{area}/most-expensive?duration=PT3H

Query parameters:

Parameter Type Required Description
duration string no Total duration to return. ISO 8601 duration. Default: PT3H
date string no Date in YYYY-MM-DD format
include_tomorrow boolean no Include tomorrow if available. Default: false

Example:

GET /api/v1/public/prices/SE3/most-expensive?duration=PT3H

Example response:

{
  "area": "SE3",
  "duration": "PT3H",
  "timezone": "Europe/Stockholm",
  "most_expensive_periods": [
    {
      "rank": 1,
      "start": "2026-05-18T18:00:00+02:00",
      "end": "2026-05-18T18:15:00+02:00",
      "spot_price": 2.35,
      "unit": "SEK/kWh"
    }
  ]
}

Get best continuous window

GET /api/v1/public/prices/{area}/cheapest-window?duration=PT3H

Query parameters:

Parameter Type Required Description
duration string no Window length as ISO 8601 duration. Default: PT3H
date string no Date in YYYY-MM-DD format
include_tomorrow boolean no Include tomorrow if available. Default: false

Example:

GET /api/v1/public/prices/SE3/cheapest-window?duration=PT3H

Example response:

{
  "area": "SE3",
  "duration": "PT3H",
  "timezone": "Europe/Stockholm",
  "best_window": {
    "start": "2026-05-18T02:00:00+02:00",
    "end": "2026-05-18T05:00:00+02:00",
    "average_price": 0.48,
    "unit": "SEK/kWh",
    "reason": "This is the cheapest continuous 3 hour window."
  }
}

Get multiple cheap windows

GET /api/v1/public/prices/{area}/cheap-windows?duration=PT3H&count=3

Query parameters:

Parameter Type Required Description
duration string no Window length as ISO 8601 duration. Default: PT3H
count integer no Number of windows to return. Default: 3
date string no Date in YYYY-MM-DD format
include_tomorrow boolean no Include tomorrow if available. Default: false

Example response:

{
  "area": "SE3",
  "duration": "PT3H",
  "count": 3,
  "timezone": "Europe/Stockholm",
  "windows": [
    {
      "rank": 1,
      "start": "2026-05-18T02:00:00+02:00",
      "end": "2026-05-18T05:00:00+02:00",
      "average_price": 0.48,
      "unit": "SEK/kWh",
      "reason": "Lowest average price."
    },
    {
      "rank": 2,
      "start": "2026-05-18T12:00:00+02:00",
      "end": "2026-05-18T15:00:00+02:00",
      "average_price": 0.72,
      "unit": "SEK/kWh",
      "reason": "Second best continuous window."
    }
  ]
}

Get summary

This is the most important public endpoint for simple integrations.

GET /api/v1/public/prices/{area}/summary

Example:

GET /api/v1/public/prices/SE3/summary

Query parameters:

Parameter Type Required Description
cheapest_duration string no Cheapest periods to include. Default: PT3H
expensive_duration string no Expensive periods to include. Default: PT3H
window_duration string no Best window duration. Default: PT3H
include_tomorrow boolean no Include tomorrow if available. Default: true

Example response:

{
  "area": "SE3",
  "timezone": "Europe/Stockholm",
  "currency": "SEK",
  "resolution": "PT15M",
  "generated_at": "2026-05-18T14:05:00+02:00",
  "current": {
    "start": "2026-05-18T14:00:00+02:00",
    "end": "2026-05-18T14:15:00+02:00",
    "spot_price": 1.24,
    "unit": "SEK/kWh",
    "price_level": "normal",
    "rank_today": 48
  },
  "thresholds": {
    "p30": 0.92,
    "p80": 1.85
  },
  "cheapest_periods": [
    {
      "rank": 1,
      "start": "2026-05-18T02:00:00+02:00",
      "end": "2026-05-18T02:15:00+02:00",
      "spot_price": 0.42
    }
  ],
  "most_expensive_periods": [
    {
      "rank": 1,
      "start": "2026-05-18T18:00:00+02:00",
      "end": "2026-05-18T18:15:00+02:00",
      "spot_price": 2.35
    }
  ],
  "best_window": {
    "duration": "PT3H",
    "start": "2026-05-18T02:00:00+02:00",
    "end": "2026-05-18T05:00:00+02:00",
    "average_price": 0.48
  },
  "recommendation": {
    "level": "normal",
    "message": "It is okay to use electricity now, but there may be better periods later.",
    "recommended_uses": [],
    "avoid_uses": [],
    "reason": "Current price is normal."
  },
  "flags": {
    "is_cheap_now": false,
    "is_expensive_now": false,
    "is_one_of_cheapest_periods": false,
    "is_one_of_most_expensive_periods": false,
    "is_in_best_window": false,
    "good_time_to_consume": false,
    "avoid_consumption": false
  },
  "data_status": {
    "today_available": true,
    "tomorrow_available": true,
    "status": "complete"
  }
}

Signal API

Signal endpoints provide more advanced energy signals and practical recommendations.

The purpose of the Signal API is to turn electricity price data and future energy signals into useful decisions for users and connected systems.

Examples:

These endpoints may require an API key in later versions.


Get signal summary

GET /api/v1/signals/summary

Query parameters:

Parameter Type Required Description
area string yes Electricity area, for example SE3
contract_type string no hourly, variable, fixed, mixed, unknown
has_solar boolean no Whether the home has solar panels
has_battery boolean no Whether the home has a battery
device_type string no Device type
duration string no Desired duration as ISO 8601 duration
optimization_goal string no cost, grid_support, solar_self_consumption, balanced
usage_level string no recommendation, notification, api, webhook, mqtt, integration, script

Example:

GET /api/v1/signals/summary?area=SE3&contract_type=fixed&has_solar=true&device_type=water_heater&duration=PT3H&optimization_goal=balanced

Example response:

{
  "area": "SE3",
  "timezone": "Europe/Stockholm",
  "contract_type": "fixed",
  "device_type": "water_heater",
  "optimization_goal": "balanced",
  "usage_level": "recommendation",
  "current": {
    "start": "2026-05-18T14:00:00+02:00",
    "end": "2026-05-18T14:15:00+02:00",
    "price_score": 55,
    "grid_support_score": 42,
    "solar_score": 30,
    "combined_score": 46,
    "signal": "normal"
  },
  "recommendation": {
    "level": "normal",
    "message": "It is okay to use electricity now, but there may be better periods later.",
    "recommended_uses": [
      "washing_machine",
      "dishwasher",
      "ev_charging",
      "water_heater",
      "heat_pump_preheating"
    ],
    "avoid_uses": [],
    "reason": "Current price is normal and the combined score is moderate."
  },
  "recommended_window": {
    "start": "2026-05-18T02:00:00+02:00",
    "end": "2026-05-18T05:00:00+02:00",
    "duration": "PT3H",
    "combined_score": 91,
    "reason": "Low price and high combined score."
  },
  "flags": {
    "good_time_to_consume": false,
    "avoid_consumption": false,
    "is_in_recommended_window": false,
    "supports_grid_now": false,
    "is_solar_friendly_now": false
  }
}

Get daily plan

A daily plan is a complete package of prices, thresholds, signals, recommendations and windows for one day.

The purpose of a daily plan is to reduce unnecessary API calls.

Clients should normally fetch a daily plan:

GET /api/v1/public/plans/{area}/{date}

Example:

GET /api/v1/public/plans/SE3/2026-05-19

Example response:

{
  "area": "SE3",
  "date": "2026-05-19",
  "timezone": "Europe/Stockholm",
  "currency": "SEK",
  "resolution": "PT15M",
  "generated_at": "2026-05-18T14:10:00+02:00",
  "valid_from": "2026-05-19T00:00:00+02:00",
  "valid_to": "2026-05-20T00:00:00+02:00",
  "data_status": "complete",
  "thresholds": {
    "p30": 0.52,
    "p80": 1.34
  },
  "periods": [
    {
      "start": "2026-05-19T00:00:00+02:00",
      "end": "2026-05-19T00:15:00+02:00",
      "spot_price": 0.48,
      "currency": "SEK",
      "price_level": "cheap",
      "price_score": 92,
      "flags": {
        "is_cheap": true,
        "is_expensive": false,
        "good_time_to_consume": true,
        "avoid_consumption": false
      }
    }
  ],
  "best_windows": {
    "cheapest_3h": {
      "start": "2026-05-19T02:00:00+02:00",
      "end": "2026-05-19T05:00:00+02:00",
      "duration": "PT3H",
      "average_price": 0.47,
      "combined_score": 91,
      "reason": "Lowest average price and good combined score."
    }
  },
  "recommendation": {
    "level": "good",
    "message": "There are good flexible consumption windows today.",
    "recommended_uses": [
      "washing_machine",
      "dishwasher",
      "ev_charging",
      "water_heater"
    ],
    "reason": "Several periods have low price and good signal score."
  },
  "flags": {
    "has_tomorrow_prices": true,
    "is_complete": true
  }
}

Device types

Supported planned device types:

washing_machine
dishwasher
water_heater
ev_charger
heat_pump
battery
solar_inverter
generic_switch
smart_relay
energy_manager
home_automation

Recommended uses describe what the signal is suitable for.

Planned values:

washing_machine
dishwasher
ev_charging
water_heater
heat_pump_preheating
battery_charging
solar_self_consumption
generic_flexible_load
grid_support

These values are intended for:

Example:

{
  "recommended_uses": [
    "washing_machine",
    "dishwasher",
    "ev_charging"
  ],
  "avoid_uses": [
    "battery_charging"
  ]
}

Contract types

Supported contract types:

hourly
variable
fixed
mixed
unknown

Meaning:

Value Description
hourly Hourly or period-based price contract
variable Variable electricity contract
fixed Fixed-price electricity contract
mixed Mixed contract
unknown Unknown contract type

For fixed-price users, Elsignal should not claim direct hour-by-hour savings.

Instead, recommendations should focus on grid support and moving flexible consumption away from strained periods.


Optimization goals

Supported optimization goals:

cost
grid_support
solar_self_consumption
balanced

Meaning:

Value Description
cost Optimize mainly for low electricity price
grid_support Optimize mainly for supporting the electricity system
solar_self_consumption Optimize mainly for using more self-produced solar energy
balanced Balance price, grid support, solar and user preferences

Labels

Possible labels:

cheap
normal
expensive
very_cheap
very_expensive
solar_friendly
good_time_to_consume
avoid_consumption
best_window
high_grid_support
low_grid_support
supports_grid
wait

Flags

Common boolean flags:

is_cheap_now
is_expensive_now
is_one_of_cheapest_periods
is_one_of_most_expensive_periods
is_in_best_window
good_time_to_consume
avoid_consumption
is_solar_friendly_now
is_in_recommended_window
supports_grid_now

User API

The User API is for logged-in users.

This part is planned for later versions.


Get current user

GET /api/v1/users/me

Get user homes

GET /api/v1/users/me/homes

Create home

POST /api/v1/users/me/homes

Example request:

{
  "name": "Villa",
  "country": "SE",
  "price_area": "SE3",
  "contract_type": "fixed",
  "electricity_supplier": "unknown",
  "grid_operator": "unknown",
  "has_solar": true,
  "has_battery": false,
  "has_ev": true,
  "has_water_heater": true,
  "has_heat_pump": true,
  "optimization_goal": "grid_support",
  "preferred_usage_level": "notification"
}

Get home signal summary

GET /api/v1/homes/{home_id}/signals/summary

User notification preferences

This part is planned for later versions.

Example request:

GET /api/v1/users/me/notification-preferences

Example response:

{
  "email": true,
  "push": false,
  "webhook": false,
  "notify_when": [
    "tomorrow_plan_ready",
    "good_time_to_consume",
    "avoid_consumption"
  ]
}

Partner API

The Partner API is for manufacturers and commercial integrations.

This part is planned for later versions.


Partner authentication

Partner requests should use an API key.

Example:

Authorization: Bearer <api_key>

Partner signal request

GET /api/v1/partner/signals/summary

Example:

GET /api/v1/partner/signals/summary?area=SE3&device_type=ev_charger&duration=PT4H

Example response:

{
  "area": "SE3",
  "device_type": "ev_charger",
  "recommended_windows": [
    {
      "rank": 1,
      "start": "2026-05-18T01:00:00+02:00",
      "end": "2026-05-18T05:00:00+02:00",
      "duration": "PT4H",
      "combined_score": 94,
      "reason": "Low price and high grid support score."
    }
  ],
  "signals": {
    "good_time_to_consume": true,
    "avoid_consumption": false,
    "price_score": 91,
    "grid_support_score": 88,
    "combined_score": 90
  }
}

Automation and integration channels

This part is planned for later versions.

Elsignal should be able to support optional automation through different channels.

Planned channels:

api
mqtt
webhook
home_assistant
homey
shelly
ohmigo
custom_script

Elsignal should not require automation.

The basic service should work with recommendations and notifications only.

When automation is used, the connected system should decide the final action.

Elsignal provides the signal. The client performs the action.


Example automation signal

{
  "area": "SE3",
  "channel": "webhook",
  "device_type": "water_heater",
  "signal": "good_time_to_consume",
  "recommended_action": "turn_on",
  "valid_from": "2026-05-18T02:00:00+02:00",
  "valid_to": "2026-05-18T05:00:00+02:00",
  "reason": "This is one of the best flexible consumption windows today."
}

MQTT topic structure

Example MQTT topic structure:

elsignal/SE3/signal
elsignal/SE3/price_level
elsignal/SE3/good_time_to_consume
elsignal/SE3/avoid_consumption
elsignal/SE3/recommended_window

Example MQTT payload:

{
  "signal": "good_time_to_consume",
  "price_level": "cheap",
  "recommended_uses": [
    "washing_machine",
    "dishwasher",
    "ev_charging",
    "water_heater"
  ],
  "valid_until": "2026-05-18T05:00:00+02:00"
}

Webhook payload example

Example webhook payload:

{
  "event": "good_time_to_consume",
  "area": "SE3",
  "recommended_uses": [
    "ev_charging",
    "water_heater"
  ],
  "recommended_window": {
    "start": "2026-05-18T02:00:00+02:00",
    "end": "2026-05-18T05:00:00+02:00"
  },
  "reason": "Low price and good grid support score."
}

Script execution

Script execution is a future advanced feature.

Elsignal may later provide examples or templates for local scripts.

Elsignal should not execute arbitrary scripts on behalf of users in the first versions.

Possible future script use cases:

The recommended model is:

Elsignal API
    ↓
local client or integration
    ↓
user-controlled script or automation

Error responses

Errors should use a consistent format.

Example:

{
  "error": {
    "code": "invalid_area",
    "message": "Unsupported electricity area.",
    "details": {
      "area": "SE5",
      "supported_areas": ["SE1", "SE2", "SE3", "SE4"]
    }
  }
}

Common error codes

invalid_area
invalid_date
invalid_duration
invalid_device_type
invalid_contract_type
invalid_optimization_goal
prices_not_available
tomorrow_prices_not_available
unauthorized
forbidden
rate_limited
internal_error

Rate limiting

Public API should have a reasonable rate limit.

Example:

Public API: 60 requests per minute per IP
Free API key: 300 requests per hour
Developer API key: higher limit
Partner API key: negotiated limit

Exact limits are not decided yet.

Clients should be encouraged to fetch complete daily plans and cache them locally instead of polling individual endpoints too often.


Authentication

Planned authentication methods:

Public API

No authentication required for basic endpoints.

User API

Authentication required.

Possible methods:

Partner API

API key required.

API keys should be hashed before storage.


OpenAPI

The API should expose OpenAPI documentation.

Recommended URLs:

/api/v1/openapi.json
/api/v1/docs

FastAPI can generate this automatically.


Backward compatibility

The API should avoid breaking changes within the same version.

Breaking changes should use a new API version.

Example:

/api/v2/...

First MVP API scope

The first MVP should include only public endpoints:

GET /api/v1/public/areas
GET /api/v1/public/prices/{area}/today
GET /api/v1/public/prices/{area}/tomorrow
GET /api/v1/public/prices/{area}/current
GET /api/v1/public/prices/{area}/cheapest
GET /api/v1/public/prices/{area}/most-expensive
GET /api/v1/public/prices/{area}/cheapest-window
GET /api/v1/public/prices/{area}/summary
GET /api/v1/public/plans/{area}/{date}

The first MVP may expose simple recommendation fields such as:

good_time_to_consume
avoid_consumption
recommended_uses
reason
price_level
best_window

No account system is required in the first MVP.

No partner system is required in the first MVP.

No MQTT system is required in the first MVP.

No webhook system is required in the first MVP.

No Shelly integration is required in the first MVP.

No Ohmigo integration is required in the first MVP.

No script execution is required in the first MVP.

No direct device control is required in the first MVP.

The first MVP should provide data, signals, recommendations and daily plans.

Automation and device control are future features.

```