Webhooks

Webhooks are HTTP requests from our servers to your servers to let you know about a particular event that just happened. For some users, having UtilityAPI push events to an endpoint of their choosing is easier than polling our API to monitor for changes. Using webhooks is optional! We only send events to users who opt-in to receive them in their user settings.

  1. On your server, setup an endpoint to receive our webhook requests (e.g. "https://yourserver.com/webhook-receiver").
  2. On UtilityAPI, go to User Settings > Webhook Settings > "Create new webhook endpoint."
  3. Input your server endpoint (e.g. "https://yourserver.com/webhook-receiver"), and select the events that you want to to receive.
  4. Submit the form. Congrats! You have setup webhooks. <that_was_easy.jpeg>
  5. Test it out! Under "Webhook Settings" you can send a test ping event for each of your endpoints.

Here is an example of a webhook request you will typically get when a customer submits an authorization form.

POST /webhook-receiver HTTP/1.1
Host: yourserver.com
X-UtilityAPI-Webhook-Salt: 0934ujsd...
X-UtilityAPI-Webhook-Signature: 310723b64b26a72ab9...
Content-Length: 519
Content-Type: application/json
{
    "events": [
        {
            "uid": "0b346106", 
            "type": "authorization_created", 
            "ts": "2019-01-01T12:32:42.347321+00:00", 
            "delivery_method": "webhook", 
            "delivery_target": "https://yourserver.com/webhook-receiver", 
            "is_delivered": false, 
            "authorization_uid": "12345-678"
        }, 
        {
            "uid": "f18bb97d", 
            "type": "authorization_update_started", 
            "ts": "2019-01-01T12:32:42.347321+00:00", 
            "delivery_method": "webhook", 
            "delivery_target": "https://yourserver.com/webhook-receiver", 
            "is_delivered": false, 
            "authorization_uid": "12345-678"
        }
    ], 
    "next": null
}

Below are the types of events we can push to your server via webhook request. These types are part of the Event object.

Type Description Additional Attributes
ping This is a test event notification that you can trigger manually from your settings. No additional attributes
form_created Triggered when a new Form is created. form_uid - UID String - The uid of the Form that was created.
authorization_created Triggered when a new Authorization is submitted by a customer (i.e. utility account holder). authorization_uid - UID String - The uid of the Authorization that was created.
authorization_declined Triggered when a customer declines an Authorization. authorization_uid - UID String - The uid of the declined Authorization that was created.
authorization_renewed Triggered when an existing Authorization has been re-submitted or renewed by the customer. This typically happens when a customer extends the expiration for an authorization. authorization_uid - UID String - The uid of the Authorization that was updated.
authorization_update_started Triggered when we start verifying an Authorization, which includes updating the meter list associated with the Authorization. authorization_uid - UID String - The uid of the Authorization that is being updated.
authorization_update_delayed Triggered when updating an Authorization has been delayed. This usually happens when we are waiting on something from the utility (e.g. they need to push us the meter list) or customer (e.g. they need to submit a code for two-factor-authentication). authorization_uid - UID String - The uid of the Authorization that is being updated.
authorization_update_progress Triggered when significant progress has been made updating an Authorization, but the task is not yet complete. This usually happens when authorization forms have multiple steps and one of the steps is completed. authorization_uid - UID String - The uid of the Authorization that is being updated.
authorization_update_finished_successful Triggered when the task updating an Authorization has completed, and the Authorization's status is updated. authorization_uid - UID String - The uid of the Authorization that was updated.
authorization_update_finished_errored Triggered when task updating an Authorization has completed, but we encountered errors from the utility during collection. Check the Authorization's notes for what happened. authorization_uid - UID String - The uid of the Authorization that was updated.
authorization_expired Triggered when an existing Authorization has expired. We delete access credentials when a authorization expires, so we will not be able to collect any additional utility data. If you want to continue to be able to collect data for this Authorization or its Meters, you need to send the customer a re-authorization form. authorization_uid - UID String - The uid of the Authorization that was updated.
authorization_revoked Triggered when an existing Authorization has been revoked. We delete all collected data (including bill and interval data) and access credentials when a authorization is revoked. If you want to get access again for this Authorization or its Meters, you need to send the customer a new authorization form. authorization_uid - UID String - The uid of the Authorization that was updated.
meter_created Triggered when we find a new Meter. You will usually see this during Authorization updates (e.g. when we build the meter list). You may also see this event when we perform historical collection tasks and happen to find new meters associated with the Authorization.

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

meter_bills_added Triggered when we find new Bills associated with a Meter. You will usually see this event during historical collections tasks. Check the Meter's bill_count and bill_coverage to see what bills were added.

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

meter_intervals_added Triggered when we find new Intervals associated with a Meter. You will usually see this event during historical collections tasks. Check the Meter's interval_count and interval_coverage to see what intervals were added.

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

meter_historical_collection_started Triggered when we start collecting historical data for a Meter.

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

meter_historical_collection_delayed Triggered when a historical collection for a Meter has been delayed. This usually happens when we are waiting on something from the utility (e.g. they need to push us the data) or customer (e.g. they need to submit a code for two-factor-authentication).

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

meter_historical_collection_retrying Triggered when we encountered an error, and will be automatically retrying in a moment. This usually happens when the utility times out or is down for maintenance. Check the Meter's retrying note for an estimated time of retry.

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

meter_historical_collection_progress Triggered when significant progress has been made collecting historical data for a Meter, but the task is not yet complete. For example, you may see this event when we have finished collecting the historical bills, but have not yet collected the historical intervals.

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

meter_historical_collection_finished_successful Triggered when historical collection for a Meter has completed, and the Meter's status is updated.

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

meter_historical_collection_finished_errored Triggered when historical collection for a Meter has completed, but we encountered errors from the utility during collection. Check the Meter's notes for what happened.

authorization_uid - UID String - The uid of the Meter's Authorization.

meter_uid - UID String - The uid of the Meter.

... We may add other types in the future, so be able to handle unknown types gracefully.

When an Event object is created, is_delivered is false. Here's our logic for successfully delivering events:

  • Send a webhook request (POST ...) to the endpoint on your server that you configured during setup.
  • If we get a 200 OK HTTP response code back from your server, we mark is_delivered=true for all the events in the webhook request.
  • If we get no response or an error response code (4xx, 5xx, etc.), we start retrying to send the webhook request every hour for 72 hours.

If your server goes down and you want to see what events you missed, you can look them up on our /events API endpoints. These API endpoints have the same Event formats as what we POST to your server. You can also manually update the delivery status of undelivered events so we will stop retrying to push them to you.

We cryptographically sign every webhook request made to your server using SHA-256 . We hash the webhook endpoint secret from your settings plus a salt and the webhook request body, joined with periods (".").

SHA256("<secret>.<salt>.<body>")

For example, say you receive the following request to your webhook endpoint:

POST /notify-me HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: UtilityAPI Bot
X-UtilityAPI-Webhook-Signature: 285783a12faafd0c991f131ccb08514481f2c728a303e309955b6f474012bb37
X-UtilityAPI-Webhook-Salt: E7EB2SFcv8JSDbaH
Content-Type: application/json
Content-Length: 320

{
    "events": [
        {
            "delivery_method": "webhook", 
            "delivery_target": "http://localhost:8888/notify-me", 
            "is_delivered": false, 
            "ts": "2018-03-03T01:05:28.119646+00:00", 
            "type": "ping", 
            "uid": "2229"
        }
    ], 
    "next": null
}

Here's how you can verify the X-UtilityAPI-Webhook-Signature header in Python 3.

$ python3
>>> from hashlib import sha256
>>> secret_from_settings = "vWU36X4C6Y9gm7wkrw7RUdATmGejHpNs" # Get this from your settings
>>> salt_from_header = "E7EB2SFcv8JSDbaH"
>>> webhook_body = """{
...     "events": [
...         {
...             "delivery_method": "webhook", 
...             "delivery_target": "http://localhost:8888/notify-me", 
...             "is_delivered": false, 
...             "ts": "2018-03-03T01:05:28.119646+00:00", 
...             "type": "ping", 
...             "uid": "2229"
...         }
...     ], 
...     "next": null
... }"""
>>> combined_string = "{}.{}.{}".format(secret_from_settings, salt_from_header, webhook_body)
>>> sha256(combined_string.encode("utf-8")).hexdigest()
'285783a12faafd0c991f131ccb08514481f2c728a303e309955b6f474012bb37'
# ^ This is the same as the X-UtilityAPI-Webhook-Signature above