EnergyCAP webhooks:
Many times, integrated systems that connect to a primary system (EnergyCAP) must determine when to act. Without a webhook feature, the integrated system must poll the primary system until some condition is met. Polling is inefficient because most of the time the trigger condition does not occur.
By contrast, webhooks represent a “don’t call us, we’ll call you” approach to trigger functionality in integrated systems. A webhook configured for an event in EnergyCAP will notify the integrated system when that event occurs.
You manage EnergyCAP webhooks with the UI or with the webhook management APIs.
Event Name | ID Type | Trigger Conditions |
---|---|---|
Account Create | Account ID | Account created |
AP Export | Task ID | Bills exported to AP |
AP Export Reversal | Task ID | Bills unexported from AP |
Batch Closed | Batch ID | Batch of bills closed by invoking the Close Batch API, as a side effect of APIs which allow closing an open batch while creating a new one, (e.g. Bill Import) or creating a “self-contained” batch which is created “closed” (e.g. import bills, process Chargebacks, process Accruals, reverse bills). |
Bill Created | Bill ID | Bill created |
Bill Edited | Bill ID | Bill edited |
Bill Analyzed and Reportable | Bill ID | Post-processing completed after bill created or edited (includes calendarization, normalization, GHG factors, reporting data such as Bill/Account/Meter data and statistics) |
Building Create | Place ID | Building created |
Custom Account Action | Account ID | Custom account action triggered from Actions menu when viewing an account |
Custom Application Action | Custom application action triggered from Gear icon in the application | |
Custom Bill Action | Bill ID | Custom bill action triggered from bill list |
Custom Meter Action | Meter ID | Custom meter action triggered from Actions menu when viewing a meter |
GL Export | Task ID | Bills exported to GL |
GL Export Reversal | Task ID | Bills unexported from GL |
Meter Create | Meter ID | Meter created |
Most of the time a configured event triggers an EnergyCAP webhook, such as a bill being created, or a building being edited.
Regular webhooks:
Webhooks are triggered asynchronously, meaning when an API request fires the webhook, the webhook does not add any additional time to the API request. For example, when a bill is created, if webhooks exist for the Create Bill event, the API caller does not wait any additional length of time before the API response is returned.
However, this also means that there could be a delay between receipt of the triggering API response and the firing of the webhook.
EnergyCAP uses a queueing mechanism for webhook execution, so while near-instantaneous webhook firing could occur after a triggering API call, it is not guaranteed. There may be other queued actions waiting in line in front of the webhook. If a regular webhook fails, an automatic retry policy takes effect. A failure consists of the response to the webhook request having an HTTP response code not falling within the 2XX
range. For example, a 204 No Content
status code is considered a success, while a 404 Not Found
status code is considered a failure and is retried.
A common reason for a webhook failure is when there is a lapse in internet connectivity or unavailability of the server receiving the webhook, resulting in a 502 Bad Gateway
. If the webhook encounters this scenario and the retry schedule is exhausted, EnergyCAP will write a webhook log with a status code of 0
, not making any assumptions about what would have happened if the server had been online. However, if the server comes back online during the retry schedule, the failed webhook would then succeed (barring other failures).
Webhook retry schedule:
A webhook is disabled after 10 consecutive failures and a failure notification email is sent. It must be manually reactivated.
Custom bill action webhooks target bill custom action events and are only triggered by specific API endpoints.
Execute a custom bill action from any bill list.
A green banner displays the success message.
A yellow banner displays the error message.
Custom code which returns error messages in the following format will have the contents of the message
property displayed instead of the default message:
{
"status": {
"message": "Custom code could not process bill ID 1234"
}
}
More information on API endpoints that trigger custom bill actions:
You review the webhook execution details using the “Webhook Log” view, visible by clicking on the success percentage of a webhook in the “API Keys and Webhooks” view.
The webhook log displays success and failure statuses for webhook executions.
Each log entry displays
The webhook log is preserved for the past 3 days unless that data is less than 100 rows. Then, only 100 rows are kept.
The Webhook Log Details pane shows details from the webhook request and the response received from the target server. The HTTP status code from the target server is shown at the top.
The request shows
The response shows
All EnergyCAP webhook requests have the same structure, specifically the provided request headers and body (although the contents differ). The user configures the webhook URL when it is created. Below is an example of a raw EnergyCAP webhook request, followed by an explanation of each part:
https://energycap-webhook-receiver.example.com/custom?debug=false
"Content-Length": 138
"Content-Type": "application/json; charset=utf-8"
"ECI-Signature": "4DBB070C719E66D748A972B963DB1D1BEC7C8A181DA876EF9D015A5743D25B5B",
{
"ids": [
1995696,
1999706,
2006157
],
"eventType": "Bill Custom Action",
"meta": {
"userId" : "1024"
}
}
Webhook URL:
Webhook Headers:
Content-Type
- EnergyCAP always sends webhooks with a content type of application/json
since the webhook payload is a JSON object.ECI-Signature
– This header contains an HMAC/SHA256 encrypted signature for optional (but recommended) verification that:
Webhook Body:
ids
- An array of integer ID values from EnergyCAP. The eventType
property determines the IDs. There may be one or many values in this array.eventType
- Name of the event which triggered the webhook, such as “Bill Created” or “Building Edited”. It gives context to the contents of the ids property. For example, if the eventType is AP Export, then each ID in ids points to a bill which EnergyCAP has exported to Accounts Payable as part of the triggering event. For details about event types and their corresponding IDs, please refer to Supported Webhook Events.meta
- A dictionary which currently has the userId
of the user who triggered the webhook.EnergyCAP provides the ECI-Signature
header as part of the webhook payload. It contains an opaque string that represents an HMAC/SHA256 hash of the webhook request body with all whitespace removed. The hash of the body is computed using the secret configured with the webhook. Any dashes between bytes are removed.
It is a best practice to add signature verification to any system which receives EnergyCAP webhooks.
Using the HMAC/SHA256 strategy protects against fraudulent requests by:
Below is an example of C# code which verifies the signature of an EnergyCAP webhook request:
using System;
using System.Text;
using System.Security.Cryptography;
private bool VerifySignature(string webhookSecret, string rawWebhookPayload, string webhookSignature)
{
// Remove all whitespace from request body before computing signature.
// The receiving code should accept the webhook request verbatim, but you'll need to remove the
// whitespace when computing the hash value, otherwise you'll get a different hash value than
// what EnergyCAP generates.
var payloadNoWhitespace = rawWebhookPayload
.Replace(Environment.NewLine, "")
.Replace(" ", "");
var secretBytes = Encoding.UTF8.GetBytes(webhookSecret);
var payloadBytes = Encoding.UTF8.GetBytes(payloadNoWhitespace);
// Compute signature
using (var hashFunction = new HMACSHA256(secretBytes))
{
var hash = hashFunction.ComputeHash(payloadBytes);
var computedSignature = BitConverter.ToString(hash).Replace("-", "");
// If we computed the same value as the webhook signature, it has been verified
return computedSignature == webhookSignature;
}
}
Consider the following when developing integrations which receive and act upon EnergyCAP webhook requests.
ids
array by eventType
. Because the webhook payload is always the same structure, if your solution expects Account IDs but receives Place IDs, unexpected behavior could result.param1
and param2
, to the integrated system: https://ecap-webhook-catcher.com/custom?param1=foo¶m2=bar.