Eliq’s webhook solution allows event delivery to Utility API via custom endpoints
Eliq offers a webhook solution which enables Eliq to send events to Utility API. To enable this, the utility would need to implement custom endpoints that Eliq can send webhook events to. The various types of webhook events can either be sent to the same endpoint, or to different endpoints. All webhook events are sent using POST.
Endpoints must use HTTPS and can optionally use Basic HTTP Authentication or OAuth2.
Eliq signs all webhook events and sends the signature in the X-Eliq-Signature HTTP header. This allows your application to verify that Eliq generated the event. The X-Eliq-Signature HTTP header contains a timestamp and a signature. Timestamp is prefixed with t= and signature prefixed with the scheme used for signing the data. The current supported scheme is SHA256, and will be prefixed with sha256.
X-Eliq-Signature:
t=1591091590,
sha256=c39a4c26da13cba4258b698a3f849242af7d2e7b7559c50d0a94917355ff9532Note: The signature is a hash-based message authentication code (HMAC) with SHA-256.
Eliq will generate a secret which is shared with the utility. That secret can be used to verify the signature. Below shows how the verification is done.
The signature includes the timestamp available in the X-Eliq-Signature HTTP header and the JSON string payload from the request body. To verify the signature, the timestamp and JSON string should be joined as follows:
{timestamp}.{json_payload}Compute an HMAC with the SHA256 hash function. Use your secret as the key and sign the payload generated in step 1.
Compare signature received in X-Eliq-Signature HTTP header and your computed signature.
Eliq will retry to send events for a few times, with decreasing frequency, until the endpoint returns a 2xx status code within 10 seconds or until 24 hours have passed. A new timestamp and hash for the signature is generated for every retry. The Utility API must be able to handle duplicate events. Duplicate events can be detected by storing which event ids have been received.
All events sent in the request body will have the same model structure. The event object will always include id, created_date (in UTC), type and object. The event.type defines how the event.object will look and how it should be parsed.
{
"id": "a7b76b9f-ea64-4fd0-94db-624787fcb734",
"created_date": "2020-01-01T21:23:00Z",
"type": "{event_type}",
"object": {
...
}
}Notifications are defined as notifications that should be sent to the end user. In a white label solution, this is handled by sending push, SMS or email messages to the end user. In an API solution, Eliq does not have the ability to contact end users directly. However, the notifications that should have been sent out can be sent to the utility. The event.type for these events are notification_created.
The structure of the notification_created object model always includes a location_id, location_ext_ref, type and object. The notification_created.type defines how the notification_created.object will look and how it should be parsed.
{
"id": "a7b76b9f-ea64-4fd0-94db-624787fcb734",
"created_date": "2020-01-01T21:23:00Z",
"type": "notification_created",
"header": "{notification_header}",
"content": "{notification_content}",
"object": {
"client_id": 123456789,
"location_id": 1234,
"location_ext_ref": "{location_ext_ref}",
"type": "{notification_type}",
"object": {
...
}
}
}| Field | Type | Description |
|---|---|---|
| client_id | Number | Id of client |
| location_id | Number | Id of location |
| location_ext_ref | String | External reference of location |
| type | String | Type of notification |
| header | String | Top level of the event, next to type. Title of the notification in the location's language, based on the client's configured notification texts |
| content | String | Top level of the event, next to type. Text of the notification in the location's language, based on the client's configured notification texts. |
| object | Object | Dynamic object changes depending on type of notification |
The following event types are supported.
Every event is a notification_created event. object.type tells you which notification it is and how to read the inner object.
| object.type | Feature | Sent when | Inner object |
|---|---|---|---|
budget_weekly | Budgets | A weekly budget ends under budget, is exceeded, or is forecast to be exceeded | The budget, as in the Insights API |
budget_monthly | Budgets | The same, for a monthly budget | The budget, as in the Insights API |
daily_anomaly | Anomalies | Yesterday’s consumption was unusually high or low | Anomaly type, fuel and status |
monthly_anomaly | Anomalies | This month’s consumption is unusually high | Anomaly type, fuel and status |
market_price_next_day_avg_price | Market Prices | Tomorrow’s average price is unusually low or high. Sent at 17:00 Stockholm time | Price level, average price, and the highest and lowest hour |
market_price_next_day_high_peak | Market Prices | Tomorrow has a price peak. Sent at 17:00 Stockholm time | The peak hour and its price |
market_price_next_day_le_zero | Market Prices | Tomorrow has prices at or below zero. Sent at 17:00 Stockholm time | The date and type |
monthly_insight | Monthly Report | Last month’s consumption is available for the location | Fuel and period. The wrapper also has sent_language and message, and no client_id |
connection_action_required | Eliq Connect | A connection needs the user to act | The connection id |
connection_first_data_received | Eliq Connect | The first data has arrived for a new connection | The connection id |
Notifications reach your endpoint only for the types enabled for your client. To enable a type, or if you receive a type not listed here, contact Eliq.
Handling events
X-Eliq-Signature header before you trust the payload.The sections below show a full example payload for each type.
budget_weekly and budget_monthly are sent in three cases: the budget is exceeded, the period ends under budget, or the forecast shows the budget will go over the limit (at most once per period). The payload is the same for all three. Read status.result in the budget object to tell them apart: above, completed_below or forecasted_above.budget_weekly and budget_monthly. This is sent when a weekly or monthly budget is either completed and under budget, or if budget exceeds the limit. A notification can also be sent if the forecast indicates that the user will exceed the limit.
The budget object will be the same as in API V3 and will look as follows:
{
"id": "a7b76b9f-ea64-4fd0-94db-624787fcb734",
"created_date": "2025-06-25T06:00:00Z",
"type": "notification_created",
"header": "You stayed below your weekly budget",
"content": "Well done! Your electricity costs last week were 97% below your budget.",
"object": {
"client_id": 123456789,
"location_id": 1234,
"location_ext_ref": "{location_ext_ref}",
"type": "budget_weekly",
"object": {
"enabled": true,
"type": "budget_weekly",
"fuel": "elec",
"resolution": "week",
"unit": "cost",
"limit": 15.0,
"suggested_limit": 0.38,
"status": {
"code": "ok",
"value": 0.38,
"forecast": 0.38,
"period_start": "2025-06-23T00:00:00",
"period_end": "2025-06-30T00:00:00",
"data_until": "2025-06-25T00:00:00",
"result": "currently_below"
}
}
}
}There are two possible notification types: daily_anomaly and monthly_anomaly. The notifications are sent if we detect that a location’s yesterday’s consumption was lower/higher than what we expect it to be or if we detect that a location’s consumption for the current month is unusually high.
The anomaly object schema looks like the following:
{
"id": "a7b76b9f-ea64-4fd0-94db-624787fcb734",
"created_date": "2020-01-01T21:23:00Z",
"type": "notification_created",
"header": "Unusually high electricity use",
"content": "Yesterday you used more electricity than you normally do. Check the app to see what might have caused it.",
"object": {
"client_id": 123456789,
"location_id": 1234,
"location_ext_ref": "{location_ext_ref}",
"type": "daily_anomaly",
"object": {
"type": "daily_anomaly",
"fuel": "elec",
"status": {
"data_until": "2020-04-08T00:00:00.000",
"result": "high"
}
}
}
}The three possible notification types for this feature are market_price_next_day_avg_price, market_price_next_day_high_peak and market_price_next_day_le_zero. They are generated and sent at 17:00 Stockholm time if there are any price alerts for the next day to send out.
The market price objects will be the same as in Insights API and will look as follows:
{
"id": "a7b76b9f-ea64-4fd0-94db-624787fcb734",
"created_date": "2022-11-05T13:00:00Z",
"type": "notification_created",
"header": "Low electricity prices tomorrow",
"content": "Tomorrow's average price is 0,35 kr/kWh. The cheapest hour is 23:00-00:00 at 0,22 kr/kWh.",
"object": {
"client_id": 123456789,
"location_id": 1234,
"location_ext_ref": "{location_ext_ref}",
"type": "market_price_next_day_avg_price",
"object": {
"level": "low",
"abs_percentage_difference": 53,
"avg_price_kwh": "0.3517083333333333333333333333",
"highest_price_kwh": {
"period_start": "2022-11-06T17:00:00",
"price_kwh": "0.544240"
},
"lowest_price_kwh": {
"period_start": "2022-11-06T23:00:00",
"price_kwh": "0.215760"
},
"type": "market_price_next_day_avg_price",
"date": "2022-11-06"
}
}
}{
"id": "a7b76b9f-ea64-4fd0-94db-624787fcb734",
"created_date": "2022-11-03T13:00:00Z",
"type": "notification_created",
"header": "Price peak tomorrow",
"content": "Electricity is most expensive tomorrow between 19:00-20:00, at 2,32 kr/kWh. Try to move your usage to another time.",
"object": {
"client_id": 123456789,
"location_id": 1234,
"location_ext_ref": "{location_ext_ref}",
"type": "market_price_next_day_high_peak",
"object": {
"highest_price_period_start": "2022-11-04T19:00:00",
"highest_price_kwh": "2.323090",
"type": "market_price_next_day_high_peak",
"date": "2022-11-04"
}
}
}Monthly Insights Notifications provide a concise summary of last month's energy usage. The only notification type for this feature is monthly_insight. They are generated and sent once the previous month’s consumption is available for a given location.
The notification objects looks like the following:
{
"id": "882656c3-f4bd-4b75-a954-b45c68185fba",
"created_date": "2024-02-01T03:23:00Z",
"type": "notification_created",
"header": "Your consumption in January",
"content": "You consumed 3456 kWh in January which is about the same as the same month last year. The consumption decreased 45 kWh compared to December. Check out all your insights in the app.",
"object": {
"location_id": 123,
"location_ext_ref": "EXT_REF",
"type": "monthly_insight",
"sent_language": "sv-SE",
"message": {
"language":{
"sv-SE": {
"header": "Your consumption in January",
"content": "You consumed 3456 kWh in January which is about the same as the same month last year. The consumption decreased 45 kWh compared to December. Check out all your insights in the app."
}
}
},
"object": {
"type": "monthly_insight",
"fuel": "elec",
"period_start": "2024-01-01T00:00:00.000",
"period_end": "2024-02-01T00:00:00.000"
}
}
}Eliq Connect clients are provided with two possible notification types for this feature: connection_action_required and connection_first_data_received. They are sent when the status of a connection changes.
{
"client_id": 123456789,
"location_id": 1234,
"location_ext_ref": "{location_ext_ref}",
"type": "connection_action_required",
"object": {
"connection_id": "3AA8FC59-607E-EE11-8925-000D3A241A52",
"type": "connection_action_required"
}
}{
"client_id": 123456789,
"location_id": 1234,
"location_ext_ref": "{location_ext_ref}",
"type": "connection_first_data_received",
"object": {
"connection_id": "3AA8FC59-607E-EE11-8925-000D3A241A52",
"type": "connection_first_data_received"
}
}