GPT-5.5 & Codex API access - $19/week, $76/month, or $59 first month with UNLIMITED59 when configuredSee packagesvs OpenAI API
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.

Ready 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.