# Simpro Webhooks

## When to Use This Skill

* How do I receive Simpro webhooks?
* How do I verify the Simpro `X-Response-Signature` header?
* Why does my Simpro webhook signature verification fail?
* How do I handle `job.created`, `company.customer.updated`, or `invoice.created` events?
* How do I use the Simpro "Test Subscription" button (`test.updated`)?

## Setup note

Set the Secret on the Simpro webhook subscription to a long random value, then paste the same value here.

## Verification (core)

Simpro sends `X-Response-Signature`: the **lowercase hex HMAC-SHA1 of the raw request body**, keyed with the UTF-8 bytes of the subscription's Secret. No prefix, no timestamp. Return `401` when the header is missing or wrong. There is no timestamp, so there is no replay protection beyond HTTPS; de-duplicate on your side.

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

function verifySimproSignature(rawBody, signature, secret) {
  // Exactly 40 hex chars: Buffer.from(x, 'hex') silently truncates invalid hex
  if (!signature || !secret || !/^[0-9a-fA-F]{40}$/.test(signature)) return false;
  const expected = crypto.createHmac('sha1', secret).update(rawBody).digest();
  return crypto.timingSafeEqual(Buffer.from(signature, 'hex'), expected);
}

```

Python: `hmac.compare_digest(signature.lower(), hmac.new(secret.encode(), raw_body, hashlib.sha1).hexdigest())`.

Read the **raw body** (`express.raw({ type: '*/*' })`) and parse JSON only after the check.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/simpro-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/simpro-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/simpro-webhooks/examples/fastapi/).

## Common Event Types

Every message is a POST with a JSON body `{ID, build, description, name, action, reference, date_triggered}`. Dispatch on `ID`; `reference` holds the ids to fetch the record from the Simpro API.

| `ID` | Description |
| --- | --- |
| `job.created` | A job was created |
| `company.customer.updated` | A company customer was updated |
| `invoice.created` | An invoice was created |
| `quote.updated` | A quote was updated |
| `employee.deleted` | An employee was deleted |
| `test.updated` | Sent by **Test Subscription** |

The available events are chosen in the subscription screen; see [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/simpro-webhooks/references/overview.md).

## Important Headers

| Header | Description |
| --- | --- |
| `X-Response-Signature` | Hex HMAC-SHA1 of the raw body |

## Environment Variables

```bash
SIMPRO_WEBHOOK_SECRET=your_subscription_secret   # System > Setup > API > Webhook Subscriptions > Secret

```

## Local Development

```bash
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 simpro --path /webhooks/simpro

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/simpro-webhooks/references/overview.md) - Payload shape, events, delivery behavior
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/simpro-webhooks/references/setup.md) - Create the subscription and Secret
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/simpro-webhooks/references/verification.md) - Signature details and debugging