# Toggl Track Webhooks

## When to Use This Skill

* How do I receive Toggl Track webhooks?
* How do I verify the Toggl `X-Webhook-Signature-256` signature?
* How do I validate a Toggl webhook subscription (`validation_code`)?
* How do I handle `time_entry` or `project` created/updated/deleted events?
* Why is my Toggl webhook signature verification failing?

## Verification (core)

Toggl sends `X-Webhook-Signature-256: sha256=<hex>`, the HMAC-SHA256 (hex) of the **raw, unparsed body** keyed with the subscription secret. Nothing else is signed (no timestamp). Compare timing-safe.

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

function verifyTogglWebhook(rawBody, signatureHeader, secret) {
  if (!signatureHeader || !secret) return false;
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  try {
    return crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
  } catch {
    return false; // length mismatch
  }
}

```

```python
import hmac, hashlib

def verify_toggl_webhook(raw_body: bytes, signature_header: str | None, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest((signature_header or "").encode(), expected.encode())

```

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

## Subscription Validation

A subscription receives events only once it is **enabled and validated**. PING events for a non-validated subscription carry `validation_code`:

* **Synchronous:** respond `200` with `{"validation_code": "<code>"}` (the examples do this).
* **Asynchronous:** `GET https://api.track.toggl.com/webhooks/api/v1/validate/{workspace_id}/{subscription_id}/{validation_code}`. Use this behind Hookdeck or any proxy that answers Toggl itself.

## Common Event Types

Events are an entity plus an action (`created`, `updated`, `deleted`, or `*` in filters). The delivery has `metadata.model` and `metadata.action`; the examples dispatch on `<model>.<action>`.

| Event | Description |
| --- | --- |
| `time_entry.created` | Time entry created |
| `time_entry.updated` | Time entry edited |
| `time_entry.deleted` | Time entry deleted |
| `project.created` | Project created |
| `project.updated` | Project edited |
| `project.deleted` | Project deleted |
| `ping` | Test/validation event (`payload` is `"ping"`) |

> **Full list:** `GET https://api.track.toggl.com/webhooks/api/v1/event_filters`, and [Toggl webhooks docs](https://engineering.toggl.com/docs/track/webhooks_start/).

## Important Headers

| Header | Description |
| --- | --- |
| `X-Webhook-Signature-256` | `sha256=<hex>` HMAC-SHA256 of the raw body |
| `Content-Type` | `application/json` (POST) |

## Environment Variables

```bash
TOGGL_WEBHOOK_SECRET=your_subscription_secret   # "secret" set on the subscription, or the one Toggl generated

```

## Local Development

```bash
npx hookdeck-cli listen 3000 toggl --path /webhooks/toggl

```

Behind Hookdeck, validate the subscription asynchronously (see above).

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/toggl-webhooks/references/overview.md) - Subscriptions, events, payload shape
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/toggl-webhooks/references/setup.md) - Create, validate and ping subscriptions via the API
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/toggl-webhooks/references/verification.md) - Signature details, test vector, gotchas