All free tools
Free tool
Webhook Receiver Starter Generator
Generate Node or Python webhook handlers with signature verification for unlimitedcodex events.
// unlimitedcodex webhook receiver — Node.js / Next.js App Router
// Signature verification notes:
// - Header: x-ucx-signature (format: t=<unix>,v1=<hex>)
// - Signed payload: `${timestamp}.${rawBody}`
// - Secret env var: UCX_WEBHOOK_SECRET (whsec_ucx_*)
// - Reject timestamps outside a 300s tolerance window.
import { createHmac, timingSafeEqual } from "crypto";
const SIGNATURE_TOLERANCE_SECONDS = 300;
function verifyWebhookSignature(rawBody: string, signatureHeader: string, secret: string) {
const parts = Object.fromEntries(
signatureHeader.split(",").map((part) => {
const [key, value] = part.split("=");
return [key, value];
})
);
const timestamp = Number(parts.t);
const signature = parts.v1;
if (!Number.isInteger(timestamp) || !signature) {
return false;
}
if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > SIGNATURE_TOLERANCE_SECONDS) {
return false;
}
const signedPayload = `${timestamp}.${rawBody}`;
const expected = createHmac("sha256", secret).update(signedPayload).digest("hex");
const left = Buffer.from(expected, "hex");
const right = Buffer.from(signature, "hex");
return left.length === right.length && timingSafeEqual(left, right);
}
async function recordWebhookEvent(eventId: string, eventType: string) {
// Persist event.id before side effects so retries stay idempotent.
// Return false when this delivery was already processed.
return true;
}
export async function POST(request: Request) {
const rawBody = await request.text();
const signature = request.headers.get("x-ucx-signature") ?? "";
const secret = process.env.UCX_WEBHOOK_SECRET;
if (!secret || !verifyWebhookSignature(rawBody, signature, secret)) {
return new Response("Invalid signature", { status: 400 });
}
const event = JSON.parse(rawBody) as {
id: string;
type: string;
created: string;
data: Record<string, unknown>;
};
const isNew = await recordWebhookEvent(event.id, event.type);
if (!isNew) {
return Response.json({ received: true, duplicate: true });
}
switch (event.type) {
case "usage.threshold_reached": {
// Pause expensive jobs, notify account owners, or refresh quota dashboards.
await handleUsageThreshold(event.data);
break;
}
case "subscription.updated": {
// Refresh local entitlements, package slug, and billing period metadata.
await syncSubscriptionState(event.data);
break;
}
case "api_key.revoked": {
// Invalidate cached credentials and alert the owning team.
await revokeCachedApiKey(event.data);
break;
}
default:
// Ignore unselected event types safely.
break;
}
return Response.json({ received: true });
}- • Read the raw request body as text before JSON parsing — signature verification must use the exact bytes received.
- • Verify the x-ucx-signature header using HMAC SHA-256 over `${timestamp}.${rawBody}` with your whsec_ucx_* signing secret.
- • Reject signatures older than 300 seconds to limit replay windows.
- • Compare the v1 digest with a constant-time equality check (timingSafeEqual in Node, hmac.compare_digest in Python).
- • Return 2xx only after persisting event.id — handlers must stay idempotent because deliveries can repeat.
- • Store UCX_WEBHOOK_SECRET in a secret manager; never log the secret, API keys, or full customer payloads.
Related tools
More in this category
Migration Generator
Generate or transform OpenAI SDK snippets to unlimitedcodex base URL, keys, and scopes.
Open toolScope Configurator
Select workloads and output least-privilege scopes, .env.example, and a rotation checklist.
Open toolRequest Builder
Build chat completion JSON visually and export cURL, JavaScript, or Python snippets.
Open toolReady for GPT-5.5 and Codex API access?
Choose Unlimited Weekly or Unlimited Monthly, complete Stripe checkout, and receive manual setup in 10 minutes to 5 hours. The full API key arrives by email, while the dashboard safely shows delivery details.