# Example: API Documentation Page

This example shows how to write comprehensive API documentation for external-facing APIs or internal service interfaces.

## Example API: User Authentication Service

### ✅ Good Example (Complete API Documentation)

---

# User Authentication API

REST API for user authentication, session management, and token operations.

**Base URL:** `https://api.example.com/v1`
**Version:** 1.0.0
**Last Updated:** 2026-01-07

---

## Table of Contents

- [Authentication](#authentication)
- [Endpoints](#endpoints)
  - [POST /auth/login](#post-authlogin)
  - [POST /auth/logout](#post-authlogout)
  - [POST /auth/refresh](#post-authrefresh)
  - [GET /auth/verify](#get-authverify)
- [Data Models](#data-models)
- [Error Codes](#error-codes)
- [Rate Limiting](#rate-limiting)
- [Security Considerations](#security-considerations)
- [Examples](#examples)

---

## Authentication

All authenticated endpoints require a JWT token in the Authorization header:

```http
Authorization: Bearer <jwt_token>
```

Tokens are obtained via the `/auth/login` endpoint and expire after 1 hour. Use `/auth/refresh` to obtain a new token without re-authenticating.

---

## Endpoints

### POST /auth/login

Authenticate a user and receive access and refresh tokens.

**Authentication:** None (public endpoint)

#### Request

**Headers:**
```http
Content-Type: application/json
```

**Body:**
```json
{
  "email": "user@example.com",
  "password": "securePassword123!",
  "remember_me": false
}
```

**Parameters:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | User's email address (max 255 chars) |
| `password` | string | Yes | User's password (min 8 chars) |
| `remember_me` | boolean | No | If true, extends refresh token lifetime to 30 days. Default: false (7 days) |

**Validation Rules:**
- Email must be valid format (RFC 5322)
- Password minimum 8 characters
- Rate limited to 5 attempts per email per 15 minutes

#### Response

**Success (200 OK):**
```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "user": {
    "id": "usr_1a2b3c4d5e",
    "email": "user@example.com",
    "name": "John Doe",
    "role": "user",
    "created_at": "2025-12-01T10:30:00Z"
  }
}
```

**Response Fields:**

| Field | Type | Description |
|-------|------|-------------|
| `access_token` | string | JWT access token for authenticated requests (1 hour lifetime) |
| `refresh_token` | string | JWT refresh token for obtaining new access tokens (7-30 day lifetime) |
| `token_type` | string | Always "Bearer" |
| `expires_in` | integer | Access token lifetime in seconds (3600 = 1 hour) |
| `user` | object | User profile information |
| `user.id` | string | Unique user identifier |
| `user.email` | string | User's email address |
| `user.name` | string | User's display name |
| `user.role` | string | User role: "user", "admin", "moderator" |
| `user.created_at` | string | ISO 8601 timestamp of account creation |

#### Error Responses

**Invalid Credentials (401 Unauthorized):**
```json
{
  "error": "invalid_credentials",
  "error_description": "Email or password is incorrect",
  "attempts_remaining": 3
}
```

**Account Locked (403 Forbidden):**
```json
{
  "error": "account_locked",
  "error_description": "Account has been locked due to too many failed login attempts",
  "locked_until": "2026-01-07T15:45:00Z"
}
```

**Rate Limited (429 Too Many Requests):**
```json
{
  "error": "rate_limit_exceeded",
  "error_description": "Too many login attempts. Please try again later.",
  "retry_after": 900
}
```

**Validation Error (400 Bad Request):**
```json
{
  "error": "validation_error",
  "error_description": "Request validation failed",
  "details": [
    {
      "field": "email",
      "message": "Invalid email format"
    },
    {
      "field": "password",
      "message": "Password must be at least 8 characters"
    }
  ]
}
```

#### Example Usage

**cURL:**
```bash
curl -X POST https://api.example.com/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "securePassword123!",
    "remember_me": true
  }'
```

**Python:**
```python
import requests

response = requests.post(
    "https://api.example.com/v1/auth/login",
    json={
        "email": "user@example.com",
        "password": "securePassword123!",
        "remember_me": True
    }
)

if response.status_code == 200:
    data = response.json()
    access_token = data["access_token"]
    print(f"Logged in as {data['user']['name']}")
else:
    error = response.json()
    print(f"Login failed: {error['error_description']}")
```

**JavaScript (fetch):**
```javascript
const response = await fetch('https://api.example.com/v1/auth/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: 'user@example.com',
    password: 'securePassword123!',
    remember_me: true
  })
});

const data = await response.json();
if (response.ok) {
  const { access_token, user } = data;
  console.log(`Logged in as ${user.name}`);
  // Store token for authenticated requests
  localStorage.setItem('access_token', access_token);
} else {
  console.error(`Login failed: ${data.error_description}`);
}
```

---

### POST /auth/logout

Invalidate the current access and refresh tokens.

**Authentication:** Required (Bearer token)

#### Request

**Headers:**
```http
Authorization: Bearer <access_token>
```

**Body:** None

#### Response

**Success (200 OK):**
```json
{
  "message": "Successfully logged out"
}
```

#### Error Responses

**Unauthorized (401 Unauthorized):**
```json
{
  "error": "unauthorized",
  "error_description": "Invalid or expired token"
}
```

#### Example Usage

**cURL:**
```bash
curl -X POST https://api.example.com/v1/auth/logout \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

**Python:**
```python
response = requests.post(
    "https://api.example.com/v1/auth/logout",
    headers={"Authorization": f"Bearer {access_token}"}
)
```

---

### POST /auth/refresh

Obtain a new access token using a refresh token.

**Authentication:** None (uses refresh token in body)

#### Request

**Headers:**
```http
Content-Type: application/json
```

**Body:**
```json
{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

#### Response

**Success (200 OK):**
```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

#### Error Responses

**Invalid Token (401 Unauthorized):**
```json
{
  "error": "invalid_token",
  "error_description": "Refresh token is invalid or expired"
}
```

---

### GET /auth/verify

Verify that the current access token is valid and get user info.

**Authentication:** Required (Bearer token)

#### Request

**Headers:**
```http
Authorization: Bearer <access_token>
```

#### Response

**Success (200 OK):**
```json
{
  "valid": true,
  "user": {
    "id": "usr_1a2b3c4d5e",
    "email": "user@example.com",
    "name": "John Doe",
    "role": "user"
  },
  "expires_at": "2026-01-07T16:30:00Z"
}
```

---

## Data Models

### User Object

```typescript
interface User {
  id: string;              // Unique identifier (format: usr_[a-z0-9]{10})
  email: string;           // Email address (max 255 chars)
  name: string;            // Display name (max 100 chars)
  role: "user" | "admin" | "moderator";  // User role
  created_at: string;      // ISO 8601 timestamp
  updated_at?: string;     // ISO 8601 timestamp (optional)
}
```

### Token Response

```typescript
interface TokenResponse {
  access_token: string;    // JWT access token
  refresh_token?: string;  // JWT refresh token (only on login)
  token_type: "Bearer";    // Always "Bearer"
  expires_in: number;      // Lifetime in seconds
}
```

---

## Error Codes

| Error Code | HTTP Status | Description | Recovery Action |
|------------|-------------|-------------|-----------------|
| `invalid_credentials` | 401 | Email or password incorrect | Verify credentials and retry |
| `account_locked` | 403 | Account locked due to failed attempts | Wait until `locked_until` timestamp |
| `unauthorized` | 401 | Missing or invalid access token | Re-authenticate via `/auth/login` |
| `invalid_token` | 401 | Refresh token invalid or expired | Re-authenticate via `/auth/login` |
| `rate_limit_exceeded` | 429 | Too many requests | Wait `retry_after` seconds |
| `validation_error` | 400 | Request validation failed | Fix validation errors in `details` |
| `server_error` | 500 | Internal server error | Retry with exponential backoff |

---

## Rate Limiting

**Login Endpoint:**
- 5 attempts per email per 15 minutes
- After 5 failed attempts: account locked for 15 minutes
- After 10 failed attempts in 24 hours: account locked for 24 hours

**Other Endpoints:**
- 100 requests per minute per access token
- Rate limit headers included in all responses:
  ```http
  X-RateLimit-Limit: 100
  X-RateLimit-Remaining: 95
  X-RateLimit-Reset: 1609459200
  ```

---

## Security Considerations

### Token Storage
- **Never** store tokens in localStorage for sensitive applications (XSS risk)
- Use httpOnly cookies for web applications when possible
- Store tokens in secure storage (Keychain/Keystore) for mobile apps

### HTTPS Only
- All API calls **must** use HTTPS
- HTTP requests will be rejected with 426 Upgrade Required

### Token Expiration
- Access tokens expire after 1 hour
- Refresh tokens expire after 7 days (30 days with `remember_me`)
- Implement token refresh logic before expiration

### Password Requirements
- Minimum 8 characters
- Must contain: uppercase, lowercase, number, special character
- Cannot be a common password (checked against breach database)

---

## Examples

### Complete Authentication Flow

```python
import requests
from datetime import datetime, timedelta

class AuthClient:
    def __init__(self, base_url: str):
        self.base_url = base_url
        self.access_token = None
        self.refresh_token = None
        self.token_expires_at = None

    def login(self, email: str, password: str, remember_me: bool = False):
        """Authenticate and store tokens."""
        response = requests.post(
            f"{self.base_url}/auth/login",
            json={
                "email": email,
                "password": password,
                "remember_me": remember_me
            }
        )
        response.raise_for_status()

        data = response.json()
        self.access_token = data["access_token"]
        self.refresh_token = data["refresh_token"]
        self.token_expires_at = datetime.now() + timedelta(seconds=data["expires_in"])

        return data["user"]

    def refresh_access_token(self):
        """Refresh the access token using refresh token."""
        response = requests.post(
            f"{self.base_url}/auth/refresh",
            json={"refresh_token": self.refresh_token}
        )
        response.raise_for_status()

        data = response.json()
        self.access_token = data["access_token"]
        self.token_expires_at = datetime.now() + timedelta(seconds=data["expires_in"])

    def get_headers(self):
        """Get headers with valid access token."""
        # Refresh if token expires in < 5 minutes
        if datetime.now() + timedelta(minutes=5) >= self.token_expires_at:
            self.refresh_access_token()

        return {"Authorization": f"Bearer {self.access_token}"}

# Usage
client = AuthClient("https://api.example.com/v1")
user = client.login("user@example.com", "securePassword123!")
print(f"Logged in as {user['name']}")

# Make authenticated requests
headers = client.get_headers()
response = requests.get("https://api.example.com/v1/protected", headers=headers)
```

---

## Related Documentation

- **Authentication Architecture**: `docs/architecture/authentication.md`
- **Security Best Practices**: `docs/security/api-security.md`
- **Client SDK Documentation**: `docs/sdks/`
- **API Changelog**: `docs/api/CHANGELOG.md`

---

**API Support:** api-support@example.com
**Bug Reports:** https://github.com/example/api/issues
**Status Page:** https://status.example.com
