A webhook payload to TypeScript
Event envelopes usually nest the interesting data two levels down, and the type name should follow.
Input
{
"id": "evt_123",
"type": "invoice.paid",
"created": 1735689600,
"data": {
"object": {
"id": "in_456",
"amountPaid": 2000,
"currency": "usd"
}
}
}An object with 2 nested shapes.
3 interfaces · 8 fields · 3 levels deep
Where this sample is ambiguous
Note
Whole numbers are still `number`
Every numeric value in the sample was a whole number, but JSON has a single number type and cannot express the difference. The output uses `number`.
Fix: If a field is genuinely an integer, tighten it by hand: `z.number().int()`.
TypeScript
export interface Root {
id: string;
type: string;
created: number;
data: Data;
}
export interface Data {
object: Object;
}
export interface Object {
id: string;
amountPaid: number;
currency: string;
}Zod
import { z } from 'zod';
export const ObjectSchema = z.object({
id: z.string(),
amountPaid: z.number(),
currency: z.string(),
});
export const DataSchema = z.object({
object: ObjectSchema,
});
export const RootSchema = z.object({
id: z.string(),
type: z.string(),
created: z.number(),
data: DataSchema,
});Convert your own JSON
Paste a sample on the home page, or call the API or MCP server. This page is also available as markdown.