API Spec Template (OpenAPI) for AI Coding
Free OpenAPI template designed for AI coding tools. Includes endpoint contracts, request/response schemas, error handling, and authentication. Prevents hallucinated APIs.
TL;DR: This OpenAPI template prevents AI tools from inventing endpoints, wrong payloads, or missing error handling. Copy, customize, and feed to your AI coding tool.
Table of Contents
- Why API Specs Prevent Hallucinations
- The Template
- How to Customize
- Common Patterns
- Error Handling Standard
- Authentication Patterns
- Using with AI Tools
- Related Templates
Why API Specs Prevent Hallucinations
Without an API spec, AI coding tools:
- Invent endpoints like
/api/users/sync(doesn't exist) - Guess payload fields (
userIdvsuser_idvsid) - Ignore error handling
- Assume wrong authentication methods
The Fix
An OpenAPI spec defines:
| Element | Prevents |
|---|---|
| Paths | Wrong endpoint URLs |
| Methods | GET vs POST confusion |
| Request bodies | Wrong field names, missing required fields |
| Responses | Wrong response shapes |
| Errors | Missing error handling |
| Auth | Wrong authentication |
The Template
Copy this complete OpenAPI template:
openapi: 3.0.3
info:
title: "[PROJECT NAME] API"
version: "1.0.0"
description: |
[One paragraph describing your API]
## Authentication
All endpoints require Bearer token authentication unless marked [Public].
## Errors
All errors follow the standard error response format.
servers:
- url: http://localhost:3000/api
description: Local development
- url: https://api.[YOUR-DOMAIN].com
description: Production
tags:
- name: Health
description: System health checks
- name: Auth
description: Authentication endpoints
- name: "[Resource 1]"
description: "[Description]"
- name: "[Resource 2]"
description: "[Description]"
## ============================================================
## PATHS
## ============================================================
paths:
# # ----------------------------------------------------------
# # Health
# # ----------------------------------------------------------
/health:
get:
tags:
- Health
summary: Health check [Public]
description: Returns API health status. No authentication required.
operationId: getHealth
security: [] # Public endpoint
responses:
200:
description: API is healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: [ok, degraded, down]
example: "ok"
timestamp:
type: string
format: date-time
# # ----------------------------------------------------------
# # Auth
# # ----------------------------------------------------------
/auth/signup:
post:
tags:
- Auth
summary: Create new account [Public]
operationId: signup
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
example: "user@example.com"
password:
type: string
format: password
minLength: 8
example: "securepassword123"
name:
type: string
example: "John Doe"
responses:
201:
description: Account created
content:
application/json:
schema:
$ref: '#/components/schemas/AuthResponse'
400:
$ref: '#/components/responses/BadRequest'
409:
$ref: '#/components/responses/Conflict'
/auth/login:
post:
tags:
- Auth
summary: Login [Public]
operationId: login
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
password:
type: string
format: password
responses:
200:
description: Login successful
content:
application/json:
schema:
$ref: '#/components/schemas/AuthResponse'
401:
$ref: '#/components/responses/Unauthorized'
/auth/me:
get:
tags:
- Auth
summary: Get current user
operationId: getCurrentUser
responses:
200:
description: Current user
content:
application/json:
schema:
$ref: '#/components/schemas/User'
401:
$ref: '#/components/responses/Unauthorized'
# # ----------------------------------------------------------
# # [RESOURCE] - Replace with your resources
# # ----------------------------------------------------------
/[resources]:
get:
tags:
- "[Resource]"
summary: List [resources]
operationId: list[Resources]
parameters:
- $ref: '#/components/parameters/LimitParam'
- $ref: '#/components/parameters/OffsetParam'
- name: sort
in: query
schema:
type: string
enum: [created_at, updated_at, name]
default: created_at
- name: order
in: query
schema:
type: string
enum: [asc, desc]
default: desc
responses:
200:
description: List of [resources]
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/[Resource]'
meta:
$ref: '#/components/schemas/PaginationMeta'
401:
$ref: '#/components/responses/Unauthorized'
post:
tags:
- "[Resource]"
summary: Create [resource]
operationId: create[Resource]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/[Resource]Create'
responses:
201:
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/[Resource]'
400:
$ref: '#/components/responses/BadRequest'
401:
$ref: '#/components/responses/Unauthorized'
/[resources]/{id}:
get:
tags:
- "[Resource]"
summary: Get [resource] by ID
operationId: get[Resource]ById
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
200:
description: [Resource] details
content:
application/json:
schema:
$ref: '#/components/schemas/[Resource]'
401:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
patch:
tags:
- "[Resource]"
summary: Update [resource]
operationId: update[Resource]
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/[Resource]Update'
responses:
200:
description: Updated
content:
application/json:
schema:
$ref: '#/components/schemas/[Resource]'
400:
$ref: '#/components/responses/BadRequest'
401:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
delete:
tags:
- "[Resource]"
summary: Delete [resource]
operationId: delete[Resource]
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
204:
description: Deleted (no content)
401:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
## ============================================================
## COMPONENTS
## ============================================================
components:
# # ----------------------------------------------------------
# # Schemas
# # ----------------------------------------------------------
schemas:
# # Auth
AuthResponse:
type: object
properties:
user:
$ref: '#/components/schemas/User'
token:
type: string
description: JWT access token
expires_at:
type: string
format: date-time
User:
type: object
properties:
id:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
# # [Resource] - Customize these
"[Resource]":
type: object
properties:
id:
type: string
format: uuid
name:
type: string
description:
type: string
nullable: true
status:
type: string
enum: [active, archived]
owner_id:
type: string
format: uuid
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
"[Resource]Create":
type: object
required:
- name
properties:
name:
type: string
minLength: 1
maxLength: 100
description:
type: string
maxLength: 500
"[Resource]Update":
type: object
properties:
name:
type: string
minLength: 1
maxLength: 100
description:
type: string
maxLength: 500
status:
type: string
enum: [active, archived]
# # Common
PaginationMeta:
type: object
properties:
total:
type: integer
limit:
type: integer
offset:
type: integer
has_more:
type: boolean
Error:
type: object
required:
- error
- message
properties:
error:
type: string
description: Error code (snake_case)
example: "validation_error"
message:
type: string
description: Human-readable message
example: "Email is required"
details:
type: object
description: Additional error context
additionalProperties: true
# # ----------------------------------------------------------
# # Parameters
# # ----------------------------------------------------------
parameters:
IdParam:
name: id
in: path
required: true
schema:
type: string
format: uuid
description: Resource ID
LimitParam:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 10
description: Number of items to return
OffsetParam:
name: offset
in: query
schema:
type: integer
minimum: 0
default: 0
description: Number of items to skip
# # ----------------------------------------------------------
# # Responses
# # ----------------------------------------------------------
responses:
BadRequest:
description: Bad request - validation error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "validation_error"
message: "Request validation failed"
details:
email: "Invalid email format"
Unauthorized:
description: Unauthorized - missing or invalid token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "unauthorized"
message: "Authentication required"
Forbidden:
description: Forbidden - insufficient permissions
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "forbidden"
message: "You don't have permission to access this resource"
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "not_found"
message: "Resource not found"
Conflict:
description: Conflict - resource already exists
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "conflict"
message: "Email already registered"
InternalError:
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "internal_error"
message: "An unexpected error occurred"
# # ----------------------------------------------------------
# # Security Schemes
# # ----------------------------------------------------------
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
JWT access token. Include in header:
`Authorization: Bearer <token>`
## Default security (applied to all endpoints unless overridden)
security:
- bearerAuth: []
How to Customize
Step 1: Replace Placeholders
Find and replace all [PLACEHOLDERS]:
[PROJECT NAME]→ Your project name[YOUR-DOMAIN]→ Your domain[Resource]→ Your main resource (e.g., "Project", "Task", "Document")
Step 2: Add Your Endpoints
Copy the resource pattern for each resource:
/projects→ List/Create/projects/{id}→ Get/Update/Delete
Step 3: Define Your Schemas
For each resource, define:
- Base schema (full object)
- Create schema (required fields only)
- Update schema (optional fields only)
Step 4: Add Custom Endpoints
For action endpoints (not CRUD):
/[resources]/{id}/[action]:
post:
summary: [Action description]
# # ...
Using with AI Tools
Cursor
Reference in prompts:
Using @api-spec.yaml, implement the POST /projects endpoint.
Include all validation and error handling from the spec.
Cline
Add to .clinerules:
## API Implementation Rules
1. All endpoints must match /docs/api-spec.yaml
2. All request/response shapes must match schemas
3. All error responses must use the Error schema
v0 / Lovable
For frontend work, paste relevant endpoint definitions:
API endpoint for creating projects:
POST /api/projects
Body: { name: string, description?: string }
Response: { id, name, description, created_at }
Related Templates
- PRD Template — Scope + requirements
- Database Schema Template — Tables + columns
- SDD Template Pack — Full spec kit
- How to Stop AI Hallucinating Code — The workflow
Want all your APIs designed automatically? Generate from a brain dump →
Last updated: January 2026
Generate All 60+ Documents Automatically
Skip manual template filling. Context Ark generates complete spec packs from a brain dump.
Get Started Free →