Agent skill

Requesty Webhooks Skill

Receive and verify Requesty webhooks (LLM routing gateway spending alerts and sample requests, signed with Standard Webhooks). Use when setting up Requesty webhook handlers, debugging webhook-signature verification, or handling events like user.budget.exceeded_percent, org.balance.below_absolute, apikey.budget.exceeded_absolute, and sample.request.

Install this skill

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


Requesty is an LLM routing gateway. Your organisation's webhooks carry spending alerts (JSON, Slack or Teams formats) and mirrored sample requests. Once the organisation has a signing secret, every delivery is signed with Standard Webhooks headers: webhook-id, webhook-timestamp and webhook-signature. The event name is in the X-Requesty-Event header. JSON alert bodies are {id, type, data} and repeat it as type. Sample request bodies are {request_id, request, response} and have no type.

When to Use This Skill

  • How do I receive Requesty webhooks?
  • How do I verify Requesty webhook signatures (webhook-signature, whsec_ secret)?
  • How do I handle user.budget.exceeded_percent, org.balance.below_absolute or apikey.budget.exceeded_absolute alerts?
  • How do I receive Requesty sample.request webhooks?
  • Why is my Requesty webhook signature verification failing, or rejecting Hookdeck retries?

Create a Signing Secret First

Hookdeck's configuration alert for this source reads: "Create a signing secret for your Requesty organization. Until one exists, deliveries are unsigned and fail verification." Get the secret from Admin Panel > Alerts > Webhook signing secret (admins only). Requesty also generates one the first time you save a webhook URL. See references/setup.md.

Verification (core)

Signed content is {webhook-id}.{webhook-timestamp}.{raw body}. Requesty signs it with HMAC-SHA256 using the base64-decoded secret (the part after whsec_), base64-encodes the result, and sends one or more space-separated v1,<signature> entries (several during a secret rotation). Use a Standard Webhooks library (standardwebhooks on npm and PyPI), which compares in constant time. Read the webhook-* headers, and when webhook-id is absent fall back to the svix-* headers (svix-id, svix-timestamp, svix-signature), as Hookdeck does.

const { Webhook } = require('standardwebhooks');

const prefix = req.get('webhook-id') ? 'webhook' : 'svix';
const headers = {
  'webhook-id': req.get(`${prefix}-id`),
  'webhook-timestamp': req.get(`${prefix}-timestamp`),
  'webhook-signature': req.get(`${prefix}-signature`),
};
// rawBody: the raw Buffer/string, never re-serialized JSON
const body = new Webhook(process.env.REQUESTY_WEBHOOK_SECRET).verify(rawBody, headers);
// throws on a bad signature or a timestamp outside the window; returns the parsed body
from standardwebhooks.webhooks import Webhook, WebhookVerificationError

wh = Webhook(os.environ["REQUESTY_WEBHOOK_SECRET"])  # "whsec_..."
body = wh.verify(raw_body, {"webhook-id": id_, "webhook-timestamp": ts, "webhook-signature": sig})

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

Keep the full whsec_... value in REQUESTY_WEBHOOK_SECRET. There is one secret per organisation. Handlers fail closed: with the variable unset they return 500 instead of accepting anything. A missing header or a bad signature returns 400. Each retry is signed again with the same webhook-id and a new timestamp and signature, so deduplicate on webhook-id.

Hookdeck retries and replays hit the 5-minute window

The Standard Webhooks libraries always enforce a fixed 5-minute timestamp window (Requesty's instruction too: reject timestamps "more than 5 minutes from the current time"), and it can't be configured. Hookdeck retries and replays resend the original webhook-timestamp, so the library rejects any retry or replay that happens more than 5 minutes after the original delivery. If you verify behind Hookdeck (or replay old events), use the manual verifier in references/verification.md, where the window can be dropped or widened. Deduplicate on webhook-id instead of relying on the timestamp.

Common Event Types

7 events are documented, and the list may not be exhaustive. The name is the X-Requesty-Event header (alert bodies repeat it as type). The examples handle all of these:

EventTriggered When
user.budget.exceeded_percentA user's monthly spend reaches a percentage of their budget
user.budget.exceeded_absoluteA user's monthly spend reaches a dollar amount
group.budget.exceeded_percentA group's combined spend reaches a percentage of its budget
org.balance.below_absoluteThe organisation balance drops below a dollar amount
apikey.budget.exceeded_percentAn API key's monthly spend reaches a percentage of its budget
apikey.budget.exceeded_absoluteAn API key's monthly spend reaches a dollar amount
sample.requestA sampled request and response are mirrored to your webhook_url

Slack and Teams alert webhooks carry no event name in the body and ignore the signature headers. See references/overview.md for payload shapes and delivery behavior (15 s timeout, up to 3 retries with exponential backoff).

Environment Variables

# Organisation signing secret (Standard Webhooks format, starts with whsec_)
REQUESTY_WEBHOOK_SECRET=whsec_xxxxx

Local Development

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

Save the tunnel URL as your JSON alert webhook (Admin Panel > Alerts), then lower an alert threshold or send a sampled request to see an event arrive.

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 13, 2026

View on GitHub →