Agent skill

MeetGeek Webhooks Skill

Receive and verify MeetGeek webhooks. Use when setting up a MeetGeek webhook handler, debugging X-MG-Signature verification, or handling meeting analysis notifications (successful-analysis and failed-analysis) from the MeetGeek Public API.

Install this skill

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


When to Use This Skill

  • How do I receive MeetGeek webhooks?
  • How do I verify the X-MG-Signature header on a MeetGeek webhook?
  • How do I tell a successful MeetGeek analysis from a failed one?
  • Why is my MeetGeek webhook signature verification failing?
  • How do I fetch a meeting after MeetGeek finishes analyzing it?

Verification (core)

MeetGeek sends X-MG-Signature: <hex_hmac_of_body>: the bare lowercase hex HMAC-SHA256 of the exact raw request body, keyed with the UTF-8 bytes of the configured secret (not hex- or base64-decoded). No prefix, and no timestamp, id or other header is signed, so there is no replay window to check. Compare the whole header value as one digest. Verify over the raw bytes before parsing.

Node (validate the hex shape first; never call Buffer.from(sig, 'hex') on an unvalidated value):

const crypto = require('crypto');

function verifyMeetGeekSignature(rawBody, signatureHeader, secret) {
  if (!signatureHeader || !/^[0-9a-f]{64}$/i.test(signatureHeader)) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader.toLowerCase()),
    Buffer.from(expected)
  );
}

Python (compare bytes, never str):

import hashlib, hmac, re

def verify_meetgeek_signature(raw_body: bytes, signature_header: str | None, secret: str) -> bool:
    if not signature_header or not re.fullmatch(r"[0-9a-fA-F]{64}", signature_header):
        return False
    expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest().encode("utf-8")
    return hmac.compare_digest(signature_header.lower().encode("utf-8"), expected)

A missing, empty or malformed header, or a mismatch, gets 401. Express handlers must read the body with express.raw({ type: '*/*' }) so any content type verifies the exact bytes.

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

Events

MeetGeek has no event-name field or header. One webhook URL per user is notified (POST) when a meeting's analysis finishes. Branch on the body:

PayloadMeaning
{"message": "File analyzed successfully", "meeting_id": "<uuid>"}successful-analysis: fetch the meeting with the Public API using meeting_id
{"message": "File analyzed failed"}failed-analysis: no meeting_id

Branch on whether meeting_id is present. Delivery is up to three POSTs: the second and third are retries sent only when the first is not acknowledged with 200 OK (no body needed). For team-shared meetings, every team member with view access gets the webhook, so dedupe on meeting_id (see idempotency below).

Environment Variables

MEETGEEK_WEBHOOK_SECRET=your_webhook_secret   # the secret configured for the MeetGeek Public API

Setup with Hookdeck

Paste the webhook secret configured for the MeetGeek Public API. Deliveries without a signature fail verification.

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 meetgeek --path /webhooks/meetgeek

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 12, 2026

View on GitHub →