api-spec-builder takes a prose description of an API feature — “we need to let users search orders by date range and status, returning a paginated list” — and produces a valid OpenAPI 3.1 YAML fragment with paths, request schemas, response schemas, error shapes, and a working example response.
Designed for the moment when you’re about to start building a new endpoint and you’d rather review a YAML than write one from scratch.
At a glance
| Field | Value |
|---|---|
| Name | api-spec-builder |
| Version | 1.0.0 |
| Files | 1 file (SKILL.md) |
| Runtime | None — pure prompting |
| Triggers on | “write OpenAPI for…”, “spec out an endpoint that…”, “I need an API to…”, “draft the schema for a search endpoint”, “turn this requirement into OpenAPI” |
| Does NOT trigger on | generating server code from a spec, generating a TypeScript SDK, designing the database schema |
Step 1 — Create the folder
mkdir -p ~/.claude/skills/api-spec-builderWindows:
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.claude\skills\api-spec-builder" | Out-NullStep 2 — Paste this file
Path: ~/.claude/skills/api-spec-builder/SKILL.md
---
name: api-spec-builder
description: Use this skill whenever the user describes an API feature in prose and wants the OpenAPI 3.1 YAML for it. Trigger on "write OpenAPI for…", "spec out an endpoint that…", "I need an API to…", "draft the schema for a search endpoint", "turn this requirement into OpenAPI". Do NOT use for generating server-side code from a spec, building a TypeScript SDK, or designing the database schema — those are downstream jobs handled by other skills.
version: 1.0.0
---
# api-spec-builder
Takes a prose feature description and produces a valid OpenAPI 3.1 YAML fragment ready to paste into the project's `openapi.yaml`.
## When invoked
If the prose is missing something obvious, ask ONE clarifying question covering all the gaps in a single turn. Do not Q&A-loop the user. Default to sensible REST conventions:
- Resource collections: `GET /resource`, `POST /resource`
- Single resource: `GET /resource/{id}`, `PATCH /resource/{id}`, `DELETE /resource/{id}`
- Sub-resources: `GET /resource/{id}/sub-resource`
- Search: `POST /resource/search` (not GET — search inputs grow beyond URL limits)
- Filters: query params for simple cases; POST body for complex
- Pagination: cursor-based (`cursor`, `limit`) — not page numbers
- Auth: `bearer` token via `Authorization` header
## Output structure
Always emit YAML with these sections in this order:
paths:
/your/endpoint:
method:
summary: …
description: …
tags: [resource]
parameters: # query/path/header
- …
requestBody: # if applicable
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/X'
responses:
'200': …
'400': …
'401': …
'404': … # if path has {id}
security:
- bearerAuth: []
components:
schemas:
X:
type: object
required: […]
properties: { … }
Y: …
responses:
Error: # reusable error envelope
description: …
content: …
securitySchemes:
bearerAuth:
type: http
scheme: bearer
The fragment must be valid OpenAPI 3.1 (note: 3.1 uses JSON Schema 2020-12 — `nullable` is replaced by `type: [string, "null"]`).
## Schema rules
- Every property has a `description` (one short sentence) and an `example`.
- Strings have `minLength`/`maxLength` if there's any reasonable bound.
- Numbers have `minimum`/`maximum` where they exist.
- Enums use `enum:` with all valid values listed; do NOT make up values.
- IDs are strings (UUID or opaque), not integers, unless the user specifies otherwise.
- Timestamps are `string` with `format: date-time` (ISO 8601).
- Money is an object `{ amount_minor: integer, currency: string }`, not a float.
## Error responses
Always include a reusable `Error` response component with this shape and reference it from `400/401/404/409/422/500`:
type: object
required: [code, message]
properties:
code: { type: string, example: invalid_argument }
message: { type: string, example: "limit must be between 1 and 100" }
details: { type: array, items: { type: object } }
Per-endpoint, only list the response codes that actually apply. Don't carpet-bomb every code.
## Example responses
Every `200` (and `201` where applicable) gets an `example` block under `content.application/json` with realistic-looking data — not "string", not "lorem ipsum". Make IDs look like real IDs, dates like real dates, money like real money. The example is the spec's most-read line; treat it as documentation.
## When NOT to use
- Generating server code → different skill (codegen)
- Building TypeScript/Python SDKs from the spec → SDK-gen skill
- Designing the database schema behind the API → data-model skill
## Output
Print the YAML in a single fenced code block. No preamble. If the user wants the file written to disk, they'll ask — default is paste-back.Step 3 — Restart Claude Code
/clearor quit and re-open the CLI.
Step 4 — Try it
Write the OpenAPI for an endpoint that lets a logged-in user
search their orders by date range, status (one of: pending,
shipped, delivered, cancelled), and an optional text query
on order notes. Return paginated results, max 50 per page.The skill produces a POST /orders/search endpoint with cursor pagination, a request body schema with date range + enum status + free-text query, a response with orders array + next_cursor, an Order schema with realistic example IDs and timestamps, plus error responses for 400 / 401 / 422.
Customising
- Pin your project’s auth scheme. Replace the
securitySchemesblock inSKILL.mdwith the one your project uses (API key, OAuth2, mTLS). - Different ID format. If your project uses snowflake IDs or hashids, edit the “IDs are strings” line to specify the format and pattern.
- Stricter error envelope. If your team uses Problem Details (RFC 7807), replace the
Errorcomponent spec with the RFC 7807 shape.
Related
More skills in the Skill Library. For testing changes to this skill before shipping them, see Testing a Skill Before You Ship It.