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_ 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_orabsolute apikey.budget.exceeded_alerts?absolute - How do I receive Requesty
sample.requestwebhooks? - 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:
| Event | Triggered When |
|---|---|
user.budget.exceeded_ | A user's monthly spend reaches a percentage of their budget |
user.budget.exceeded_ | A user's monthly spend reaches a dollar amount |
group.budget.exceeded_ | A group's combined spend reaches a percentage of its budget |
org.balance.below_ | The organisation balance drops below a dollar amount |
apikey.budget.exceeded_ | An API key's monthly spend reaches a percentage of its budget |
apikey.budget.exceeded_ | An API key's monthly spend reaches a dollar amount |
sample.request | A 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
- references/overview.md - Alert and sample request webhooks, events, payloads, retries
- references/setup.md - Create the signing secret, register the alert webhook, sample requests, rotation
- references/verification.md - Standard Webhooks verification details, header fallback, manual verifier, timestamp window