Agent skill

Ardoq Webhooks Skill

Receive and verify Ardoq webhooks. Use when setting up an Ardoq webhook handler, debugging X-Ardoq-Signature-256 HMAC-SHA256 signature verification, or handling component, reference and tag change events from an Ardoq enterprise-architecture organization.

Install this skill

npx skills add hookdeck/webhook-skills --skill ardoq-webhooks


Webhooks from Ardoq (ardoq.com), the enterprise-architecture platform. An organization-wide webhook receives every change across the organization. This skill covers signed webhooks, which deliver component, reference and tag changes.

When to Use This Skill

  • How do I receive Ardoq webhooks?
  • How do I verify the X-Ardoq-Signature-256 header?
  • Why is my Ardoq webhook signature verification failing?
  • How do I handle Ardoq component, reference and tag events?
  • Why did my Ardoq webhook stop sending report or dashboard events?

Setup Note

Keep signing on for the Ardoq webhook (it is on by default) and paste its secret, which Ardoq shows only once. Ardoq enables webhooks per organization.

Verification (core)

Ardoq signs each request with two headers:

X-Ardoq-Signature-256: sha256=<hex digest>
X-Ardoq-Timestamp: <unix epoch seconds>

The digest is HMAC-SHA256(secret, "<timestamp>.<raw body>"), hex-encoded. The key is the secret's UTF-8 bytes, used as-is. Build the signed message as bytes: the timestamp header exactly as received, a literal ., then the raw body. Never decode and re-encode the body, and never JSON.parse / JSON.stringify before verifying.

const crypto = require('crypto');

function verifyArdoqSignature(rawBody /* Buffer */, signatureHeader, timestampHeader, secret) {
  if (!secret || !signatureHeader || !timestampHeader) return false;

  // Accept the value with or without "sha256="; validate format BEFORE decoding
  const digest = signatureHeader.replace(/^sha256=/, '');
  if (!/^[0-9a-fA-F]{64}$/.test(digest)) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(Buffer.concat([Buffer.from(timestampHeader, 'latin1'), Buffer.from('.'), rawBody]))
    .digest();
  const provided = Buffer.from(digest.toLowerCase(), 'hex'); // hex is case-insensitive
  return provided.length === expected.length && crypto.timingSafeEqual(provided, expected);
}

Missing or empty signature or timestamp header, malformed value, or mismatch: respond 401.

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

There is no official Ardoq SDK for webhook verification. Ardoq's help article shows Python, Node.js and Java snippets; the examples here follow the same algorithm.

Timestamp tolerance is opt-in

Ardoq's own snippets reject deliveries more than 5 minutes old. This skill does not by default: Hookdeck retries and replays resend the original headers and timestamp, and Hookdeck applies no tolerance itself, so a fixed window would reject legitimate retries. Set ARDOQ_WEBHOOK_TOLERANCE_SECONDS to opt in (X-Ardoq-Timestamp is Unix seconds; unset or 0 = off). Because the timestamp is signed, it cannot be swapped for a fresh one.

Event Types

The body is {resource-type, resource-id, event-type, organization, organization-label, data}. Dispatch on resource-type, then event-type.

resource-typeTriggered WhenNotes
componentA component changesSigned webhooks only
referenceA reference (link between components) changesSigned webhooks only
tagA tag changes, e.g. one is added to a componentSigned webhooks only; data.components lists tagged components

Ardoq's docs show event-type: "create" in the sample payload and do not list the other values, so log unknown ones instead of guessing. Signed webhooks do not deliver field, report, dashboard or survey changes (only unsigned webhooks do, and this skill does not cover them), and there are no deletion events.

Important Details

  • Method: POST. Hookdeck's Ardoq source manages the method as POST.
  • Scope: the endpoint receives every change in the organization, unfiltered by workspace or permissions, including confidential fields. Only use an endpoint you trust.
  • HTTPS required for signed webhooks; Ardoq verifies the endpoint's TLS certificate.
  • Signing is one-way. To stop signing, delete the webhook and create an unsigned one.
  • Secret rotation: "Rotate signing secret" invalidates the old secret immediately.
  • Retries: Ardoq documents no retry or timeout policy. Respond quickly and process asynchronously.
  • No delivery ID header. Build an idempotency key yourself, e.g. resource-id + event-type + data._version where present.

Environment Variables

ARDOQ_WEBHOOK_SECRET=your_signing_secret      # shown once, when the webhook is created
ARDOQ_WEBHOOK_TOLERANCE_SECONDS=0             # optional; unset or 0 = no timestamp window (default)

Local Development

# Forward Ardoq webhooks to your local server (no account required)
npx hookdeck-cli listen 3000 ardoq --path /webhooks/ardoq

Paste the resulting HTTPS URL as the destination URL when creating the webhook in Ardoq (Preferences → Organization settings → Settings → Webhooks → Create Webhook). Test by adding and removing a tag on a component.

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 9, 2026

View on GitHub →