TypeScript types from the Buffy OpenAPI spec (codegen walkthrough)
Hand-written fetch calls drift from reality quickly—especially across POST /v1/message, activities CRUD, and webhook-shaped payloads. Buffy publishes a first-class OpenAPI 3 description; this post shows how to turn that YAML into TypeScript types (and optionally a generated SDK) so your integration breaks at compile time when the contract changes.
Start with the map, not a wall of paths: Buffy API reference overview. The integration story lives in Buffy API — integrate your app.
Prerequisites
- Node 18+ and a package manager (
npm,pnpm, oryarn). - A server-side Buffy API key from Account → API keys on buffyai.org (never commit it; load from env).
- Canonical spec URL:
https://api.buffyai.org/openapi.yaml(same host ashttps://api.buffyai.org; interactive docs are often at/swagger).
Fetch the spec (local file or CI)
Download a snapshot for reproducible builds:
curl -fsSL "https://api.buffyai.org/openapi.yaml" -o openapi/buffy.yaml
In CI, you can fail the job if the spec changes unexpectedly:
curl -fsSL "https://api.buffyai.org/openapi.yaml" | shasum -a 256
Store the hash in a comment or artifact log; when Buffy ships breaking changes, regenerate types deliberately and fix compile errors rather than shipping silent runtime bugs.
Option A — Types only with openapi-typescript
openapi-typescript turns the YAML into a paths / components type map—small output, no runtime SDK.
Install (dev dependency):
npm install -D openapi-typescript
Generate (pin the CLI version in package.json; upgrade when you want new OpenAPI features):
npx openapi-typescript https://api.buffyai.org/openapi.yaml -o ./src/generated/buffy-api.ts
Or from the downloaded file:
npx openapi-typescript ./openapi/buffy.yaml -o ./src/generated/buffy-api.ts
Use the types with fetch. Exact paths[...] keys follow whatever the spec names (for example /v1/message). After generation, explore buffy-api.ts in your editor—TypeScript will guide you to the correct requestBody and response shapes.
import type { paths } from "./generated/buffy-api";
const BASE = "https://api.buffyai.org";
type MessageRequest =
paths["/v1/message"]["post"]["requestBody"]["content"]["application/json"];
type MessageResponse =
paths["/v1/message"]["post"]["responses"][200]["content"]["application/json"];
export async function sendMessage(
apiKey: string,
body: MessageRequest
): Promise<MessageResponse> {
const res = await fetch(`${BASE}/v1/message`, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) {
const text = await res.text();
throw new Error(`Buffy API ${res.status}: ${text}`);
}
return (await res.json()) as MessageResponse;
}
// Example body shape from production OpenAPI — `user_id` + `platform` + `message` are required:
// sendMessage(apiKey, { user_id: "usr_…", platform: "cli", message: "Ping from codegen smoke test." })
First sanity check with curl (fill real user_id from /v1/auth/me or your integration):
export BUFFY_API_KEY="your_key"
curl -sS -X POST "https://api.buffyai.org/v1/message" \
-H "Authorization: Bearer $BUFFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"user_id":"usr_your_id","platform":"cli","message":"Ping from curl."}'
If your generated paths keys differ slightly (for example versioned prefixes), adjust the indexed access once—the generated file is the source of truth, not this blog snippet.
Optional — openapi-fetch
If you want a thin typed client instead of raw fetch, pair openapi-typescript with openapi-fetch. The pattern is: generate types, create a client with createClient<paths>({ baseUrl: BASE }), then call typed .POST("/v1/message", { body: ... }). Treat it as syntactic sugar over the same Bearer header rules.
Option B — Generated SDK with OpenAPI Generator
When you want classes or modules emitted for every operation, use OpenAPI Generator with the typescript-fetch generator (names and folders vary by generator version).
One-shot via Docker (avoids local Java installs):
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
-i https://api.buffyai.org/openapi.yaml \
-g typescript-fetch \
-o /local/generated/buffy-sdk
Trade-offs:
- Pros: Faster time-to-hello-world for large specs; lots of operations wrapped.
- Cons: Large diffs on regeneration; you may need to wrap awkward method names; merge conflicts when upgrading.
For many Buffy integrations, Option A + a few hand-written helpers stays easier to own than a full generated SDK.
Auth and safety
- Send
Authorization: Bearer <API_KEY>on every request (see API reference overview). - Keep keys in
process.envor a secrets manager; block.envfrom git. - Prefer server-side calls. If a mobile or web app needs Buffy, proxy through your backend.
Keep types fresh
Add scripts to package.json:
{
"scripts": {
"gen:buffy": "openapi-typescript https://api.buffyai.org/openapi.yaml -o src/generated/buffy-api.ts"
}
}
Run gen:buffy when you upgrade integrations or when Buffy announces API changes. Fix TypeScript errors locally before deploy—that is the point of codegen.
Next step
Wire the behavior loop: First week with the Buffy API, then Buffy webhook integrations for outbound events. For tool-style access, see MCP tools with the Buffy API.