New blogMaking an AI Agent You Can Trust With Money

★ JSON Schema · from JSON

JSON to JSON Schema Converter

A draft 2020-12 schema inferred from your sample, with required lists, nullable types, string formats and nested objects factored into $defs. Useful for API docs, OpenAPI components and validating payloads in any language.

  • Runs in your browser
  • No signup

Strictness

Your JSON

JSON Schema

3 types · 16 fields
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Root",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "display-name": {
      "type": "string"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    },
    "plan": {
      "type": "null"
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "team": {
      "$ref": "#/$defs/Team"
    },
    "invoices": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Invoice"
      }
    }
  },
  "required": [
    "id",
    "email",
    "display-name",
    "createdAt",
    "plan",
    "tags",
    "team",
    "invoices"
  ],
  "$defs": {
    "Team": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid"
        },
        "name": {
          "type": "string"
        },
        "website": {
          "type": "string",
          "format": "uri"
        }
      },
      "required": [
        "id",
        "name",
        "website"
      ]
    },
    "Invoice": {
      "type": "object",
      "properties": {
        "number": {
          "type": "string"
        },
        "amount": {
          "type": "number"
        },
        "paid": {
          "type": "boolean"
        },
        "paidAt": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        },
        "note": {
          "type": "string"
        }
      },
      "required": [
        "number",
        "amount",
        "paid",
        "paidAt"
      ]
    }
  }
}

Typing APIs by hand?

I set up end-to-end type safety (DB → API → UI) so this never happens again.

Fix my types
01

How the JSON Schema mapping works

Each JSON value is read, merged with every other sample of the same key, and then mapped to the closest JSON Schema type:

JSON to JSON Schema mapping
In your JSONJSON Schema
string{ "type": "string" }
timestamp / email / uuid / URL"format": date-time / email / uuid / uri
integer / decimal"integer" / "number"
null alongside a value"type": ["string", "null"]
key present in every samplelisted in "required"
nested object"$ref": "#/$defs/Name"
mixed valuesanyOf
empty array"items": {}
02

Worked example

A user record with a nested team, a list of invoices (one missing a note, one with a null payment date) and an awkward display-name key:

{
  "id": 1042,
  "email": "ada@example.com",
  "display-name": "Ada",
  "createdAt": "2026-11-07T09:30:00Z",
  "plan": null,
  "tags": ["beta", "founder"],
  "team": {
    "id": "7f3c9a2e-1b4d-4c8e-9f2a-6d5e4c3b2a19",
    "name": "Analytical Engines",
    "website": "https://example.com"
  },
  "invoices": [
    { "number": "INV-001", "amount": 49.5, "paid": true, "paidAt": "2026-10-01T00:00:00Z" },
    { "number": "INV-002", "amount": 49, "paid": false, "paidAt": null, "note": "Card declined" }
  ]
}

Becomes this JSON Schema, generated by the same engine that runs the converter above (3 types, 16 fields):

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Root",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "display-name": {
      "type": "string"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    },
    "plan": {
      "type": "null"
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "team": {
      "$ref": "#/$defs/Team"
    },
    "invoices": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Invoice"
      }
    }
  },
  "required": [
    "id",
    "email",
    "display-name",
    "createdAt",
    "plan",
    "tags",
    "team",
    "invoices"
  ],
  "$defs": {
    "Team": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid"
        },
        "name": {
          "type": "string"
        },
        "website": {
          "type": "string",
          "format": "uri"
        }
      },
      "required": [
        "id",
        "name",
        "website"
      ]
    },
    "Invoice": {
      "type": "object",
      "properties": {
        "number": {
          "type": "string"
        },
        "amount": {
          "type": "number"
        },
        "paid": {
          "type": "boolean"
        },
        "paidAt": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        },
        "note": {
          "type": "string"
        }
      },
      "required": [
        "number",
        "amount",
        "paid",
        "paidAt"
      ]
    }
  }
}
03

JSON Schema gotchas

format is advisory

Many validators only check format when you turn it on (Ajv needs ajv-formats). Without it, a bad email still passes.

Extra keys are allowed

The schema doesn't set additionalProperties: false, so unknown keys pass. Add it if you want a strict contract.

Draft versions differ

2020-12 uses $defs; older tools may expect definitions (draft-07). Rename the key if your validator is old.

04

Questions developers actually ask

Can I use this in OpenAPI?
OpenAPI 3.1 uses JSON Schema 2020-12 directly. Move the $defs into components/schemas and update the $ref paths.
How do I validate data against it in JavaScript?
Use Ajv 2020 (import Ajv from "ajv/dist/2020") with ajv-formats, compile the schema once, then call the validator on each payload.
Why is a field required?
It appeared in every sample. Paste more samples (as an array) and keys that are sometimes missing drop out of required.
Is my JSON sent to a server?
No. Parsing and type generation run in your browser, so you can paste real API responses with tokens or customer data. Nothing leaves the tab.
How does it know a field is optional?
Paste an array of objects, or a response that contains one. Every element is read and merged: keys missing from some elements become optional, and keys that are sometimes null become nullable.
05

Other languages

06

More from the workbench

Fine print

Tools: on the house.
Engineer: by the hour.

A codebase that doesn't need this tool is the upgrade. I set up end-to-end type safety so your API, database and UI agree by construction.

I'm Himanshu, an AI and full-stack engineer. I build MVPs, AI agents and the growth plumbing around them for early-stage startups.