Agent skill

Tremendous Webhooks Skill

Receive and verify Tremendous webhooks. Use when setting up Tremendous webhook handlers, debugging Tremendous-Webhook-Signature verification, or handling rewards and payouts events like REWARDS.DELIVERY.SUCCEEDED, REWARDS.DELIVERY.FAILED, ORDERS.APPROVED, and CAMPAIGNS.CREATED.

Install this skill

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


When to Use This Skill

  • How do I receive Tremendous webhooks?
  • How do I verify the Tremendous-Webhook-Signature header?
  • Why is my Tremendous webhook signature verification failing?
  • How do I handle REWARDS.DELIVERY.SUCCEEDED and REWARDS.DELIVERY.FAILED events?
  • How do I get the webhook private_key for a Tremendous webhook?
  • How do I handle ORDERS.APPROVED, ORDERS.FAILED, or FUNDING_SOURCES.FUNDED events?

Verification (core)

Tremendous signs the raw request body with HMAC-SHA256, keyed with the webhook's private_key, and sends the hex digest in Tremendous-Webhook-Signature as sha256=<hex>. The prefix is always present: require it and strip it before comparing. There is no timestamp or message ID in the signed content. Read the raw body (any content type) and compare in constant time.

Node:

const crypto = require('crypto');

function verify(rawBody, signatureHeader, privateKey) {
  if (!signatureHeader || !signatureHeader.startsWith('sha256=')) return false;
  const sig = signatureHeader.slice('sha256='.length);
  // Check hex shape first: Buffer.from(x, 'hex') silently truncates invalid input
  if (!/^[0-9a-f]{64}$/i.test(sig)) return false;
  const expected = crypto.createHmac('sha256', privateKey).update(rawBody).digest();
  return crypto.timingSafeEqual(Buffer.from(sig, 'hex'), expected);
}

Python:

import hmac, hashlib

def verify(raw_body: bytes, signature_header: str, private_key: str) -> bool:
    if not signature_header or not signature_header.startswith("sha256="):
        return False
    sig = signature_header[len("sha256="):].lower()
    expected = hmac.new(private_key.encode(), raw_body, hashlib.sha256).hexdigest()
    # Compare bytes so a non-ASCII header returns False instead of raising
    return hmac.compare_digest(sig.encode(), expected.encode())

In Express use express.raw({ type: '*/*' }) on the route so verification works whatever Content-Type arrives. Tremendous has no SDK helper for webhook verification, so verification is manual in every framework.

For complete handlers with route wiring, event dispatch, and tests, see:

Common Event Types

Events are uppercase and dotted. The payload's event field carries the name:

EventDescription
REWARDS.DELIVERY.SUCCEEDEDTremendous received confirmation the reward email was delivered (not sent for LINK rewards)
REWARDS.DELIVERY.FAILEDReward delivery failed, usually an email bounce (payload.meta has the failure details)
REWARDS.CANCELEDA reward was canceled
REWARDS.FLAGGEDA reward was flagged for fraud review
ORDERS.CREATEDAn order was created (payload.meta holds the Order)
ORDERS.APPROVEDAn admin approved an order (only fires when order approvals are on)
ORDERS.CANCELEDAn order held for review was rejected
ORDERS.FAILEDAn order failed, typically a declined card
CAMPAIGNS.CREATEDA campaign was created in the UI
FUNDING_SOURCES.FUNDEDFunds were added and made available on your balance
INVOICES.PAIDAn invoice was paid

Tremendous sends every event to the one receiver registered for your organization, so filter in your handler. The full list (36 events across campaigns, connected organizations, funding sources, invoices, members, orders, products, rewards, fraud reviews, reports and topups) is in references/overview.md.

Important Headers and Payload

ItemDescription
Tremendous-Webhook-Signaturesha256=<hex> HMAC-SHA256 of the raw body
eventEvent name, e.g. ORDERS.APPROVED
uuidUnique ID of this webhook; use it to dedupe retries
payload.resource{ id, type } of the resource the event refers to

Environment Variables

TREMENDOUS_WEBHOOK_PRIVATE_KEY=your_webhook_private_key   # returned when you create or retrieve the webhook via the API

Local Development

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

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 6, 2026

View on GitHub →