- name
- api-documentation
- description
- API Documentation: OpenAPI/Swagger specs, Postman collections, API reference patterns, and client SDK docs
- metadata
- {"author":"cosmicstack-labs","version":"1.0.0","category":"development","tags":["api-documentation","openapi","swagger","postman","api-reference"]}
# API Documentation
Document APIs that developers love to integrate with — complete, accurate, and testable from the spec itself.
## Core Principles
### 1. The Spec Is the Source of Truth
Your OpenAPI/Swagger specification should be the single source of truth for your API. Generate documentation, client libraries, and test suites from it. Never let docs drift from the spec.
### 2. Document the Experience, Not Just the Endpoints
Good API docs don't just list endpoints — they explain authentication, error handling, rate limits, pagination, and common workflows. Developer experience is documentation.
### 3. Every Endpoint Needs a Runnable Example
Every API endpoint should have at least one complete request/response example that a developer can copy, paste, and run. Show both success and error responses.
### 4. Version Everything, Deprecate Gracefully
APIs evolve. Documentation must clearly indicate which versions are active, deprecated, and sunset. Give consumers time to migrate with clear migration guides.
---
## API Documentation Maturity Model
| Level | Completeness | Accuracy | Interactivity | Versioning | Client Generation |
|-------|-------------|----------|---------------|------------|-------------------|
| **1: Minimal** | Endpoints listed only | Often outdated | None (static text) | No versioning | None |
| **2: Basic** | Endpoints + parameters | Occasionally accurate | Static examples | One active version | Manual SDK examples |
| **3: Structured** | Full OpenAPI spec | Verified on each release | Interactive docs (Swagger UI) | Semantic versioning | Generated SDKs |
| **4: Comprehensive** | Spec + guides + tutorials | Tested in CI | Interactive console + code samples | Multiple versions documented | Multi-language SDK generation |
| **5: Exemplary** | Spec + guides + tutorials + playground | Contract-tested | Live API playground | Automated migration guides | Published package managers |
**Target**: Level 3 minimum for internal APIs. Level 4 for public APIs.
---
## Actionable Guidance
### OpenAPI 3.0/3.1 Specification Structure
```yaml
# openapi.yaml
openapi: 3.0.3
info:
title: Payment Processing API
description: |
Process payments, manage subscriptions, and handle refunds.
## Getting Started
1. [Sign up](https://dashboard.example.com/signup) for an account
2. Generate an API key in the dashboard
3. Include the key in the `Authorization` header
## Base URLs
- Production: `https://api.example.com/v2`
- Sandbox: `https://sandbox-api.example.com/v2`
version: 2.0.0
contact:
name: API Support
email: api-support@example.com
url: https://developer.example.com/support
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0
servers:
- url: https://api.example.com/v2
description: Production server
- url: https://sandbox-api.example.com/v2
description: Sandbox (test) server
security:
- BearerAuth: []
paths:
/charges:
post:
summary: Create a charge
description: |
Creates a new charge and attempts to capture payment.
**Idempotency**: This endpoint supports idempotency. Send an
`Idempotency-Key` header to safely retry requests without
creating duplicate charges.
**Refunds**: Charges can be fully or partially refunded
within 90 days of creation via `POST /charges/{id}/refund`.
operationId: createCharge
tags:
- Charges
parameters:
- name: Idempotency-Key
in: header
required: false
schema:
type: string
format: uuid
description: |
Unique key to prevent duplicate charges.
Generate a UUID v4 for each unique charge attempt.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateChargeRequest'
example:
amount: 2999
currency: usd
source: tok_visa
description: "Premium Plan - Monthly"
metadata:
customer_id: "cus_123"
responses:
'201':
description: Charge created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Charge'
example:
id: ch_3f8a1c2b9d0e4f
amount: 2999
currency: usd
status: succeeded
description: "Premium Plan - Monthly"
created: 1710518400
metadata:
customer_id: "cus_123"
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
description: Payment failed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
type: card_declined
code: insufficient_funds
message: "The card has insufficient funds to complete the purchase."
'409':
$ref: '#/components/responses/Conflict'
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: API-Key
description: |
Generate your API key in the [Dashboard](https://dashboard.example.com/api-keys).
Include it in all requests:
```
Authorization: Bearer sk_live_abc123def456
```
schemas:
CreateChargeRequest:
type: object
required:
- amount
- currency
- source
properties:
amount:
type: integer
description: Amount in cents ($29.99 = 2999)
minimum: 50
maximum: 99999999
example: 2999
currency:
type: string
description: Three-letter ISO currency code
pattern: '^[a-z]{3}$'
example: usd
source:
type: string
description: Payment source ID from onboarded customer
example: tok_visa
description:
type: string
maxLength: 255
description: Description of the charge (visible in dashboard)
example: "Premium Plan - Monthly"
metadata:
type: object
description: Up to 20 key-value pairs for your records
maxProperties: 20
additionalProperties:
type: string
maxLength: 500
Charge:
type: object
required:
- id
- amount
- currency
- status
- created
properties:
id:
type: string
pattern: '^ch_'
description: Unique charge identifier
example: ch_3f8a1c2b9d0e4f
amount:
type: integer
description: Amount in cents
example: 2999
currency:
type: string
description: Three-letter ISO currency code
example: usd
status:
type: string
enum:
- succeeded
- pending
- failed
- refunded
- partially_refunded
description: Current status of the charge
description:
type: string
nullable: true
example: "Premium Plan - Monthly"
created:
type: integer
description: Unix timestamp of when the charge was created
example: 1710518400
metadata:
type: object
description: Key-value pairs attached to the charge
example:
customer_id: "cus_123"
Error:
type: object
properties:
error:
type: object
properties:
type:
type: string
enum:
- card_declined
- insufficient_funds
- expired_card
- invalid_cvc
- processing_error
- rate_limit_error
- authentication_error
description: Category of error
code:
type: string
description: Machine-readable error code
message:
type: string
description: Human-readable error message
param:
type: string
nullable: true
description: Parameter that caused the error (if applicable)
responses:
BadRequest:
description: Invalid request parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Conflict:
description: Idempotency key already used for a different request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
```
### Linting and Validating OpenAPI Specs
```bash
# Install Redocly CLI
npm install -g @redocly/cli
# Lint your spec (catches common issues)
npx @redocly/cli lint openapi.yaml
# Lint with a specific ruleset
npx @redocly/cli lint openapi.yaml \
--ruleset .redocly.yaml
# Validate against OpenAPI 3.0 schema
npx @redocly/cli lint --format openapi-3.0
# Generate beautiful API reference HTML
npx @redocly/cli build-docs openapi.yaml \
--output docs/api-reference.html
# Spectral linting (alternative)
npx spectral lint openapi.yaml
```
**Sample `.redocly.yaml` configuration:**
```yaml
rules:
operation-operationId: error
operation-summary: error
operation-description: warn
operation-4xx-response: error
path-params-defined: error
no-unused-components: warn
spec: error
# Custom rules
info-contact: error
operation-tags: error
operation-parameters-unique: error
no-invalid-media-type-examples: error
# Override severity for specific rules
boolean-parameter-prefixes:
severity: warn
prefixes:
- is
- has
- should
```
---
### Authentication Documentation
Document every auth method your API supports:
#### API Key Auth
```yaml
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: |
## Obtaining an API Key
1. Log into the [Developer Dashboard](https://dashboard.example.com)
2. Navigate to **API Keys**
3. Click **Generate New Key**
4. Copy the key immediately — you won't see it again
## Key Types
| Key Type | Prefix | Permissions |
|----------|--------|-------------|
| Live | `sk_live_` | Real transactions |
| Test | `sk_test_` | Sandbox only (no charges) |
## Best Practices
- Use different keys for development, staging, and production
- Rotate keys every 90 days
- Never hardcode keys in source code
- Use environment variables or a secrets manager
```
#### OAuth 2.0
```yaml
securitySchemes:
OAuth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.example.com/oauth/authorize
tokenUrl: https://auth.example.com/oauth/token
refreshUrl: https://auth.example.com/oauth/token
scopes:
read: Read access to resources
write: Write access to resources
admin: Administrative access
clientCredentials:
tokenUrl: https://auth.example.com/oauth/token
scopes:
read: Read access to resources
write: Write access to resources
```
#### Authentication Guide Section
```markdown
## Authentication
All API requests require authentication via Bearer token in the
`Authorization` header.
### Getting Your API Key
1. Create an account at [dashboard.example.com](https://dashboard.example.com)
2. Go to **Settings > API Keys**
3. Click **Create API Key**
4. Copy the key (shown once) and store it securely
### Authenticating Requests
Include your API key in every request:
```bash
curl -X POST https://api.example.com/v2/charges \
-H "Authorization: Bearer sk_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{"amount": 2999, "currency": "usd", "source": "tok_visa"}'
```
```python
import requests
response = requests.post(
"https://api.example.com/v2/charges",
headers={"Authorization": "Bearer sk_live_abc123def456"},
json={"amount": 2999, "currency": "usd", "source": "tok_visa"}
)
```
```javascript
const response = await fetch("https://api.example.com/v2/charges", {
method: "POST",
headers: {
"Authorization": "Bearer sk_live_abc123def456",
"Content-Type": "application/json"
},
body: JSON.stringify({ amount: 2999, currency: "usd", source: "tok_visa" })
});
```
### Handling Authentication Errors
```json
// HTTP 401 - Unauthorized
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The API key provided is invalid. Generate a new key at https://dashboard.example.com/api-keys",
"doc_url": "https://docs.example.com/errors#invalid_api_key"
}
}
```
```
---
### Error Response Patterns
Standardize error responses across your API:
```yaml
components:
schemas:
ApiError:
type: object
required:
- error
properties:
error:
type: object
required:
- type
- code
- message
properties:
type:
type: string
description: High-level error category
enum:
- invalid_request_error
- authentication_error
- rate_limit_error
- api_error
- not_found
- conflict
code:
type: string
description: Machine-readable error identifier
example: "insufficient_funds"
message:
type: string
description: Human-readable description with actionable guidance
example: "The payment source has insufficient funds. Try a different payment method or contact the card issuer."
param:
type: string
nullable: true
description: The parameter that caused the error (validation errors)
example: "amount"
doc_url:
type: string
format: uri
description: Link to documentation explaining this error in detail
example: "https://docs.example.com/errors#insufficient_funds"
```
**Error response examples by status code:**
```json
// HTTP 400 - Validation Error
{
"error": {
"type": "invalid_request_error",
"code": "validation_error",
"message": "The 'amount' field must be between 50 and 99999999 cents.",
"param": "amount"
}
}
// HTTP 401 - Authentication Error
{
"error": {
"type": "authentication_error",
"code": "missing_api_key",
"message": "No API key provided. Include your API key in the Authorization header."
}
}
// HTTP 404 - Not Found
{
在 GitHub 查看