Skip to content

SDK generation

The CLI reads {mount}/callspec.json (mount URL or file path) and writes a typed ApiClient. Add --validators only if you use spec({ exports }) for shared form preds — see Shared validation.

# Live mount
npx callspec http://127.0.0.1:3000/v1 --output src/generated/api.ts
# From a pinned file
npx callspec ./callspec.json --output src/generated/api.ts
# Optional second pass
npx callspec ./callspec.json --output src/generated/validators.ts --validators

Generated code imports only callspec/client (browser-safe) — one typed method per route. Codegen reads callspec.json, not OpenAPI.

A live URL is enough when the server is already up in the same pipeline. Pin callspec.json when frontend CI should not boot the API, you want contract diffs in PRs, or another repo consumes the file.

curl -fsS http://127.0.0.1:3000/v1/callspec.json -o callspec.json

Or emit without HTTP:

import {writeFileSync} from 'fs';
import {emitCallspec} from 'callspec/document';
import {api} from '../server/routes';
writeFileSync(
'callspec.json',
JSON.stringify(
emitCallspec(api.routes, {
title: api.meta.title ?? 'My API',
version: api.meta.version ?? '1.0.0',
basePath: '/v1',
description: api.meta.intro,
exports: api.exports,
}),
null,
2,
),
);
"scripts": {
"generate:api": "callspec ./callspec.json --output src/generated/api.ts",
"check:api": "npm run generate:api && git diff --exit-code src/generated/api.ts callspec.json"
}

Commit the contract file, the generated SDK, or both — match check:api to what you keep in git.