Webhooks
Prepare your product for webhook events.
Create and manage customer webhook endpoints for usage, billing, and API key lifecycle events, then prepare receivers for signed delivery, retries, and redacted observability.
Last updated: July 6, 2026. Examples use safe placeholders and do not include real secrets, API keys, or customer payloads.
Receiver rule
Prepare receivers to verify the raw payload signature first, record each event ID once, and return 2xx only after your app can safely process or ignore the event.
Setup path
Five steps from endpoint URL to delivery readiness.
Step 1
Create a receiver endpoint
Expose an HTTPS URL that accepts POST requests and can read the raw request body before JSON parsing.
Step 2
Select events
Choose the usage, subscription, invoice, or API key lifecycle event types your receiver should be ready for.
Step 3
Store the signing secret
Copy the endpoint secret once and save it in a secret manager so receivers are ready for signed webhook delivery.
Step 4
Plan retry handling
Design idempotent receivers so repeated delivery attempts are safe when webhook sending is enabled.
Step 5
Plan observability
Track endpoint status now and define the delivery records your team will need for future webhook sending.
Endpoint URL
Register one endpoint per environment.
Use separate URLs for development, staging, and production so future test deliveries never trigger production side effects.
{
"name": "Production usage events",
"url": "https://example.com/api/unlimitedcodex/webhook",
"events": [
"usage.threshold_reached",
"subscription.updated",
"invoice.payment_failed"
]
}Event selection
Select event types your receiver should be ready for.
Keep each receiver narrow while delivery is being prepared. A billing service may only need invoice events, while a usage guardrail may only need threshold-event fixtures.
| Event | Trigger context | Receiver use case |
|---|---|---|
| usage.threshold_reached | A workspace crosses a configured usage threshold. | Prepare account-owner messaging, pause expensive jobs, or ask billing owners to review package fit. |
| subscription.updated | The subscription state, package, or billing period changes. | Refresh local entitlements and access details. |
| api_key.revoked | An API key is revoked. | Invalidate cached credentials and prepare an owning-team notification. |
| invoice.paid | An invoice is marked paid. | Unlock paid access, reconcile billing state, or update account records. |
| invoice.payment_failed | An invoice payment fails. | Prepare a dunning flow, account-owner messaging, or limits for risky background usage. |
Signing secret
Verify the raw body before processing.
Webhook signing secrets are shown once. Store the secret in an environment variable or secret manager, then use it to validate timestamped HMAC SHA-256 signatures when webhook sending is enabled.
The signature value uses t=timestamp,v1=signature. This example names the header x-ucx-signature; use the signature header shown for your delivery.
import { createHmac, timingSafeEqual } from "crypto";
function verifySignature(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(",").map((part) => part.split("="))
);
const timestamp = Number(parts.t);
const signature = parts.v1;
if (!Number.isInteger(timestamp) || !signature) {
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);
}Receiver example
Keep handlers small and idempotent.
Use this receiver pattern once outbound delivery is enabled: parse the event after signature verification, record the event ID, then hand off slow work to your own queue.
export async function POST(request) {
const rawBody = await request.text();
const signature = request.headers.get("x-ucx-signature") ?? "";
const secret = process.env.UCX_WEBHOOK_SECRET;
if (!secret || !verifySignature(rawBody, signature, secret)) {
return new Response("Invalid signature", { status: 400 });
}
const event = JSON.parse(rawBody);
// Store event.id before doing side effects so retries stay idempotent.
await recordWebhookEvent(event.id, event.type);
return Response.json({ received: true });
}Safe payload shape
Event payloads should be treated as operational metadata. Do not put prompts, raw API keys, payment card data, or customer secrets in webhook fixtures or logs.
{
"id": "evt_example_123",
"type": "usage.threshold_reached",
"created": "2026-07-06T12:00:00.000Z",
"data": {
"workspaceId": "workspace_example",
"metric": "requests",
"thresholdPercent": 80
}
}Retries
Design for repeated delivery attempts.
When webhook sending is enabled, network failures, timeouts, and non-2xx responses can lead to retry attempts. Build handlers that can receive the same event more than once without duplicating side effects.
Return 2xx after durable work
Write the event ID or enqueue the work before returning success.
Use event IDs for idempotency
Ignore duplicates that have already been recorded or processed.
Keep handlers fast
Move email, billing sync, and long jobs to an internal queue.
Do not depend on exact ordering
Use current resource state when possible instead of assuming events arrive in sequence.
Observability
Plan for redacted endpoint context.
Plan delivery records around redacted operational context such as event type, endpoint, status, attempt count, response status, response body, next retry time, and delivery time.
Require HTTPS for production endpoint URLs.
Verify the timestamped HMAC signature before trusting the payload.
Store signing secrets in a secret manager, not source code.
Treat event handlers as idempotent because delivery attempts can repeat.
Return 2xx only after the event is safely recorded or intentionally ignored.
Do not log raw signing secrets, API keys, payment details, prompts, or customer payloads.
Local testing
Test with a tunnel before production.
Point a development webhook endpoint at a temporary tunnel, prepare a safe event fixture, verify the signature helper, and confirm your handler stores a single event record.
# Use a local tunnel URL as the endpoint while testing. https://your-tunnel.example/api/unlimitedcodex/webhook # Keep the signing secret out of source code. UCX_WEBHOOK_SECRET=whsec_ucx_placeholder_value
FAQ
Webhook setup questions.
Which events can I subscribe to?
Customer webhook endpoint management supports selecting usage.threshold_reached, subscription.updated, api_key.revoked, invoice.paid, and invoice.payment_failed so receivers can be configured before webhook sending is enabled.
How are webhook deliveries signed?
Prepare receivers for a timestamped HMAC SHA-256 signature. The signature value follows the t=timestamp,v1=signature format, and receivers should verify it against the raw request body and signing secret.
What delivery assumptions should my handler make?
When webhook sending is enabled, do not assume a single delivery, strict ordering, or a successful final attempt. Build idempotent handlers and record event IDs before side effects.
Can I rotate a webhook signing secret?
Yes. Rotating an endpoint creates a new signing secret that is shown once. Store the new value securely and update the receiver before depending on it in production.
Free tools
Generate webhook receiver starters
Scaffold handlers, env files, scoped keys, and retry-safe patterns before enabling billing or usage events.
Webhook Generator
Generate Node or Python webhook handlers with signature verification for unlimitedcodex events.
Env Setup
Generate .env.example blocks from selected endpoints, environment, and webhook needs.
Scope Configurator
Select workloads and output least-privilege scopes, .env.example, and a rotation checklist.
Retry Simulator
Tune backoff and retry settings to see simulated outcomes and copy a retry handler snippet.
Ready to prepare event receivers?
Pair webhooks with usage and billing controls.
Review package fit, rate-limit behavior, and error handling before customer-event workflows affect customer-facing systems.