Agent skill

High Mobility Webhooks Skill

Receive and verify High Mobility webhooks. Use when setting up High Mobility (connected-car data platform) webhook handlers, debugging X-HM-Signature-256 verification, or handling fleet_clearance_changed and ping events.

Install this skill

npx skills add hookdeck/webhook-skills --skill high-mobility-webhooks


When to Use This Skill

  • How do I receive High Mobility webhooks?
  • How do I verify the X-HM-Signature-256 header?
  • How do I handle fleet_clearance_changed and ping events?
  • Why is my High Mobility webhook signature verification failing?
  • Why does a sha256= prefix break my HMAC comparison?

Essential Code (USE THIS)

High Mobility sends X-HM-Signature-256: sha256=<lowercase hex>. The digest is HMAC-SHA256 over the raw request body bytes only (no timestamp, id or other header is signed), keyed with the webhook secret string's UTF-8 bytes as-is (not hex- or base64-decoded). High Mobility has no verification SDK, so verify manually.

Verify only X-HM-Signature-256. The deprecated X-HM-Signature header (HMAC-SHA1) is still sent for old integrations; ignore it, as Hookdeck's source does.

Verification (Node.js)

const crypto = require('crypto');

// rawBody: Buffer of the exact request bytes (express.raw({ type: '*/*' }), not express.json)
function verifyHighMobility(rawBody, header, secret) {
  if (!secret || typeof header !== 'string') return false;
  let sig = header.trim();
  if (/^sha256=/i.test(sig)) sig = sig.slice('sha256='.length); // bare digest is accepted too
  if (!/^[0-9a-f]{64}$/i.test(sig)) return false;               // validate before comparing
  const expected = Buffer.from(
    crypto.createHmac('sha256', secret).update(rawBody).digest('hex'));
  const received = Buffer.from(sig.toLowerCase());
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

Verification (Python)

import hashlib, hmac, re

def verify_high_mobility(raw_body: bytes, header: str, secret: str) -> bool:
    if not secret or not header:
        return False
    sig = header.strip()
    if sig[:7].lower() == "sha256=":
        sig = sig[7:]                                    # bare digest is accepted too
    if not re.fullmatch(r"[0-9a-fA-F]{64}", sig):        # validate before comparing
        return False
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest().encode()
    return hmac.compare_digest(sig.lower().encode(), expected)

Respond 401 when the header is missing or empty, the value is malformed, or the signature does not match. No timestamp is signed, so there is no replay window to check; dedupe on your own keys instead (deliveries can repeat and arrive out of order).

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

HTTP Methods

High Mobility's docs don't name the HTTP method. Hookdeck's High Mobility source pre-selects POST without managing the method (you can change it), so any other method the sender uses must also be allowed on the source. The examples accept GET, POST, PUT, PATCH and DELETE on the route, verify the signature first for every method, and treat a missing body as zero bytes: a verified GET with no body is acknowledged with 200, not rejected as invalid JSON.

Common Event Types

The event name is in the body's nested event.type field.

EventDescription
fleet_clearance_changedA fleet vehicle's clearance changed; event.action refines it (for example rejected) and event.detail gives a reason
pingSent when the webhook configuration changes; a normal signed delivery, not a challenge. vehicle.vin is *

After verifying, treat every field of the parsed body as untrusted and check types before reading into it. See references/overview.md.

For the full payload reference, see High Mobility webhooks.

Important Headers

HeaderDescription
X-HM-Signature-256sha256=<lowercase hex HMAC-SHA256 of the raw body>
X-HM-SignatureDeprecated HMAC-SHA1 signature; do not use

Environment Variables

HIGH_MOBILITY_WEBHOOK_SECRET=your_webhook_secret   # the secret you entered when configuring the webhook

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 high-mobility --path /webhooks/high-mobility

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 12, 2026

View on GitHub →