# A webhook payload to TypeScript

**An object with 2 nested shapes.**

## Input

```json
{
  "id": "evt_123",
  "type": "invoice.paid",
  "created": 1735689600,
  "data": {
    "object": {
      "id": "in_456",
      "amountPaid": 2000,
      "currency": "usd"
    }
  }
}
```

## TypeScript

```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

```typescript
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,
});
```

## Warnings

### Whole numbers are still `number` (info)

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()`.

---

Canonical URL: https://json-to-types.gumballtools.com/types/webhook-payload-to-typescript
JSON API: `POST https://json-to-types.gumballtools.com/api/v1/convert`
MCP endpoint: `https://json-to-types.gumballtools.com/api/mcp`
