Agent skill

Navattic Webhooks Skill

Receive and authenticate Navattic interactive product demo webhooks. Use when setting up a Navattic webhook endpoint, checking the Authorization header (Basic or Bearer), debugging 401s, or handling session_closed events for visitors and accounts.

Install this skill

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


Navattic (interactive product demos) sends a webhook whenever a visitor session in one of your demos is closed. Payloads are not signed. The only authentication is an Authorization header that Navattic sends only when you configure one on the webhook: Basic <credentials> or Bearer <token>.

When to Use This Skill

  • How do I receive Navattic webhooks?
  • How do I verify the Navattic Authorization header (Basic or Bearer)?
  • Does Navattic sign webhook payloads? (No: shared credential header only)
  • Why does my Navattic webhook endpoint return 401?
  • How do I handle the session_closed event for visitors and accounts?

Verification (core)

Hookdeck's Navattic source compares the whole Authorization header value to the configured key, and so do the examples. Store the value exactly as Navattic sends it, scheme prefix included (for example Bearer abc123). Don't strip, parse or base64-decode it:

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 verifyNavatticRequest(headers, expected = process.env.NAVATTIC_AUTHORIZATION) {
  if (!expected) return false;                // never accept when unconfigured
  const received = headers['authorization'];  // full value, e.g. "Bearer abc123"
  return Boolean(received) && safeEqual(received, expected);
}

Return 401 when this fails (missing header or mismatch), before reading the body. Read the body raw (express.raw({ type: '*/*' })) so any content type works, and parse it only after the check. Python and Next.js equivalents are in references/verification.md.

Security note: a static shared credential authenticates the sender, not the body, and gives no replay protection (there is no signature and no timestamp). Use HTTPS only, and rotate the credential in Navattic and in NAVATTIC_AUTHORIZATION if it leaks.

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

HTTP Methods

Navattic's page doesn't name the HTTP method, so the examples accept GET, POST, PUT, PATCH and DELETE on the route, check the credential first for every method, and treat an empty body as nothing to process (200). Hookdeck's Navattic source pre-selects POST without managing the method, so any other method the sender uses must also be allowed on the source.

Event Types

eventTypeSent whendata holds
session_closed (visitor)A visitor session is marked closed{ session, endUser, companyAccount } (companyAccount can be null)
session_closed (account)Same, for an account eventThe company account object itself (id, name, websiteDomain, ...)

The envelope is { eventType, timestamp, data }; timestamp is the ISO 8601 session close time. eventType is always session_closed today. Dispatch on eventType, then tell visitor and account events apart by the shape of data (the examples check for data.session).

Environment Variables

NAVATTIC_AUTHORIZATION=Bearer your-token   # the full Authorization value, prefix included

Local Development

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

No account required. Use the printed URL as the webhook URL in Navattic.

Hookdeck Source Setup

Hookdeck's Navattic source type (NAVATTIC, labelled "Navattic") shows this note, and it applies to the examples too: Paste the full Authorization value Navattic sends, including the "Basic " or "Bearer " prefix.

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 10, 2026

View on GitHub →