Back to Skills
⚙️
VerifiedSimple🥈silver⚙️Meta-Skills

api-documentation-writer

Expert guide for writing comprehensive API documentation including OpenAPI specs, endpoint references, authentication guides, and code examples. Use when documenting APIs, creating developer portals, or improving API discoverability.

Verified
Version1.0.0
AuthorID8Labs
LicenseMIT
Published1/8/2026
View on GitHub

Skill Content

---
name: api-documentation-writer
description: Expert guide for writing comprehensive API documentation including OpenAPI specs, endpoint references, authentication guides, and code examples. Use when documenting APIs, creating developer portals, or improving API discoverability.
---

# API Documentation Writer Skill

## Overview

This skill helps you create clear, comprehensive API documentation that developers love. Covers OpenAPI/Swagger specifications, endpoint references, authentication guides, code examples in multiple languages, and developer experience best practices.

## Documentation Philosophy

### The Three C's
1. **Clear**: Unambiguous, jargon-free explanations
2. **Complete**: All parameters, responses, and edge cases documented
3. **Current**: Always in sync with the actual API behavior

### What to Document
- **DO**: Document every public endpoint
- **DO**: Include request/response examples for all scenarios
- **DO**: Document error codes with remediation steps
- **DO**: Provide code examples in popular languages
- **DON'T**: Document internal/private endpoints
- **DON'T**: Assume readers know your domain
- **DON'T**: Let documentation drift from implementation

## OpenAPI Specification

### Basic Structure

```yaml
# openapi.yaml
openapi: 3.1.0
info:
  title: My API
  version: 1.0.0
  description: |
    Welcome to the My API documentation.

    ## Getting Started
    1. Sign up for an API key at [dashboard.example.com](https://dashboard.example.com)
    2. Include your key in the `Authorization` header
    3. Start making requests!

    ## Rate Limits
    - Free tier: 100 requests/minute
    - Pro tier: 1000 requests/minute
  contact:
    name: API Support
    email: api@example.com
    url: https://support.example.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.example.com/v1
    description: Production
  - url: https://staging-api.example.com/v1
    description: Staging

tags:
  - name: Users
    description: User management operations
  - name: Items
    description: Item CRUD operations
```

### Endpoint Documentation

```yaml
paths:
  /users:
    get:
      tags:
        - Users
      summary: List all users
      description: |
        Retrieves a paginated list of users. Results are sorted by creation date (newest first).

        **Permissions required:** `users:read`
      operationId: listUsers
      parameters:
        - name: page
          in: query
          description: Page number (1-indexed)
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
          example: 1
        - name: limit
          in: query
          description: Number of results per page (max 100)
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          example: 20
        - name: status
          in: query
          description: Filter by user status
          required: false
          schema:
            type: string
            enum: [active, inactive, pending]
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserList'
              example:
                data:
                  - id: "usr_123"
                    email: "john@example.com"
                    name: "John Doe"
                    status: "active"
                    created_at: "2024-01-15T10:30:00Z"
                meta:
                  page: 1
                  limit: 20
                  total: 150
                  total_pages: 8
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'

    post:
      tags:
        - Users
      summary: Create a new user
      description: |
        Creates a new user account. An email verification will be sent to the provided address.

        **Permissions required:** `users:write`
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
            examples:
              basic:
                summary: Basic user creation
                value:
                  email: "jane@example.com"
                  name: "Jane Doe"
              with_metadata:
                summary: User with metadata
                value:
                  email: "jane@example.com"
                  name: "Jane Doe"
                  metadata:
                    department: "Engineering"
                    role: "Developer"
      responses:
        '201':
          description: User created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          description: User with this email already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: "USER_EXISTS"
                  message: "A user with this email already exists"
```

### Schema Definitions

```yaml
components:
  schemas:
    User:
      type: object
      description: Represents a user in the system
      required:
        - id
        - email
        - status
        - created_at
      properties:
        id:
          type: string
          description: Unique identifier (prefixed with `usr_`)
          pattern: '^usr_[a-zA-Z0-9]+$'
          example: "usr_123abc"
        email:
          type: string
          format: email
          description: User's email address (unique)
          example: "user@example.com"
        name:
          type: string
          description: User's display name
          maxLength: 100
          example: "John Doe"
        status:
          type: string
          enum: [active, inactive, pending]
          description: |
            Account status:
            - `active`: User can sign in and use the service
            - `inactive`: Account has been deactivated
            - `pending`: Awaiting email verification
          example: "active"
        metadata:
          type: object
          additionalProperties: true
          description: Custom key-value pairs for storing additional data
          example:
            department: "Engineering"
        created_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp of account creation
          example: "2024-01-15T10:30:00Z"
        updated_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp of last update
          example: "2024-01-16T14:45:00Z"

    CreateUserRequest:
      type: object
      required:
        - email
      properties:
        email:
          type: string
          format: email
          description: Email address for the new user (must be unique)
        name:
          type: string
          description: User's display name
          maxLength: 100
        metadata:
          type: object
          additionalProperties: true

    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Machine-readable error code
            message:
              type: string
              description: Human-readable error description
            details:
              type: array
              description: Additional error details for validation errors
              items:
                type: object
                properties:
                  field:
                    type: string
                  message:
                    type: string
```

### Authentication Documentation

```yaml
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        JWT token obtained from the `/auth/token` endpoint.

        Include in requests as:
        ```
        Authorization: Bearer <your-token>
        ```

        Tokens expire after 1 hour. Use refresh tokens for long-lived sessions.

    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        API key for server-to-server communication.

        Obtain your key from the [Developer Dashboard](https://dashboard.example.com).

        Include in requests as:
        ```
        X-API-Key: <your-api-key>
        ```

security:
  - BearerAuth: []
  - ApiKeyAuth: []
```

### Reusable Responses

```yaml
components:
  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            validation_error:
              summary: Validation error
              value:
                error:
                  code: "VALIDATION_ERROR"
                  message: "Request validation failed"
                  details:
                    - field: "email"
                      message: "Must be a valid email address"
            missing_field:
              summary: Missing required field
              value:
                error:
                  code: "MISSING_FIELD"
                  message: "Required field 'email' is missing"

    Unauthorized:
      description: Missing or invalid authentication
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "UNAUTHORIZED"
              message: "Invalid or expired authentication token"

    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "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:
              code: "NOT_FOUND"
              message: "The requested resource was not found"

    RateLimited:
      description: Rate limit exceeded
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Request limit per minute
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Remaining requests in current window
        X-RateLimit-Reset:
          schema:
            type: integer
          description: Unix timestamp when the rate limit resets
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "RATE_LIMITED"
              message: "Too many requests. Please retry after 60 seconds"
```

## Markdown Documentation

### Endpoint Reference Template

```markdown
# Create User

Create a new user account.

## Endpoint

```
POST /v1/users
```

## Authentication

Requires API key with `users:write` permission.

## Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | User's email address (must be unique) |
| `name` | string | No | Display name (max 100 characters) |
| `metadata` | object | No | Custom key-value pairs |

### Example Request

```bash
curl -X POST https://api.example.com/v1/users \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane@example.com",
    "name": "Jane Doe"
  }'
```

## Response

### Success (201 Created)

```json
{
  "id": "usr_abc123",
  "email": "jane@example.com",
  "name": "Jane Doe",
  "status": "pending",
  "created_at": "2024-01-15T10:30:00Z"
}
```

### Errors

| Status | Code | Description |
|--------|------|-------------|
| 400 | `VALIDATION_ERROR` | Invalid email format or missing required field |
| 401 | `UNAUTHORIZED` | Invalid or missing authentication |
| 409 | `USER_EXISTS` | User with this email already exists |
| 429 | `RATE_LIMITED` | Too many requests |

### Error Example

```json
{
  "error": {
    "code": "USER_EXISTS",
    "message": "A user with this email already exists"
  }
}
```
```

## Code Examples

### Multi-Language Examples

```markdown
## Code Examples

### cURL

```bash
curl -X GET "https://api.example.com/v1/users?limit=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### JavaScript (fetch)

```javascript
const response = await fetch('https://api.example.com/v1/users?limit=10', {
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});

const data = await response.json();
console.log(data);
```

### JavaScript (axios)

```javascript
import axios from 'axios';

const { data } = await axios.get('https://api.example.com/v1/users', {
  params: { limit: 10 },
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});
```

### Python

```python
import requests

response = requests.get(
    'https://api.example.com/v1/users',
    params={'limit': 10},
    headers={'Authorization': 'Bearer YOUR_TOKEN'}
)

data = response.json()
print(data)
```

### Ruby

```ruby
require 'net/http'
require 'json'

uri = URI('https://api.example.com/v1/users?limit=10')
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer YOUR_TOKEN'

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

data = JSON.parse(response.body)
puts data
```

### Go

```go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET", "https://api.example.com/v1/users?limit=10", nil)
    req.Header.Set("Authorization", "Bearer YOUR_TOKEN")

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    var data map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&data)
    fmt.Println(data)
}
```
```

## Error Documentation

### Error Code Reference

```markdown
# Error Codes

All API errors follow a consistent format:

```json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description",
    "details": []  // Optional additional information
  }
}
```

## Authentication Errors

| Code | HTTP Status | Description | Resolution |
|------|-------------|-------------|------------|
| `UNAUTHORIZED` | 401 | Missing or invalid token | Include a valid `Authorization` header |
| `TOKEN_EXPIRED` | 401 | Token has expired | Obtain a new token via `/auth/token` |
| `INVALID_API_KEY` | 401 | API key not recognized | Check your API key in the dashboard |
| `FORBIDDEN` | 403 | Insufficient permissions | Request appropriate scopes for your token |

## Validation Errors

| Code | HTTP Status | Description | Resolution |
|------|-------------|-------------|------------|
| `VALIDATION_ERROR` | 400 | Request body validation failed | Check the `details` array for specific fields |
| `MISSING_FIELD` | 400 | Required field not provided | Include all required fields |
| `INVALID_FORMAT` | 400 | Field format is incorrect | Match the expected format (see schema) |

## Resource Errors

| Code | HTTP Status | Description | Resolution |
|------|-------------|-------------|------------|
| `NOT_FOUND` | 404 | Resource doesn't exist | Verify the resource ID is correct |
| `ALREADY_EXISTS` | 409 | Resource already exists | Use a different identifier or update existing |
| `CONFLICT` | 409 | State conflict | Refresh and retry the operation |

## Rate Limiting

| Code | HTTP Status | Description | Resolution |
|------|-------------|-------------|------------|
| `RATE_LIMITED` | 429 | Too many requests | Wait and retry (see `Retry-After` header) |
```

## Changelog Documentation

### API Changelog Format

```markdown
# API Changelog

## 2024-01-15 - v1.2.0

### Added
- `GET /users/{id}/activity` - Retrieve user activity history
- `metadata` field on User object for custom data storage

### Changed
- Pagination now 1-indexed (previously 0-indexed)
- Rate limits increased: Free tier 100 → 200 req/min

### Deprecated
- `GET /users/search` - Use `GET /users` with query parameters instead
  - Will be removed in v2.0.0

### Fixed
- `created_at` now correctly returns UTC timezone

---

## 2024-01-01 - v1.1.0

### Added
- Webhook support for user events
- `status` filter on `GET /users`

### Security
- API keys now support IP allowlisting
```

## Interactive Documentation

### Swagger UI Configuration

```javascript
// swagger-config.js
const swaggerUiOptions = {
  customCss: '.swagger-ui .topbar { display: none }',
  customSiteTitle: 'API Documentation',
  customfavIcon: '/favicon.ico',
  swaggerOptions: {
    persistAuthorization: true,
    displayRequestDuration: true,
    filter: true,
    tryItOutEnabled: true,
  },
};
```

### Redoc Configuration

```yaml
# redoc.yaml
x-tagGroups:
  - name: Getting Started
    tags:
      - Authentication
  - name: Core Resources
    tags:
      - Users
      - Items
  - name: Utilities
    tags:
      - Webhooks
      - Health

x-logo:
  url: 'https://example.com/logo.png'
  altText: 'API Logo'
```

## Documentation Checklist

### Per Endpoint
- [ ] Summary (one line)
- [ ] Description (detailed explanation)
- [ ] All parameters documented with types and examples
- [ ] All response codes with examples
- [ ] Error codes with remediation steps
- [ ] Code examples in at least 2 languages
- [ ] Authentication requirements stated

### Overall API
- [ ] Getting started guide
- [ ] Authentication guide with examples
- [ ] Rate limiting documentation
- [ ] Pagination patterns
- [ ] Error handling guide
- [ ] Changelog maintained
- [ ] Versioning strategy documented
- [ ] SDK/library links

### Developer Experience
- [ ] Interactive "Try It" functionality
- [ ] Copy-paste ready examples
- [ ] Consistent terminology
- [ ] Search functionality
- [ ] Mobile-friendly rendering

## Tools Integration

### Generate from Code

```bash
# From Express/Node.js routes
npx swagger-jsdoc -d swaggerDef.js -o openapi.yaml

# From TypeScript types
npx openapi-typescript-codegen --input openapi.yaml --output ./sdk
```

### Validate OpenAPI

```bash
# Validate spec
npx @redocly/cli lint openapi.yaml

# Preview documentation
npx @redocly/cli preview-docs openapi.yaml
```

## When to Use This Skill

Invoke this skill when:
- Creating new API documentation from scratch
- Adding documentation for new endpoints
- Writing OpenAPI/Swagger specifications
- Creating code examples for multiple languages
- Documenting authentication flows
- Building developer portals
- Improving existing API documentation
- Setting up interactive documentation (Swagger UI, Redoc)

Tags

Statistics

Installs0
Views1

Related Skills