# Guide to Enode Webhooks: Features and Best Practices

Enode webhooks notify your systems about connected energy-device activity: an EV's state updates, a charger changes, a battery reports. If you're building on Enode's energy API, webhooks are how you react to device changes without polling.

This guide covers how Enode webhooks work, the events you'll handle, how to verify the `x-enode-signature` (it's HMAC-SHA1, not SHA256), the retry behavior, and the best practices for production.

## What are Enode webhooks?

Enode webhooks are HTTP POSTs delivered to a URL you register, each signed. The signature detail that trips people up: Enode uses HMAC-SHA1, not SHA256. The `x-enode-signature` header is `sha1=<hex>`, and the secret is one you generate and supply at creation (Enode doesn't return it).

## Enode webhook features

| Feature | Details |
| --- | --- |
| Configuration | `POST /webhooks` with `url`, `secret`, `events`, optional auth header/value |
| Signature header | `x-enode-signature`, formatted `sha1=<hex>` |
| Signature scheme | HMAC-SHA1 over the raw UTF-8 body |
| Secret | Caller-supplied at creation (min 128 bits); not returned by Enode |
| Event format | colon-delimited (e.g. `user:vehicle:updated`) |
| Retries (production) | Over 24h with increasing intervals, then deletes pending events and marks the webhook inactive |
| Retries (sandbox) | Marks inactive after ~5 min of failures |
| SDK | None |

## Common events

Enode event names are colon-delimited:

| Event | Fires when |
| --- | --- |
| `user:vehicle:updated` | A user's vehicle state updates |
| `user:charger:updated` | A user's charger updates |
| `user:battery:updated` | A user's battery updates |
| `system:heartbeat` | A periodic heartbeat |
| `enode:webhook:test` | A test event |

Subscribe to the events you process (in the `events` array at creation), and consult Enode's webhook reference for the full catalog.

## Setting up Enode webhooks

Create a webhook with `POST /webhooks`, providing `url`, a `secret` you generate (minimum 128 bits), the `events` array, and optional custom auth header/value. Enode doesn't return the secret, so store it when you create the webhook. Use the Test and Update (`/webhooks/{id}`) endpoints to reactivate an inactive webhook.

## Securing Enode webhooks

Each delivery carries an `x-enode-signature` header formatted `sha1=<hex>`, a lowercase-hex HMAC-SHA1 of the raw UTF-8 body, keyed with your supplied secret. Compute over the exact raw bytes and compare in constant time.

```javascript
const crypto = require("crypto");

const SECRET = process.env.ENODE_WEBHOOK_SECRET; // you generated this

function verify(rawBody, signatureHeader) {
  const expected = "sha1=" +
    crypto.createHmac("sha1", SECRET).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  if (!verify(req.body, req.headers["x-enode-signature"])) {
    return res.sendStatus(401);
  }

  res.sendStatus(200); // acknowledge fast
  processQueue.add(JSON.parse(req.body)); // process asynchronously
});

```

The same check in Python:

```python
import hashlib
import hmac
import os

SECRET = os.environ["ENODE_WEBHOOK_SECRET"].encode()

def verify(raw_body: bytes, signature_header: str) -> bool:
    expected = "sha1=" + hmac.new(SECRET, raw_body, hashlib.sha1).hexdigest()
    return hmac.compare_digest(expected, signature_header or "")

```

## Enode webhook limitations and pain points

### It's SHA1, not SHA256

The Problem: Enode uses HMAC-SHA1. Reaching for SHA256 (the default for most webhooks) fails every delivery.

Why It Happens: Enode's scheme predates the SHA256 conventions many newer providers adopted.

Workarounds:

* Use `sha1` explicitly and compare against the `sha1=` header over the raw body.

How Hookdeck Can Help: Hookdeck verifies the `x-enode-signature` HMAC-SHA1 at the edge, so your app receives pre-verified events without special-casing the algorithm.

### You generate and hold the secret

The Problem: Enode doesn't return the secret; you supply it at creation. Lose it and you can't verify without recreating the webhook.

Why It Happens: Enode has you provide the signing secret rather than issuing one.

Workarounds:

* Generate a strong secret (>=128 bits), store it securely at creation, and reuse it for verification.

How Hookdeck Can Help: Hookdeck verifies at the edge, so the secret lives in one place rather than in every handler.

### Failure leads to inactivation and event loss

The Problem: In production, Enode retries over 24 hours, then deletes pending events and marks the webhook inactive; sandbox inactivates after ~5 minutes. A sustained outage loses events and switches the webhook off.

Why It Happens: Enode prunes persistently failing webhooks.

Workarounds:

* Acknowledge fast so transient issues don't accumulate; monitor webhook state and reactivate via the API; reconcile via the API for anything critical.

How Hookdeck Can Help: Hookdeck always accepts deliveries and absorbs downstream failures itself, keeping the webhook active while it retries to your service.

### Duplicates

The Problem: Retries mean the same event can arrive more than once.

Why It Happens: At-least-once delivery favors eventual delivery.

Workarounds:

* Dedupe on an event id and make side effects idempotent.

How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

## Best practices

### Verify HMAC-SHA1 over the raw body

Use `sha1`, compute over the raw UTF-8 body with your supplied secret, and compare against the `sha1=` header in constant time.

### Store the secret at creation

Generate a strong secret and keep it; Enode won't return it later.

### Acknowledge fast and monitor state

Return 200 quickly, process off a queue, and watch for inactivation so you can reactivate. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

### Dedupe

Dedupe on an event id so retries don't double-process.

## Conclusion

Enode webhooks verify with an `x-enode-signature` HMAC-SHA1 (`sha1=<hex>`) over the raw body, keyed with a secret you generate and store. Use SHA1 (not SHA256), keep the secret, acknowledge fast to avoid inactivation, and dedupe.

[Hookdeck](https://hookdeck.com) verifies the signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique device events.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Enode webhooks reliably in minutes.