Agent skill

Paragon Webhooks Skill

Receive and authenticate Paragon webhooks. Use when setting up a Paragon Webhook Destination endpoint, checking the shared secret header you configured, debugging 401s, or handling monitoring events like workflow_failure and credentials_failure.

Install this skill

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


Paragon is an embedded integrations platform. A Webhook Destination (Settings > Monitoring, paid plans) sends a JSON POST to your URL when something goes wrong in your Paragon project: a workflow fails or a connected user's credential can no longer be refreshed. Requests are not signed. You authenticate them with a secret header that you add to the destination yourself.

This skill covers Webhook Destinations only. Managed Sync webhooks have no auth option and are not covered.

When to Use This Skill

  • How do I receive Paragon webhooks?
  • How do I authenticate Paragon Webhook Destination requests?
  • Does Paragon sign webhook payloads? (No: use a shared secret header)
  • How do I handle workflow_failure and credentials_failure events?
  • Why does my Paragon webhook endpoint return 401?

Verification (core)

const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
  const ha = crypto.createHash('sha256').update(String(a)).digest();
  const hb = crypto.createHash('sha256').update(String(b)).digest();
  return crypto.timingSafeEqual(ha, hb);
}

function verifyParagonRequest(headers, secret = process.env.PARAGON_WEBHOOK_SECRET,
                              headerName = process.env.PARAGON_WEBHOOK_HEADER || 'Authorization') {
  if (!secret) return false;                          // never accept when unconfigured
  const received = headers[headerName.toLowerCase()]; // Node lowercases header names
  return typeof received === 'string' && received !== '' && safeEqual(received, secret);
}
  • You choose the header: add it to the Webhook Destination under Show more request options (headers). The name is user-chosen, so read it from PARAGON_WEBHOOK_HEADER (default Authorization) and look it up case-insensitively.
  • PARAGON_WEBHOOK_SECRET is the exact, whole header value, including any Bearer prefix you typed. Compare the whole value; do not strip or parse a prefix.
  • Return 401 for a missing header or a mismatch, 400 for a body that isn't a JSON object, 200 once handled.
  • Python: hmac.compare_digest on bytes (encode both sides; str raises on non-ASCII).
  • Read the body raw (express.raw({ type: '*/*' })) so any content type works, and parse JSON only after the credential check.

Security limits: a static shared credential authenticates the sender, not the body, and gives no replay protection (no signature, no timestamp). Use HTTPS, and rotate the credential (update the destination header and PARAGON_WEBHOOK_SECRET) if it leaks.

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

Event Types

The payload has a top-level type field (repeated in data.type for workflow failures), a message, and user, project and integration objects.

Event (type)Sent When
workflow_failureA workflow reaches the Failed status after an error. Adds workflow and data.error, data.executionUrl, data.workflowExecution, data.stepExecution
credentials_failureAn OAuth refresh fails and can't be retried; the user's credential is marked invalid. data has userId and error (e.g. invalid_grant). Ask the user to reconnect in the Connect Portal

If you change the Request Payload field of the destination, the body is whatever you template, so the type field may not be present.

Environment Variables

PARAGON_WEBHOOK_HEADER=Authorization        # header name you added to the destination
PARAGON_WEBHOOK_SECRET=your-shared-secret   # exact whole header value, incl. any "Bearer "

Local Development

Paragon can't reach localhost. Tunnel with the Hookdeck CLI (no account required):

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

Use the printed URL as the Webhook Destination URL in Paragon.

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 5, 2026

View on GitHub →