Add one line. Get OpenAPI docs from real traffic.
EasyDocs watches your API traffic and uses AI to generate accurate, up-to-date OpenAPI 3.0 specs — automatically. No spec files to write, no annotations to maintain.
Route your requests through the EasyDocs proxy. Nothing to install in your project.
npx @easydocs/cli proxy --project=my-api --port=3999Then send requests through the proxy:
http://localhost:3999?target=https://api.example.com/users
npm install @easydocs/expressimport { easydocs } from "@easydocs/express";
app.use(easydocs({ project: "my-api" }));
// all your existing routes stay the samenpm install -D @easydocs/dashboard
npx easydocs dashboard
# → http://localhost:4999Or export to a file:
npx easydocs export > openapi.json
npx easydocs export --yaml > openapi.yaml- Middleware (or proxy) intercepts every request and response
- A background queue feeds the captured data to an AI model — nothing blocks your request
- The AI generates or updates an OpenAPI 3.0 Operation object for that endpoint
- Response-shape hashing skips re-processing when the structure hasn't changed
- Specs are stored in SQLite (default) or Postgres
- The dashboard reads from that database and renders live docs
| Package | Framework |
|---|---|
@easydocs/express |
Express |
@easydocs/fastify |
Fastify |
@easydocs/hono |
Hono |
@easydocs/nestjs |
NestJS |
@easydocs/nextjs |
Next.js (App Router + Pages Router) |
@easydocs/h3 |
h3 / Nitro / Nuxt |
@easydocs/elysia |
Elysia (Bun) |
@easydocs/cli |
Proxy + export (no framework needed) |
Set one environment variable:
# OpenAI (default)
OPENAI_API_KEY=sk-...
# Anthropic
ANTHROPIC_API_KEY=sk-ant-...
# DeepSeek
DEEPSEEK_API_KEY=sk-...
# Ollama (local, no key needed)
# configure in code: easydocs({ ai: { provider: 'ollama' } })EasyDocs auto-detects the provider from your environment. If no key is set, it falls back to Ollama at localhost:11434.
easydocs({
project: "my-api", // separate spec per service, default: 'default'
ai: {
provider: "openai", // 'openai' | 'anthropic' | 'ollama' | 'deepseek'
model: "gpt-4o",
apiKey: "...", // optional, falls back to env vars
},
storage: {
type: "sqlite", // 'sqlite' | 'postgres'
url: "file:./docs.sqlite",
},
capture: {
ignoreRoutes: ["/health", "/metrics"],
includePaths: ["/api"],
},
dashboard: {
autoStart: true, // spawn dashboard on first capture (dev only)
port: 4999,
},
});Scope traffic from different services to separate specs:
// service-a
app.use(easydocs({ project: "users-service" }));
// service-b
app.use(easydocs({ project: "orders-service" }));Switch between projects in the dashboard or scope the export:
npx easydocs export --project=users-service > users.jsonMIT
