Agent skill

Toggl Track Webhooks Skill

Receive and verify Toggl Track webhooks. Use when setting up Toggl webhook handlers, debugging X-Webhook-Signature-256 signature verification, validating a subscription via PING validation_code, or handling time_entry and project events.

Install this skill

npx skills add hookdeck/webhook-skills --skill toggl-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.

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
  }
}
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/, examples/nextjs/, 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>.

EventDescription
time_entry.createdTime entry created
time_entry.updatedTime entry edited
time_entry.deletedTime entry deleted
project.createdProject created
project.updatedProject edited
project.deletedProject deleted
pingTest/validation event (payload is "ping")

Full list: GET https://api.track.toggl.com/webhooks/api/v1/event_filters, and Toggl webhooks docs.

Important Headers

HeaderDescription
X-Webhook-Signature-256sha256=<hex> HMAC-SHA256 of the raw body
Content-Typeapplication/json (POST)

Environment Variables

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

Local Development

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

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

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 4, 2026

View on GitHub →