apitype
apitype
Generate TypeScript types, Zod schemas, TypeBox, and JSON Schema from any API endpoint or JSON — instantly.
Zero config. No OpenAPI spec needed. Works as a CLI, MCP server for AI assistants, Vite plugin, and GitHub Action.
Why apitype?
Every developer writing API integrations writes the same boilerplate: copy a JSON response, manually type every field, figure out which are nullable, which are optional, what format that date string is.
apitype eliminates all of that. Point it at any URL — it fetches the response, infers every field's type and format, and outputs production-ready code.
Before: 20 minutes of manual typing + guessing nullable fields
After: npx @jayeshbansal/apitype <url> → 3 secondsAnd in 2026, when your team uses AI coding assistants daily — apitype is the tool those assistants call under the hood.
Features
4 output formats — Zod, TypeBox, TypeScript-only, JSON Schema
Smart format detection — 14 patterns: UUID, email, URL, datetime, IP, JWT, CUID, NanoID, base64, semver, hex-color, and more
Multi-sample inference — fetch a URL multiple times to detect nullable and optional fields accurately
Batch mode — define all your endpoints in a config file, generate everything with one command
Watch mode — re-generate automatically when config or files change
Typed fetch wrapper — generates a production-ready
async function fetchX()alongside the schemaMCP server — AI assistants like Claude and Cursor call apitype as a tool directly
Vite plugin — types regenerated at dev server start, zero workflow change
GitHub Action — keep types in sync in CI, fail if they drift
ENV var interpolation — use
${API_KEY}in config headers, never hardcode secretsProgrammatic API —
import { fromUrl, fromJson } from '@jayeshbansal/apitype'Zero library deps — Chalk and Ora are CLI-only; the library ships with no runtime dependencies
Install
# One-off use (no install)
npx @jayeshbansal/apitype <url|file>
# Global install
npm install -g @jayeshbansal/apitype
# Dev dependency (for programmatic use or Vite plugin)
npm install -D @jayeshbansal/apitypeCLI
Single endpoint
# From a URL
npx @jayeshbansal/apitype https://api.github.com/users/octocat
# Custom name
npx @jayeshbansal/apitype https://api.github.com/users/octocat --name GithubUser
# TypeBox format
npx @jayeshbansal/apitype https://api.example.com/products/1 --format typebox --name Product
# With auth header + typed fetch wrapper + write to file
npx @jayeshbansal/apitype https://api.example.com/me \
--header "Authorization: Bearer $TOKEN" \
--name CurrentUser \
--fetch \
--out src/types/me.ts
# Sample 5 times for accurate nullable/optional detection
npx @jayeshbansal/apitype https://api.example.com/posts/random --name Post --samples 5
# From a local JSON file
npx @jayeshbansal/apitype response.json --name ApiResponse --out src/types/api.ts
# From stdin
curl -s https://api.github.com/users/octocat | npx @jayeshbansal/apitype --name GithubUserBatch mode
Create apitype.config.json:
{
"endpoints": [
{
"url": "https://api.github.com/users/octocat",
"name": "GithubUser",
"out": "src/types/github.ts"
},
{
"url": "https://api.stripe.com/v1/customers",
"name": "StripeCustomer",
"out": "src/types/stripe.ts",
"headers": { "Authorization": "Bearer ${STRIPE_SECRET_KEY}" }
},
{
"url": "https://api.example.com/products/1",
"name": "Product",
"out": "src/types/product.ts",
"format": "typebox",
"fetchWrapper": true,
"samples": 3
}
],
"defaults": {
"format": "zod",
"fetchWrapper": false
}
}Then run:
npx @jayeshbansal/apitype # auto-detects apitype.config.json
npx @jayeshbansal/apitype --config my-config.json # explicit path
npx @jayeshbansal/apitype --config apitype.config.json --watch # re-run on changesAll flags
Flag | Alias | Description | Default |
|
| Schema name (PascalCase) |
|
|
|
|
|
|
| Write output to file | stdout |
| Include typed fetch wrapper | ||
|
| Fetch URL N times |
|
|
| Add request header (repeatable) | |
| Fetch timeout in ms |
| |
|
| Batch config file | auto-detect |
|
| Re-run on config/file changes | |
| Start MCP server for AI assistants | ||
|
| Print version | |
|
| Show help |
MCP Server (for AI assistants)
apitype ships as an MCP (Model Context Protocol) server — the standard protocol used by Claude, Cursor, Windsurf, and other AI coding assistants to call external tools.
Once configured, your AI assistant can generate types without you lifting a finger:
"Generate Zod types for our products endpoint" → Claude calls
apitype.generate_from_url→ types appear in your file
Setup
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"apitype": {
"command": "npx",
"args": ["apitype", "--mcp"]
}
}
}Cursor (.cursor/mcp.json in your project or ~/.cursor/mcp.json globally):
{
"mcpServers": {
"apitype": {
"command": "npx",
"args": ["apitype@latest", "--mcp"]
}
}
}Windsurf / other MCP clients — same pattern, command: npx, args: ["apitype", "--mcp"].
Available MCP tools
Tool | Description |
| Fetch a URL and generate types |
| Generate types from a JSON string |
| Merge multiple JSON samples for accurate nullable inference |
All tools accept name, format (zod/typebox/typescript/jsonschema), and fetchWrapper options.
Vite Plugin
npm install -D @jayeshbansal/apitype// vite.config.ts
import { defineConfig } from 'vite'
import { apitype } from '@jayeshbansal/apitype/vite'
export default defineConfig({
plugins: [
apitype({
endpoints: [
{
url: 'https://api.example.com/users/1',
name: 'User',
out: 'src/types/user.ts',
},
{
url: 'https://api.example.com/products',
name: 'ProductList',
out: 'src/types/products.ts',
format: 'typebox',
fetchWrapper: true,
},
],
defaults: { format: 'zod' },
}),
],
})Types are generated at vite dev startup and vite build — no manual step required.
Options:
skipIfExists: true— only generate if the output file doesn't exist yet (fast re-runs)verbose: false— silence the generation log
GitHub Action
Add to .github/workflows/sync-types.yml:
name: Sync API Types
on:
schedule:
- cron: '0 6 * * *' # daily at 6am
push:
branches: [main]
workflow_dispatch:
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate types from API endpoints
uses: jayesh-bansal/apitype@v1
with:
config: apitype.config.json
fail-on-diff: 'true'
env:
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}Inputs:
Input | Description | Default |
| Path to config file |
|
| apitype version to use |
|
| Fail if generated types differ from committed |
|
| Auto-commit updated types |
|
| Commit message when auto-committing |
|
Programmatic API
npm install @jayeshbansal/apitypefromUrl(url, options?)
import { fromUrl } from '@jayeshbansal/apitype'
const result = await fromUrl('https://api.github.com/users/octocat', {
name: 'GithubUser',
format: 'zod', // 'zod' | 'typebox' | 'typescript' | 'jsonschema'
fetchWrapper: true, // generate a typed fetch() wrapper
samples: 3, // fetch 3× for better nullable/optional detection
headers: { 'Authorization': 'Bearer token' },
timeout: 15_000,
})
console.log(result.combined) // full file content
// result.format → 'zod'fromJson(data, options?)
import { fromJson } from '@jayeshbansal/apitype'
const result = fromJson(
{ id: '550e8400-...', name: 'Alice', bio: 'Developer' },
{
name: 'User',
format: 'zod',
// Pass multiple samples for accurate nullable/optional detection
samples: [
{ id: '...', name: 'Bob' }, // bio missing → optional
{ id: '...', name: 'Carol', bio: null }, // bio null → nullable
],
}
)
// bio: z.string().nullable().optional()fromString(json, options?)
import { fromString } from '@jayeshbansal/apitype'
const result = fromString('{"hello":"world"}', { name: 'Greeting' })Batch processing
import { loadConfig, runBatch } from '@jayeshbansal/apitype'
const config = await loadConfig('apitype.config.json')
const results = await runBatch(config, {
onProgress: (ep, i, total) => console.log(`[${i}/${total}] ${ep.name}`),
onDone: (r) => console.log(`✓ ${r.outPath}`),
onError: (ep, err) => console.error(`✗ ${ep.name}: ${err.message}`),
})defineConfig for type-safe config files
// apitype.config.js
import { defineConfig } from '@jayeshbansal/apitype'
export default defineConfig({
endpoints: [
{
url: 'https://api.github.com/users/octocat',
name: 'GithubUser',
out: 'src/types/github.ts',
},
],
defaults: { format: 'zod' },
})Detected formats
Input | Zod | TypeBox | JSON Schema |
UUID v4 |
|
|
|
CUID |
|
|
|
Nano ID |
|
|
|
|
|
| |
URL |
|
|
|
ISO datetime |
|
|
|
ISO date |
|
|
|
ISO time |
|
|
|
IPv4 |
|
|
|
IPv6 |
|
|
|
JWT |
|
|
|
Base64 |
|
|
|
Semver |
|
|
|
Hex color |
|
|
|
Examples
Stripe API
STRIPE_SECRET_KEY=sk_test_... \
npx @jayeshbansal/apitype https://api.stripe.com/v1/customers/cus_xxx \
-H "Authorization: Bearer $STRIPE_SECRET_KEY" \
--name StripeCustomer \
--out src/types/stripe.tsInternal API with multiple samples
# Fetch 5 times to correctly detect nullable/optional fields
npx @jayeshbansal/apitype https://your-api.com/api/users/random \
-H "Authorization: Bearer $API_TOKEN" \
--name User \
--samples 5 \
--out src/types/user.tsTypeBox for Fastify
npx @jayeshbansal/apitype https://api.example.com/products/1 \
--format typebox \
--name Product \
--fetch \
--out src/types/product.tsOutput:
import { Type, Static } from '@sinclair/typebox'
export const productSchema = Type.Object({
id: Type.String({ format: 'uuid' }),
name: Type.String(),
price: Type.Number(),
createdAt: Type.String({ format: 'date-time' }),
})
export type Product = Static<typeof productSchema>
export async function fetchProduct(options?: RequestInit): Promise<Product> {
const res = await fetch('https://api.example.com/products/1', options)
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`)
return (await res.json()) as Product
}Clipboard (macOS/Linux)
pbpaste | npx @jayeshbansal/apitype --name ApiResponse # macOS
xclip -o | npx @jayeshbansal/apitype --name ApiResponse # LinuxComparison
apitype | quicktype | openapi-typescript | json-to-ts | |
From live URL | ✅ | ✅ | ❌ (needs spec) | ❌ |
Zod schemas | ✅ | ❌ | ❌ | ❌ |
TypeBox schemas | ✅ | ❌ | ❌ | ❌ |
JSON Schema output | ✅ | ✅ | ❌ | ❌ |
Multi-sample nullable detection | ✅ | ❌ | N/A | ❌ |
Typed fetch wrapper | ✅ | ❌ | ❌ | ❌ |
MCP server (AI assistant tool) | ✅ | ❌ | ❌ | ❌ |
Batch config file | ✅ | ❌ | ✅ | ❌ |
Vite plugin | ✅ | ❌ | ❌ | ❌ |
GitHub Action | ✅ | ❌ | ❌ | ❌ |
Watch mode | ✅ | ❌ | ❌ | ❌ |
Library (0 runtime deps) | ✅ | ❌ | ✅ | ✅ |
ENV var interpolation in config | ✅ | ❌ | ❌ | ❌ |
Contributing
Contributions are welcome! Open an issue before large PRs.
git clone https://github.com/jayesh-bansal/apitype
cd apitype
npm install
npm test
npm run dev # watch mode buildProject structure
src/
├── infer.ts # JSON → InferredSchema (pattern detection)
├── generate.ts # InferredSchema → code (dispatches to formats)
├── formats/
│ ├── zod.ts # Zod schema generator
│ ├── typebox.ts # TypeBox schema generator
│ ├── typescript.ts # TypeScript-only generator
│ └── jsonschema.ts # JSON Schema generator
├── config.ts # Config file loading + defineConfig
├── batch.ts # Batch endpoint processing
├── mcp.ts # MCP server (stdio JSON-RPC)
├── vite.ts # Vite plugin
├── index.ts # Public API
└── cli.ts # CLI entryLicense
MIT © Jayesh Bansal