The webhook subscription API lets XENON users manage webhook subscriptions for an account.
Warning
Managing webhook subscriptions through the Notification Rule API will be deprecated.
The new Webhook Subscription API should be used to manage webhook subscriptions from then on.
We will automatically migrate all existing webhook settings on notification rules to webhook subscriptions during this a maintenance window soon to be announced on the developer community.
For that, we will merge webhook settings with the same accountID
, targetURL
and secret
into a single webhook
subscription, as we now support subscribing to multiple event types at once.
As webhook subscriptions will be account-scoped after the migration window, you will find the migrated webhook
subscriptions by calling the GET /accounts/{accountID}/webhooks
endpoint.
All changes affect only management of webhook subscriptions. No changes will affect or break the actual webhook receiver implementation.
The following table provide an overview of the changes migrating from the deprecated Notification Rule API to the new Webhook Subscription API.
Changes introduced by the Webhook Subscription API:
Notification Rule API (deprecated) | Webhook Subscription API |
---|---|
User-scoped: /accounts/{acountID}/users/{userID}/notifications/rules |
Account-scoped: /accounts/{accountID}/webhooks |
Required policies: AccountsUsersRead and AccountsUsersWrite |
Required policies: WebhooksRead and WebhooksWrite |
Subscribes to one eventType . |
Subscribes to one or many eventTypes |
Clients can upload their own HMAC secrets (without validation) | Generates cryptographically strong HMAC secrets |
Signs requests only with one HMAC secret | Signs requests temporarily with multiple secrets for zero-downtime rotation |
- | Supports sending ping events for integration testing |
- | Property active can be used to pause a webhook subscription |
- | Improved performance due to decoupling from user notifications processing |
Planned future improvements - timeline will be announced on the developer community:
- We will offer subscribing to e-mail notifications for
webhook/failed
andwebhook/deactivated
events in your XENON account via the XENON dashboard. - We will automatically deactivate a webhook subscription after 10 consecutive failures.
- We will offer querying failed invocation logs.
Finally, find a comparison between the deprecated notification rule representation and the new webhook subscription representation.
Notification Rule (deprecated)
POST /accounts/{acountID}/users/{userID}/notifications/rules
Request:
{
"eventType": "appliance/online",
"notificationType": {
"webhook": {
"targetURL": "https://example.com/hooks/xenon",
"secret": "whsec_89d31d45a90e309f4e24b7..."
}
},
"locale": "DE"
}
Response:
{
"id": "49a4f165-8233-426b-a1a4-e569665a25dd",
"accountID": "49a4f165-8233-426b-a1a4-e569665a25dd",
"userID": "49a4f165-8233-426b-a1a4-e569665a25dd",
"eventType": "appliance/online",
"notificationType": {
"webhook": {
"targetURL": "https://example.com/hooks/xenon",
"secret": "whsec_89d31d45a90e309f4e24b7..."
}
},
"locale": "DE"
}
Webhook susbcription
POST /accounts/{acountID}/webhooks
Request:
{
"eventTypes": [
"appliance/online",
"appliance/offline"
],
"targetURL": "https://example.com/hooks/xenon",
"active": false
}
Response:
{
"id": "49a4f165-8233-426b-a1a4-e569665a25dd",
"accountID": "49a4f165-8233-426b-a1a4-e569665a25dd",
"eventTypes": [
"appliance/online",
"appliance/offline"
],
"targetURL": "https://example.com/hooks/xenon",
"active": false,
"secret": "whsec_89d31d45a90e309f4e24b7..."
}
The rest of this documentation will focus on how to implement and register webhook receivers on the Webhook Subscription API.
The gridX webhook API lets you manage webhook subscriptions for an account on the gridX webhook API. A webhook subscription subscribes to one or many event types in the referenced gridX account. If an event occurs with a type matching any webhook subscription in that account, then this event will be sent to each matching webhook subscription's target URL through an HTTP POST request. The web server listening on that target URL is called a webhook receiver.
With this, webhook subscriptions are a powerful tool to build system integrations on top of XENON, that can react programmatically to events.
Webhook subscriptions are always scoped to an account. It is not supported to subscribe to events in multiple accounts at once. For that, you need to create a webhook subscription on the according event types in each account.
In order to be allowed to manage webhook subscriptions, clients must have the policies WebhooksRead
and
WebhooksWrite
in the account, they want to manage webhook subscriptions for.
This guide walks through implementing a webhook receiver to react on events in a gridX account and registering it on the gridX webhook API.
This sequence diagram outlines the process of building and integrating a webhook receiver with the gridX webhook API:
sequenceDiagram
Actor developer
alt development
developer->>gridX: create webhook subscription ("active": false)
gridX->>developer: HMAC secret
developer->>webhook receiver: deploy with HMAC secret
developer->>webhook receiver: expose on target URL
developer->>gridX: trigger ping webhook event
gridX->>webhook receiver: ping webhook event
webhook receiver->>webhook receiver: verify HMAC digest
webhook receiver->>webhook receiver: log ping event
webhook receiver->>gridX: 204
developer->>gridX: update webhook subscription ("active": true)
end
alt runtime
gridX->>+webhook receiver: webhook event
webhook receiver->>webhook receiver: verify HMAC digest
webhook receiver->>webhook receiver: process event
webhook receiver->>gridX: 204
end
We support the following event types on a webhook subscription:
appliance/create
: A new appliance has been created.appliance/delete
: An appliance has been deleted.appliance/offline
: An appliance's state switched offline.appliance/online
: An appliance's state switched online.appliance/upate
: An appliance has been update.ev/charge-started
: Charging has started for an electric vehicle.ev/charge-stopped
: Charging has stopped for an electric vehicle.ev/control
(deprecated)ev/create
: A new electric vehicle has been created. (deprecated)ev/delete
: An electric vehicle has been deleted. (deprecated)ev/measurement
ev/plugged
: An electric vehicle has been plugged into a charging station.ev/unplugged
: An electric vehicle has been plugged out of a charging station.ev/update
: An electric vehicle has been updated. (deprecated)gateway/create
: A new gateway has been created.gateway/offline
: A gateway's state switched offline.gateway/online
: A gateway's state switched online.grid-signal-processor/limitation-of-power-consumption/set
: The grid signal processor has set a new limitation of power consumption.grid-signal-processor/limitation-of-power-consumption/unset
: The grid signal processor has unset a limitation of power consumption.inverter/status
: The status of an inverter has changed.system/action
Events are sent via HTTP requests to webhook receivers.
Important
For receiving and processing webhook events successfully, make sure that your webhook receiver implementation fulfills these criteria:
- The registered target URL starts with the
https
scheme and is secured by a trusted TLS certificate.- Self-signed certificates are not supported.
- The webhook receiver accepts
POST
requests on the registered target URL.- We use request path and query parameters exactly as specified on the webhook subscription's target URL. We don't alter or append anything.
- Keep in mind to URL-encode path segments and query parameters should you use any.
- The webhook receiver responds to the request within a 5 seconds timeout.
- The webhook receiver returns any of these status codes:
200 OK
,201 Created
,202 Accepted
,204 No Content
.
Important
The event itself will be sent in the HTTP request's body.
For its schema, please refer to the callback section on the POST /accounts/{accountID}/webhooks
endpoint.
The schema adheres to the CloudEvents v1.0.1 specification,
which defines the message envelope. Its type
property acts as a discriminator for
deserializing the data
property into a concrete event data type.
All possible event data schemas can be found in the OpenAPI specification.
You might also find the example webhook receiver OpenAPI specification helpful.
If you don't want to implement the OpenAPI specification yourself, you can also leverage tools to generate the HTTP
server's code from the OpenAPI specification (see openapi-generator
for
multi-language support or oapi-codegen
for Golang).
While you might need to tweak the templates used for the code generation and fine tune the results, it's a good way to get started in our experience.
To generate server stubs in a language of your choice using OpenAPI Generator
, use the following command:
openapi-generator generate -g <server> -o examples/<servername> -i your-webhook-receiver-spec.yaml
# or only for generating schemas
openapi-generator generate -g <server> -o examples/<servername> -i ./webhook-event-components.yaml
Note that the WebhookEvent
schema in the OpenAPI specification lists ping
as
possible event type value for events, even though this is not a valid event type to subscribe to on creating a webhook
subscription.
ping
is a special event type that can only be used for testing the integration of your webhook receiver with the
gridX webhook subscription API. ping
events only serve testing purposes!
A request with an empty request body can be sent to the POST /accounts/{accountID}/webhooks/{webhookID}/ping
endpoint
in order to trigger a ping
event for a webhook subscription.
Important
This is an overview of how we will process the HTTP responses returned by webhook receivers:
Success: The following response codes will be considered successful.
200 OK
201 Created
202 Accepted
204 No Content
Transient errors: The following responses will be considered to be transient errors. Requests will be retried up to five more times with exponential backoff.
408 Request Timeout
429 Too Many Requests
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
Gone:
A 410 Gone
response code will lead to automated deletion of the webhook subscription.
Permanent errors: All other response codes will be considered to be permanent errors and won't be retried.
If we receive a successful response, we will ignore the response's body. Otherwise, we will try to parse the response body as arbitrary JSON object and log it.
Important
This feature won't be in place yet on 21 August 2025.
We will only activate it, when the XENON dashboard supports subscribing to e-mail notifications for webhook/failed
and webhook/deactivated
events.
The timeline for this will be announced on the developer community.
Note
After 10 consecutive failures on forwarding webhook events to a webhook subscription's target URL, we will automatically set this webhook subscription to inactive.
The counter of consecutive failures increases per webhook event (no matter which event type), not per retry attempt. It will be reset to 0 on each received successful response.
We recommend subscribing to email notifications on webhook/failed
and webhook/deactivated
events in your account on
the XENON dashboard (see here).
When you finished implementing your webhook receiver, you can register a webhook subscription for it on the API by calling the create webhook subscription endpoint:
We recommend creating the webhook subscription first deactivated to fetch the HMAC secret and test it first.
POST https://api.gridx.de/accounts/{{accountID}}/webhooks
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{ bearerToken }}
{
"eventTypes": [
"gateway/online",
"gateway/offline"
],
"targetURL": "https://example.com/hooks/xenon",
"active": false
}
Make sure to extract the following values from the response body:
ìd
secret
Now you can test your webhook receiver as many times you like with the ping
endpoint:
POST https://api.gridx.de/accounts/{{accountID}}/webhooks/{{id}}/ping
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{ bearerToken }}
{}
Make sure to check the requests' signatures with the HMAC secret
.
Finally, if the tests have been successful, you can use the update endpoint to activate your webhook subscription:
PUT https://api.gridx.de/accounts/{{accountID}}/webhooks/{{id}}
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{ bearerToken }}
{
"eventTypes": [
"gateway/online",
"gateway/offline"
],
"targetURL": "https://example.com/hooks/xenon",
"active": true
}
We recommend generating a new HMAC secret at least every six months by leveraging the rotate webhook subscription secret endpoint
Important
We strongly advise you to verify each received HTTP request's integrity.
For that, we rely on hash-based message authentication code (HMAC) digests.
When you create a new webhook subscription in your account, we generate a random secret for it and return it to you in the creation request's response body.
Important
Retrieving the secret again from our API is not possible! Make sure, you persist this secret securely, so that no one else can access it!
For each webhook event we send to the webhook subscription's target URL, we will then calculate an HMAC-SHA-512 digest
of the request body with this secret. This digest will then be appended to the X-Signature
header of each outgoing
request.
The X-Signature
header has the following format:
X-Signature: sha512=<digest 1>[, sha512=<digest 2>, ...]
Each digest is prefixed with sha512=
. Multiple digests are separated by ,
(comma and whitespace). For example:
X-Signature: sha512=a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890
X-Signature: sha512=a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890, sha512=b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0
In order to verify a request's integrity, we recommend implementing these steps on your receiver:
- Retrieve your securely stored copy of the secret.
- Calculate the HMAC-SHA-512 digest of the received request body with the secret and encode it to hexadecimal.
- For each signature provided in the
X-Signature
header:- Remove the
sha512=
prefix to get only the digest. - Compare your calculated digest with the received digest using a constant-time comparison function.
- Remove the
- If any of the provided signatures match your calculated digest, the webhook is considered of integrity.
- Requests with an invalid or missing
X-Signature
header must be rejected.401 Unauthorized
with an empty response body should be returned.
Have a look at our Golang code example for verifying a request's integrity.
The Webhook Subscription API provides an endpoint to rotate a webhook subscription's HMAC secret.
To not break running webhook receivers, rotating the HMAC secret will not remove the old secret immediately.
Instead, requests will be signed with both the old and the new secret for three days and both digests will be
appended to the requests' X-Signature
header.
After these three days, the old secret will be finally dropped and requests will only be signed with the new secret.
Warning
We will only sign requests with the five most recent HMAC secrets for a webhook subscription to ensure that our requests don't exceed the header size limits of common web servers.
This means for you, that you shouldn't call the secret rotation five times after each other without actually replacing the HMAC secret key on your receiver with one of the returned secrets.
Due to the nature of network connectivity the same event may be sent more than once. We recommend making your event processing idempotent to handle duplicate events.
One way of doing this is to log events that you’ve processed and to skip processing for already-logged events.
The order, in which you might receive webhook events won't be guaranteed. For example, retrying event delivery on temporary failures (e.g. due to network problems) can lead to the affected event being received after a newer event.
Important
This feature is not in place yet.
The timeline for this will be announced on the developer community.
We encourage you to enable e-mail notifications for the following events in your account's notification settings:
webhook/failed
: Sends out an e-mail whenever a webhook subscription failed (see expected response).webhook/inactive
: Sends out an e-mail whenever a webhook subscription in your account switches to being inactive, e.g. due to consecutive failures.
- Node.js/Express: Hand-written webhook receiver that logs the IDs of appliances switching online to the console.
- Go: A server with
openapi-generator
[^1] generated stubs for multiple event types. - Python/aiohttp: A server with
openapi-generator
generated stubs for multiple event types. It prints outappliance/online
events. - Reactive webapp: A webhook receiver that relays events to a React client app through websockets.