Type a Generic Webhook Payload in TypeScript
Use json to typescript to design a reusable webhook envelope with id, event name discriminator, timestamp, and a generic data payload parameter.
Detailed Explanation
A Reusable Webhook Envelope
Webhook providers (Stripe, GitHub, Linear, Shopify, internal services) all follow the same shape: an id, an event name from a closed set, a timestamp, and a payload that depends on the event. A single generic interface captures the pattern.
Example JSON Samples
{
"id": "evt_01H8X9",
"event": "user.created",
"created_at": "2024-03-15T10:30:00Z",
"data": { "user_id": "u_001", "email": "alice@example.com" }
}
{
"id": "evt_01H8YA",
"event": "order.paid",
"created_at": "2024-03-15T11:05:00Z",
"data": { "order_id": "o_42", "amount_cents": 2500 }
}
Generated TypeScript
interface WebhookEnvelope<TEvent extends string, TData> {
id: string;
event: TEvent;
created_at: string; // ISO 8601
data: TData;
}
interface UserCreatedData {
user_id: string;
email: string;
}
interface OrderPaidData {
order_id: string;
amount_cents: number;
}
type Webhook =
| WebhookEnvelope<"user.created", UserCreatedData>
| WebhookEnvelope<"order.paid", OrderPaidData>;
Why a Generic Envelope
Without the generic, you would either repeat { id, event, created_at } across every event type or lose the link between event and data. The generic envelope keeps the discriminator and payload paired:
function handle(w: Webhook) {
switch (w.event) {
case "user.created":
return sendWelcomeEmail(w.data.email); // data is UserCreatedData
case "order.paid":
return chargeShipping(w.data.order_id); // data is OrderPaidData
}
}
Tips for Generation
- Start by collecting one JSON sample per event variant — never guess fields.
- Keep
eventstrings exactly as the provider sends them, including dots ("user.created"); do not transform them in types. - Treat
created_atas a string, then parse toDateonly when needed for display. - Add an exhaustive
nevercheck in the default branch so future events show up as compile errors instead of silent passes.
Use Case
Designing an internal webhook receiver that consumes events from three internal services and must dispatch typed handlers without manually unioning every payload shape.
Try It — JSON to TypeScript
Related Topics
JSON to TypeScript Discriminated Union — Result/Error Pattern
Real-World API Schemas
Convert Slack Events API JSON to TypeScript
Real-World API Schemas
Convert Stripe Charge JSON to TypeScript Interfaces
Real-World API Schemas
Convert GitHub Repository API JSON to TypeScript
Real-World API Schemas
Convert JSON:API Spec Responses to TypeScript
Real-World API Schemas