Generate Your PRD Free — No account required
Try PRD Generator →
Back to Templates
TemplateFree Download

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

  1. Why API Specs Prevent Hallucinations
  2. The Template
  3. How to Customize
  4. Common Patterns
  5. Error Handling Standard
  6. Authentication Patterns
  7. Using with AI Tools
  8. 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 (userId vs user_id vs id)
  • 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


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 →