New blogMaking an AI Agent You Can Trust With Money

★ Pydantic · from JSON

JSON to Pydantic Converter

Pydantic v2 models from a JSON sample, written the way you would by hand: snake_case fields, Field aliases for the original keys, and populate_by_name so you can build models from either spelling.

  • Runs in your browser
  • No signup

Field names

Strictness

Your JSON

Pydantic

3 types · 16 fields
from __future__ import annotations

from datetime import datetime
from typing import Any, Optional
from uuid import UUID

from pydantic import BaseModel, ConfigDict, Field


class Team(BaseModel):
    id: UUID
    name: str
    website: str


class Invoice(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    number: str
    amount: float
    paid: bool
    paid_at: Optional[datetime] = Field(alias="paidAt")
    note: Optional[str] = None


class Root(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    id: int
    email: str
    display_name: str = Field(alias="display-name")
    created_at: datetime = Field(alias="createdAt")
    plan: Any
    tags: list[str]
    team: Team
    invoices: list[Invoice]

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 Pydantic mapping works

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

JSON to Pydantic mapping
In your JSONPydantic
stringstr
ISO timestamp / datedatetime / date
uuidUUID
integer / decimalint / float
null alongside a valueOptional[T]
key missing in some samplesOptional[T] = None
camelCase or invalid keysnake_case field with Field(alias=...)
arraylist[T]
non-object rootRootModel[...]
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 Pydantic, generated by the same engine that runs the converter above (3 types, 16 fields):

from __future__ import annotations

from datetime import datetime
from typing import Any, Optional
from uuid import UUID

from pydantic import BaseModel, ConfigDict, Field


class Team(BaseModel):
    id: UUID
    name: str
    website: str


class Invoice(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    number: str
    amount: float
    paid: bool
    paid_at: Optional[datetime] = Field(alias="paidAt")
    note: Optional[str] = None


class Root(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    id: int
    email: str
    display_name: str = Field(alias="display-name")
    created_at: datetime = Field(alias="createdAt")
    plan: Any
    tags: list[str]
    team: Team
    invoices: list[Invoice]
03

Pydantic gotchas

Optional doesn't mean optional

In Pydantic v2, Optional[str] without a default is still required; it just allows None. Missing keys need a default, which is why they get = None.

Aliases need populate_by_name

With an alias, Pydantic only accepts the original key unless model_config sets populate_by_name=True. The generated models include it.

Leading underscores are private

Pydantic treats _field as a private attribute, so keys starting with _ become plain fields with an alias.

04

Questions developers actually ask

How do I dump the model back to the original keys?
Call model.model_dump(by_alias=True) or model.model_dump_json(by_alias=True).
Can I keep camelCase field names?
Yes. Turn off the snake_case option and keys that are already valid Python identifiers are used as-is.
Why isn't email typed as EmailStr?
EmailStr needs the extra email-validator package. The output stays dependency-free; swap in EmailStr if you have it installed.
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.