API Documentation Best Practices: Complete Guide for 2026
๐ก Monitor your APIs โ know when they go down before your users do
Better Stack checks uptime every 30 seconds with instant Slack, email & SMS alerts. Free tier available.
Affiliate link โ we may earn a commission at no extra cost to you
Great API documentation is the difference between an API that developers love and one they abandon. According to a 2025 Postman survey, 73% of developers say documentation quality is the most important factor when evaluating whether to use an API.
This guide covers everything you need to write world-class API documentation: essential components, interactive examples, code samples in multiple languages, error handling documentation, versioning strategies, and real-world examples from industry leaders like Stripe, Twilio, and GitHub.
Why API Documentation Matters
Bad documentation costs you customers, increases support burden, and damages your API's reputation. Here's why it matters:
Developer Adoption
- First impression: Documentation is often the first thing developers see
- Evaluation criteria: 83% of developers read docs before trying an API (2025 Stack Overflow survey)
- Time-to-first-call: Good docs get developers from signup to first successful API call in under 5 minutes
Support Cost Reduction
- Reduced tickets: Stripe reduced API support tickets by 40% after documentation overhaul (2024)
- Self-service: 67% of developers prefer reading docs over contacting support (Postman, 2025)
- Faster resolution: When support IS needed, good docs help agents resolve issues 3x faster
Developer Experience & Retention
- Trust signal: Comprehensive docs signal a mature, well-maintained API
- Reduced frustration: Clear examples prevent hours of trial-and-error debugging
- Word-of-mouth: Developers recommend APIs with great docs (Twilio's docs are cited in 10K+ blog posts)
Bottom line: Investing in documentation quality pays for itself in higher conversion rates, lower churn, and reduced support costs.
Essential Documentation Components
World-class API documentation includes these 8 essential components. Each serves a specific purpose in the developer journey.
1. Getting Started Guide
Your quickest path to "hello world" โ developers should make their first successful API call within 5 minutes.
What to include:
- Prerequisites: Required accounts, API keys, development environment
- Installation: SDK installation commands for major languages
- Authentication setup: How to get API keys and where to put them
- First API call: A single, working example that demonstrates success
- Expected output: What the response looks like when it works
Example (Twilio-style):
# 1. Sign up and get your API credentials
# Account SID: ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Auth Token: your_auth_token
# 2. Install the SDK
npm install twilio
# 3. Send your first SMS
const twilio = require('twilio');
const client = twilio('ACxxxxxxxx', 'your_auth_token');
client.messages.create({
body: 'Hello from Twilio!',
from: '+15551234567',
to: '+15559876543'
})
.then(message => console.log(`Sent! Message SID: ${message.sid}`))
.catch(error => console.error(error));
Anti-pattern: Don't start with architecture diagrams or abstract concepts. Get developers to a working API call FIRST, then explain how it works.
2. Authentication
Clear, secure authentication patterns with examples for every supported method.
What to document:
- Authentication methods: API keys, OAuth 2.0, JWT โ when to use each
- Header format: Exact syntax for authentication headers
- Security best practices: Never commit keys, use environment variables, rotate regularly
- Testing auth: How to verify authentication is working
- Error responses: What 401 vs 403 means, how to fix common auth errors
Example (API Key):
// โ
Correct: API key in Authorization header
fetch('https://api.example.com/v1/users', {
headers: {
'Authorization': 'Bearer sk_live_xxxxxxxxxxxxxx',
'Content-Type': 'application/json'
}
});
// โ Wrong: API key in query parameter (security risk)
fetch('https://api.example.com/v1/users?api_key=sk_live_xxx'); // Never do this
OAuth 2.0 flow diagram:
โโโโโโโโโโโโ โโโโโโโโโโโโ
โ Client โ โ API โ
โ App โ โ Server โ
โโโโโโโโโโโโ โโโโโโโโโโโโ
โ โ
โ 1. Redirect to /oauth/authorize โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ>โ
โ โ
โ 2. User logs in & grants permissions โ
โ โ
โ 3. Redirect with authorization code โ
โ<โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ 4. POST /oauth/token with code โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ>โ
โ โ
โ 5. Return access_token & refresh_token โ
โ<โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ 6. Use access_token in API calls โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ>โ
Security best practices checklist:
- โ Store API keys in environment variables, never hardcode
- โ Use different keys for development, staging, production
- โ Rotate keys every 90 days (or when compromised)
- โ Implement key expiration and renewal flows
- โ Use HTTPS for all API calls (never HTTP)
- โ Implement rate limiting per API key
See our complete API Authentication & Security Guide for implementation details.
3. API Reference
The exhaustive list of every endpoint, parameter, and response field. This is where developers spend the most time.
What to document for each endpoint:
HTTP Method & Path:
POST /v1/payments
Description: One-sentence summary of what this endpoint does.
Request parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount |
integer | Yes | Amount in cents (e.g., 1000 = $10.00) |
currency |
string | Yes | Three-letter ISO currency code (e.g., "usd") |
customer_id |
string | No | ID of existing customer to charge |
description |
string | No | Human-readable description for your records |
metadata |
object | No | Key-value pairs for custom data (max 50 keys) |
Request example:
const response = await fetch('https://api.example.com/v1/payments', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_xxxxxxxxxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 5000,
currency: 'usd',
customer_id: 'cus_xxxxxxxxxxxxx',
description: 'Premium subscription - March 2026',
metadata: {
plan: 'premium',
billing_period: 'monthly'
}
})
});
const payment = await response.json();
console.log(payment);
Response (200 OK):
{
"id": "pay_xxxxxxxxxxxxx",
"object": "payment",
"amount": 5000,
"currency": "usd",
"status": "succeeded",
"customer_id": "cus_xxxxxxxxxxxxx",
"description": "Premium subscription - March 2026",
"created": 1709222400,
"metadata": {
"plan": "premium",
"billing_period": "monthly"
}
}
Error responses:
| Status Code | Error Code | Description | How to Fix |
|---|---|---|---|
| 400 | invalid_amount |
Amount must be positive integer | Check amount is > 0 and integer (not float) |
| 401 | invalid_api_key |
API key missing or invalid | Verify Authorization header format |
| 402 | insufficient_funds |
Customer's payment method declined | Ask customer to update payment method |
| 404 | customer_not_found |
Customer ID doesn't exist | Verify customer_id or create customer first |
| 429 | rate_limit_exceeded |
Too many requests | Implement exponential backoff, check rate limits |
Rate limits: 100 requests per second per API key (see Rate Limits section).
Pagination: Not applicable (single resource creation).
Idempotency: Pass Idempotency-Key header to safely retry requests (see Idempotency section).
4. Code Examples in Multiple Languages
Developers work in different languages โ meet them where they are. Stripe and Twilio document endpoints in 7+ languages.
Essential languages to cover:
- JavaScript/Node.js (most popular for backend APIs)
- Python (data science, ML, backend)
- Ruby (Rails developers)
- PHP (WordPress, Laravel)
- cURL (universal, works everywhere)
- Go (cloud-native, performance-critical)
- Java (enterprise)
Example (Create Payment endpoint):
if (!response.ok) {
throw new Error(API error: ${response.status});
}
const payment = await response.json(); console.log('Payment created:', payment.id);
</Tab>
<Tab label="Python">
```python
import requests
import os
response = requests.post(
'https://api.example.com/v1/payments',
headers={
'Authorization': f'Bearer {os.environ.get("API_KEY")}',
'Content-Type': 'application/json'
},
json={
'amount': 5000,
'currency': 'usd',
'customer_id': 'cus_xxxxx'
}
)
response.raise_for_status()
payment = response.json()
print(f'Payment created: {payment["id"]}')
uri = URI('https://api.example.com/v1/payments') request = Net::HTTP::Post.new(uri) request['Authorization'] = "Bearer #{ENV['API_KEY']}" request['Content-Type'] = 'application/json' request.body = { amount: 5000, currency: 'usd', customer_id: 'cus_xxxxx' }.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| http.request(request) end
payment = JSON.parse(response.body) puts "Payment created: #{payment['id']}"
</Tab>
<Tab label="cURL">
```bash
curl -X POST https://api.example.com/v1/payments \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"currency": "usd",
"customer_id": "cus_xxxxx"
}'
Pro tip: Generate code examples automatically from OpenAPI specs using tools like Redocly or Postman.
5. Error Handling Documentation
Errors are where developers get stuck. Document every error code with:
- Error code: Machine-readable identifier
- HTTP status: 400, 401, 404, etc.
- Description: What caused the error
- How to fix: Actionable steps to resolve
Example error response format:
{
"error": {
"type": "invalid_request_error",
"code": "invalid_amount",
"message": "Amount must be a positive integer",
"param": "amount",
"doc_url": "https://docs.example.com/api/errors#invalid_amount",
"request_id": "req_abc123xyz"
}
}
Error types:
invalid_request_error: Client sent invalid data (400)authentication_error: Invalid API key (401)permission_error: Valid key but insufficient permissions (403)resource_not_found: Resource doesn't exist (404)rate_limit_error: Too many requests (429)api_error: Server-side error (500)
Comprehensive error table:
| HTTP | Error Code | Cause | Fix |
|---|---|---|---|
| 400 | invalid_amount |
Amount โค 0 or not integer | Send positive integer in cents |
| 400 | invalid_currency |
Currency code invalid | Use ISO 4217 code (usd, eur, gbp) |
| 400 | missing_required_field |
Required parameter missing | Check API reference for required fields |
| 401 | invalid_api_key |
API key wrong/missing | Verify Authorization header |
| 401 | expired_api_key |
API key expired | Generate new key in dashboard |
| 403 | insufficient_permissions |
Key lacks required scope | Check key permissions in dashboard |
| 404 | customer_not_found |
Customer ID doesn't exist | Verify ID or create customer first |
| 404 | payment_not_found |
Payment ID doesn't exist | Verify payment ID |
| 409 | idempotency_key_reused |
Idempotency key used for different request | Use new key or ensure request matches original |
| 429 | rate_limit_exceeded |
Too many requests | Implement exponential backoff |
| 500 | api_error |
Server error | Retry with exponential backoff |
| 503 | service_unavailable |
API maintenance/overload | Check status page, retry later |
Error handling best practices:
async function createPayment(amount: number, customerId: string) {
try {
const response = await fetch('https://api.example.com/v1/payments', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': generateIdempotencyKey() // Prevent duplicate charges
},
body: JSON.stringify({ amount, customer_id: customerId, currency: 'usd' })
});
if (!response.ok) {
const error = await response.json();
// Handle specific errors
switch (error.error.code) {
case 'invalid_amount':
throw new ValidationError('Amount must be positive integer in cents');
case 'customer_not_found':
throw new NotFoundError(`Customer ${customerId} not found`);
case 'rate_limit_exceeded':
// Wait and retry with exponential backoff
await sleep(1000);
return createPayment(amount, customerId);
case 'insufficient_funds':
throw new PaymentError('Customer payment method declined');
default:
throw new APIError(`API error: ${error.error.message}`);
}
}
return await response.json();
} catch (error) {
// Log error with request_id for support
console.error('Payment creation failed:', {
amount,
customerId,
error: error.message,
requestId: error.request_id
});
throw error;
}
}
See our complete API Error Handling Guide for implementation patterns.
6. Rate Limits
Document rate limits clearly to prevent surprise 429 errors in production.
What to document:
- Limit values: Requests per second/minute/hour
- Scope: Per API key, per IP, per endpoint
- Headers: How to check remaining quota
- Backoff strategy: How to handle 429 responses
- Burst allowance: Whether short bursts above limit are allowed
Example:
Rate limits:
- Standard: 100 requests per second per API key
- Burst: 200 requests per second for up to 10 seconds
- Daily: 1,000,000 requests per day per API key
Rate limit headers: Every API response includes these headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1709222460
X-RateLimit-Limit: Total requests allowed per windowX-RateLimit-Remaining: Requests remaining in current windowX-RateLimit-Reset: Unix timestamp when limit resets
Handling 429 errors:
async function apiRequestWithRetry(url: string, options: RequestInit, maxRetries = 3) {
let retries = 0;
while (retries < maxRetries) {
const response = await fetch(url, options);
if (response.status === 429) {
// Get retry delay from header or use exponential backoff
const retryAfter = response.headers.get('Retry-After');
const delayMs = retryAfter
? parseInt(retryAfter) * 1000
: Math.pow(2, retries) * 1000; // 1s, 2s, 4s
console.log(`Rate limited, retrying in ${delayMs}ms...`);
await sleep(delayMs);
retries++;
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
Best practices:
- โ Implement exponential backoff with jitter
- โ Cache responses when possible to reduce API calls
- โ Batch multiple operations into single requests
- โ Monitor rate limit headers and slow down before hitting limits
- โ Don't retry immediately on 429 (makes problem worse)
See our API Rate Limiting Guide for implementation details.
7. Webhooks (Event-Driven APIs)
If your API supports webhooks, document the event payloads and security verification.
What to document:
- Available events: List of all webhook event types
- Payload structure: JSON schema for each event
- Signature verification: How to verify webhook authenticity
- Retry behavior: When/how you retry failed deliveries
- Testing: How to test webhooks during development
Example webhook event:
{
"id": "evt_xxxxxxxxxxxxx",
"type": "payment.succeeded",
"created": 1709222400,
"data": {
"object": {
"id": "pay_xxxxxxxxxxxxx",
"amount": 5000,
"currency": "usd",
"status": "succeeded",
"customer_id": "cus_xxxxxxxxxxxxx"
}
}
}
Signature verification (prevents spoofing):
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook endpoint
app.post('/webhooks', async (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook...
res.status(200).json({ received: true });
});
See our complete Webhook Implementation Guide for production patterns.
8. Changelog & Versioning
Document API changes so developers can plan upgrades and stay informed about deprecations.
What to document:
- Versioning strategy: URL-based (
/v1/), header-based, or dated versions - Changelog: Chronological list of changes with dates
- Deprecation timeline: Advance notice before removing features (minimum 6 months recommended)
- Breaking vs non-breaking changes: What requires version bump
- Migration guides: How to upgrade from v1 โ v2
Example changelog:
## v2.1.0 โ March 1, 2026
### Added
- `metadata` field on Payment objects (up to 50 key-value pairs)
- `refund_reason` parameter on Refund endpoint
### Changed
- Increased rate limit from 50 to 100 requests per second
### Deprecated
- `description` field will be removed in v3.0 (use `metadata.description` instead)
- 6-month deprecation notice (removal September 1, 2026)
### Fixed
- Fixed race condition in concurrent payment creation
- Improved error messages for invalid currency codes
## v2.0.0 โ January 15, 2026 โ ๏ธ Breaking Changes
### Breaking Changes
- **Removed** deprecated `charge` endpoint (use `payments` instead)
- **Changed** amount field from dollars (float) to cents (integer)
- Old: `{ "amount": 10.50 }`
- New: `{ "amount": 1050 }`
- **Renamed** `customer` to `customer_id` for consistency
### Migration Guide
See [v1 to v2 Migration Guide](/docs/migrations/v1-to-v2) for upgrade instructions.
Versioning best practices:
- Use semantic versioning: Major.Minor.Patch (e.g., 2.1.0)
- Breaking changes = major version bump (v1 โ v2)
- New features = minor version bump (v2.0 โ v2.1)
- Bug fixes = patch version bump (v2.1.0 โ v2.1.1)
- Maintain old versions: Keep v1 running for 12+ months after v2 launch
- Announce early: Email API users 6+ months before deprecations
Interactive Documentation Tools
Static docs are good. Interactive docs are great. These tools let developers test API calls directly in your documentation.
OpenAPI / Swagger
OpenAPI Specification (formerly Swagger) is the industry standard for API documentation. Define your API in YAML/JSON, generate interactive docs automatically.
Example OpenAPI spec (YAML):
openapi: 3.1.0
info:
title: Payment API
version: 2.1.0
description: Accept payments from customers
servers:
- url: https://api.example.com/v2
description: Production
paths:
/payments:
post:
summary: Create a payment
operationId: createPayment
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- amount
- currency
properties:
amount:
type: integer
description: Amount in cents
example: 5000
currency:
type: string
description: ISO 4217 currency code
example: usd
customer_id:
type: string
description: Existing customer ID
example: cus_xxxxxxxxxxxxx
responses:
'200':
description: Payment created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Payment'
'400':
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Payment:
type: object
properties:
id:
type: string
amount:
type: integer
currency:
type: string
status:
type: string
enum: [pending, succeeded, failed]
created:
type: integer
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
securitySchemes:
bearerAuth:
type: http
scheme: bearer
Benefits:
- Auto-generated docs: Tools like Redocly, Swagger UI, Stoplight generate beautiful docs from spec
- Interactive testing: "Try it out" buttons let developers test endpoints with their API keys
- Client SDK generation: Auto-generate client libraries for JavaScript, Python, Ruby, etc.
- Contract testing: Validate requests/responses match spec
- Linting: Catch documentation mistakes before publishing
Popular OpenAPI tools:
- Redocly โ Best-in-class interactive docs (used by Stripe)
- Swagger UI โ Open-source, most popular
- Stoplight โ Design-first API development
- ReadMe โ Hosted docs with analytics
Postman Collections
Postman is the most popular API testing tool. Publish a Postman Collection so developers can import your API and start testing immediately.
Example collection structure:
Payment API v2
โโโ Authentication
โ โโโ Get API Key
โโโ Payments
โ โโโ Create Payment
โ โโโ Retrieve Payment
โ โโโ List Payments
โ โโโ Refund Payment
โโโ Customers
โโโ Create Customer
โโโ Retrieve Customer
โโโ Update Customer
Benefits:
- One-click import: Developers import collection and test immediately
- Environment variables: Store API keys, base URLs as variables
- Pre-request scripts: Auto-generate authentication headers, timestamps
- Test scripts: Validate responses automatically
- Documentation: Generate docs from collection (though OpenAPI is better for public docs)
How to create:
- Build collection in Postman
- Publish to Postman Public API Network
- Add "Run in Postman" button to your docs
Code Playgrounds
Let developers run code examples directly in your docs without leaving the browser.
Popular tools:
- CodeSandbox โ Full development environment
- StackBlitz โ Instant dev environments
- RunKit โ Node.js notebooks (embedded in docs)
Example (RunKit embed):
<!-- Embed RunKit notebook in docs -->
<div id="runkit-example"></div>
<script src="https://embed.runkit.com"></script>
<script>
RunKit.createNotebook({
element: document.getElementById("runkit-example"),
source: `
const fetch = require('node-fetch');
const response = await fetch('https://api.example.com/v1/payments', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 5000,
currency: 'usd'
})
});
const payment = await response.json();
console.log(payment);
`
});
</script>
Benefits:
- No setup required: Developers test without installing SDKs
- Shareable: Copy link to share working example
- Interactive learning: Modify code and see results instantly
Real-World Examples: Best API Documentation
Let's analyze what makes these APIs' documentation world-class.
Stripe: The Gold Standard
Stripe's API documentation is widely considered the best in the industry. Here's why:
What makes it great:
- Interactive API explorer: Test every endpoint with your API key directly in docs
- Code examples in 10+ languages: JavaScript, Python, Ruby, PHP, Go, Java, .NET, cURL, and more
- Searchable: Cmd+K search finds anything instantly
- Comprehensive error documentation: Every error code explained with fix instructions
- Real-world guides: Payment flows, SCA compliance, mobile SDKs, webhook handling
- Versioning: Clear version selector, migration guides for breaking changes
- Developer-friendly design: Clean UI, syntax highlighting, copy buttons
Specific features to emulate:
Tabbed code examples:
โโ JavaScript โ Python โ Ruby โ PHP โ cURL โโโโโโโ
โ โ
โ const stripe = require('stripe')('sk_test_...');โ
โ โ
โ const paymentIntent = await stripe โ
โ .paymentIntents.create({ โ
โ amount: 2000, โ
โ currency: 'usd', โ
โ }); โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Right-side API explorer:
โโ Documentation โโโโโโโโโโโโโฌโ API Explorer โโโโโโโ
โ POST /v1/payment_intents โ Test this endpoint โ
โ โ โ
โ Creates a PaymentIntent... โ amount * โ
โ โ [2000 ] โ
โ Parameters: โ โ
โ โข amount (required) โ currency * โ
โ โข currency (required) โ [usd ] โ
โ โข customer (optional) โ โ
โ โ [Make Request] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ
Inline error examples:
For each endpoint, Stripe shows:
- Happy path (200 OK response)
- Common errors (400, 401, 404 with explanations)
- How to fix (actionable steps)
Why it works: Developers can find what they need, test it, and debug errors โ all without leaving the docs.
Twilio: Tutorial-Driven
Twilio's docs excel at getting developers from zero to working code fast.
What makes it great:
- Quickstarts: 5-minute "Send your first SMS" tutorials
- Language-specific SDKs: First-class support for 7+ languages
- Video tutorials: Short screencasts showing how to build real features
- Code snippets library: 1000+ copy-paste examples for common tasks
- Live phone number testing: Test SMS/voice without buying a number
- Troubleshooting guides: "Why isn't my SMS delivering?" flowcharts
Specific features to emulate:
Quickstart structure:
- Prerequisites: Node.js installed, Twilio account
- Install SDK:
npm install twilio - Get credentials: Screenshot showing where to find Account SID
- Copy-paste code: Working example with TODO comments for customization
- Run it:
node send-sms.jsโ Success message - What's next: Links to related tutorials
Troubleshooting decision tree:
SMS not delivering?
โโ Is the phone number E.164 format? (+15551234567)
โ โโ No โ Fix format
โ โโ Yes โ Continue
โโ Is the number on your approved list? (trial accounts)
โ โโ No โ Add to approved list
โ โโ Yes โ Continue
โโ Check Message Status in Console
โ โโ "Undelivered" โ Carrier rejected (see error code)
โ โโ "Sent" โ Delivered successfully
Why it works: Developers get dopamine hit of working code in 5 minutes, then dig deeper.
GitHub: Developer-Friendly Reference
GitHub's REST API docs balance completeness with readability.
What makes it great:
- GraphQL alternative: Offers GraphQL API for complex queries (with GraphQL explorer)
- Comprehensive examples: Every endpoint has cURL and JavaScript examples
- Rate limit visibility: Headers showing remaining quota
- Webhook events catalog: All 50+ webhook event types documented
- API versioning: Date-based versions (2026-03-01) with migration guides
- OAuth scopes: Clear table showing which endpoints need which scopes
Specific features to emulate:
Scope requirements table:
| Endpoint | Required Scope | Description |
|---|---|---|
GET /user |
read:user |
Read user profile |
PATCH /user |
user |
Update user profile |
GET /user/repos |
repo |
List user repositories |
POST /user/repos |
public_repo or repo |
Create repository |
Date-based versioning:
X-GitHub-Api-Version: 2026-03-01
Why it works: Developers building GitHub integrations need exhaustive reference โ GitHub delivers without overwhelming.
Common Documentation Mistakes
Avoid these pitfalls that frustrate developers and increase support burden.
1. Assuming Prior Knowledge
Bad:
"Use OAuth 2.0 authorization code flow with PKCE."
Good:
"Authentication uses OAuth 2.0. Here's how it works:
1. Redirect users to our login page
2. We redirect back with an authorization code
3. Exchange code for access token
4. Use access token in API calls
[View detailed OAuth guide โ]
Quick start (code example):
[Copy-paste working OAuth implementation]
Why: Most developers haven't memorized OAuth 2.0 spec. Show them the code first, explain theory later.
2. Missing Error Examples
Bad:
## Create Payment
POST /v1/payments
Returns a Payment object if successful.
Good:
## Create Payment
POST /v1/payments
### Success Response (200 OK)
{ "id": "pay_xxx", "status": "succeeded", ... }
### Error Responses
**400 Bad Request** โ Invalid amount
{ "error": { "code": "invalid_amount", "message": "Amount must be positive integer" } }
โ Fix: Send amount in cents (1000 = $10.00)
**401 Unauthorized** โ Invalid API key
{ "error": { "code": "invalid_api_key", "message": "API key is invalid" } }
โ Fix: Check Authorization header format
**429 Too Many Requests** โ Rate limit exceeded
{ "error": { "code": "rate_limit_exceeded", "message": "100 requests per second exceeded" } }
โ Fix: Implement exponential backoff, check X-RateLimit-* headers
Why: Developers spend more time debugging errors than reading happy-path docs. Help them fix problems fast.
3. Outdated Examples
Bad:
// Using deprecated 'request' library (unmaintained since 2020)
const request = require('request');
request.post('https://api.example.com/v1/payments', ...);
Good:
// Using modern fetch API (native in Node 18+)
const response = await fetch('https://api.example.com/v1/payments', {
method: 'POST',
headers: { ... },
body: JSON.stringify({ ... })
});
Why: Outdated examples suggest unmaintained API. Update examples when ecosystems change.
4. No Authentication Examples
Bad:
"Include your API key in the Authorization header."
Good:
// โ
Correct: Bearer token in Authorization header
fetch('https://api.example.com/v1/payments', {
headers: {
'Authorization': `Bearer ${process.env.API_KEY}`,
'Content-Type': 'application/json'
}
});
// โ Wrong: API key in query parameter (security risk)
fetch('https://api.example.com/v1/payments?api_key=sk_live_xxx');
// โ Wrong: API key in request body
fetch('https://api.example.com/v1/payments', {
body: JSON.stringify({ api_key: 'sk_live_xxx', ... })
});
Why: Authentication is where most developers get stuck. Show exact syntax.
5. Missing Testing Instructions
Bad:
"Create a payment with the /v1/payments endpoint."
Good:
"Test payment creation in development:
1. Use test API key (starts with sk_test_)
2. Use test card number: 4242 4242 4242 4242
3. Use any future expiry date (e.g., 12/34)
4. Use any 3-digit CVC (e.g., 123)
Expected result: Payment status = 'succeeded'
Test failure scenarios:
โข Card declined: Use 4000 0000 0000 0002
โข Insufficient funds: Use 4000 0000 0000 9995
โข Expired card: Use any past expiry date
See all [test card numbers โ]
Why: Developers need to test unhappy paths too. Provide test data for every scenario.
6. No Migration Guides
Bad:
"Version 1.0 is deprecated. Use version 2.0."
Good:
# Migrating from v1 to v2
## Breaking Changes
### 1. Amount Format Changed
**v1 (dollars as float):**
{ "amount": 10.50 }
**v2 (cents as integer):**
{ "amount": 1050 }
**Migration code:**
// Convert existing amounts
const amountInCents = Math.round(amountInDollars * 100);
### 2. Customer Field Renamed
**v1:**
{ "customer": "cus_xxx" }
**v2:**
{ "customer_id": "cus_xxx" }
**Migration code:**
// Simple rename
const payload = {
customer_id: customer // was 'customer' in v1
};
## Timeline
- March 1, 2026: v2 released
- September 1, 2026: v1 deprecated (still works, shows warnings)
- March 1, 2027: v1 removed
## Support
Questions? Email api-migrations@example.com
Why: Breaking changes without migration paths = angry developers.
7. Ignoring Mobile/SDK Users
Bad:
"Use cURL to call our API."
Good:
## Platform-Specific SDKs
### iOS (Swift)
pod 'ExampleSDK'
let payment = ExampleSDK.shared.createPayment(
amount: 5000,
currency: "usd"
)
### Android (Kotlin)
implementation 'com.example:sdk:2.1.0'
val payment = ExampleSDK.createPayment(
amount = 5000,
currency = "usd"
)
### React Native
npm install @example/react-native-sdk
import { createPayment } from '@example/react-native-sdk';
const payment = await createPayment({ amount: 5000, currency: 'usd' });
Why: Mobile developers expect native SDKs. REST docs alone aren't enough.
Documentation Checklist
Use this checklist to audit your API documentation quality.
Essential Components
- Getting Started: 5-minute quickstart with working code
- Authentication: Clear examples for every auth method
- API Reference: Complete endpoint list with parameters
- Error Handling: Every error code documented with fixes
- Rate Limits: Limits, headers, backoff strategies
- Webhooks: Event types, payloads, signature verification (if applicable)
- Changelog: Version history with migration guides
- Search: Full-text search across all docs
Code Examples
- Multiple languages: JavaScript, Python, Ruby, cURL minimum
- Copy-paste ready: No placeholders, runnable examples
- Modern syntax: Updated for 2026 (async/await, etc.)
- Environment variables: Never hardcode API keys
- Error handling: Show how to handle failures
Interactive Features
- API explorer: Test endpoints directly in docs
- Postman collection: One-click import
- OpenAPI spec: Published and up-to-date
- Code playgrounds: RunKit, CodeSandbox, or similar
Developer Experience
- Fast loading: Docs load in <2 seconds
- Mobile-friendly: Readable on phones/tablets
- Dark mode: Option for dark theme
- Syntax highlighting: Color-coded examples
- Copy buttons: One-click copy for code blocks
Testing & Support
- Test credentials: Sandbox API keys, test data
- Troubleshooting guides: Common problems + fixes
- Support channels: Email, Slack, Discord, forum
- Status page: API uptime monitoring (e.g., API Status Check monitors Stripe, Twilio, GitHub, 160+ APIs)
Versioning & Changes
- Version selector: Switch between API versions
- Deprecation notices: 6+ month warning for removals
- Migration guides: Step-by-step upgrade instructions
- Breaking change log: Clearly marked in changelog
Documentation Maintenance
Great documentation requires ongoing maintenance. Set up these processes:
Regular Reviews
- Monthly: Check for broken links, outdated examples
- Quarterly: Audit code examples for deprecated packages
- Per release: Update docs before deploying API changes
- Annually: Review entire docs with fresh eyes
User Feedback
- Thumbs up/down: "Was this helpful?" on every page
- Comments: Allow developers to suggest improvements
- Support tickets: Track which docs generate most questions
- Analytics: Measure page views, search queries, time on page
Automated Testing
- Link checker: Catch broken internal/external links
- Code example tests: Run examples in CI to verify they work
- OpenAPI validation: Lint spec for errors
- Screenshot updates: Re-capture UI screenshots when design changes
Team Ownership
- Docs owner: Assign dedicated technical writer or DevRel engineer
- Engineering review: Require docs for every API change PR
- Support collaboration: Support team flags confusing docs
- Community contributions: Accept docs PRs from users
Advanced Documentation Strategies
Once you've nailed the basics, consider these advanced strategies:
Personalized Examples
Show code examples with user's actual API key (when logged in):
// Auto-fill user's API key
fetch('https://api.example.com/v1/payments', {
headers: {
'Authorization': 'Bearer sk_live_4mVX...xY2z', // โ User's actual key
'Content-Type': 'application/json'
}
});
Benefits:
- No "replace YOUR_API_KEY" confusion
- Developers can copy-paste and run immediately
- Higher success rate for first API call
How to implement: Detect logged-in users, inject their test API key into examples client-side.
Generated Client Libraries
Auto-generate SDKs from OpenAPI spec for every language:
# Use OpenAPI Generator
openapi-generator generate \
-i openapi.yaml \
-g javascript \
-o ./client-libraries/javascript
openapi-generator generate \
-i openapi.yaml \
-g python \
-o ./client-libraries/python
Benefits:
- Consistent API across languages
- Updates deploy automatically when API changes
- Type safety (TypeScript, Go, Java)
Tools:
- OpenAPI Generator
- Swagger Codegen
- Kiota (Microsoft)
Video Tutorials
Short screencasts showing common workflows:
- 3-minute quickstart: "Create your first payment in 3 minutes"
- 10-minute deep dive: "Building a complete checkout flow"
- 5-minute debugging: "Troubleshooting payment failures"
Best practices:
- Keep under 10 minutes
- Show real code in real IDE
- Include mistakes + how to fix them (builds trust)
- Add captions (accessibility + searchability)
API Playground
Interactive environment where developers can test your API without writing code:
โโ API Playground โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Endpoint: POST /v1/payments โ
โ โ
โ Parameters: โ
โ amount [5000 ] * โ
โ currency [usd ] * โ
โ customer_id [cus_123abc ] โ
โ โ
โ [Send Request] โ
โ โ
โ Response (200 OK): โ
โ { โ
โ "id": "pay_xyz789", โ
โ "status": "succeeded", โ
โ "amount": 5000, โ
โ "currency": "usd" โ
โ } โ
โ โ
โ [Copy as cURL] [Copy as JavaScript] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Tools:
- Postman
- Insomnia
- Hoppscotch (open-source)
- Bruno (offline-first)
Community Cookbook
Curated collection of real-world examples contributed by users:
- "Send SMS reminder 24 hours before appointment (Node.js)"
- "Process refund when Stripe webhook fires (Python)"
- "Batch create 1000 customers from CSV (Ruby)"
- "Retry failed payments with exponential backoff (Go)"
Benefits:
- Shows API in real contexts (not toy examples)
- Community feels ownership
- Covers edge cases your docs don't
- SEO goldmine (long-tail keywords)
How to implement:
- GitHub repository for examples
- Tag by language, use case, difficulty
- Community can submit PRs
- Feature best submissions in docs
Monitoring API Status
Even with perfect documentation, APIs have outages. Give developers visibility into your API health:
- Public status page: Real-time uptime for all endpoints
- Historical uptime: 30-day / 90-day availability percentages
- Incident history: Postmortems for major outages
- Monitoring APIs you depend on: Track Stripe, Twilio, GitHub, AWS, Auth0, and 160+ other APIs with API Status Check
Developers trust APIs that are transparent about downtime. Hiding outages damages credibility.
Conclusion
Great API documentation is a competitive advantage. It's the difference between developers choosing your API or your competitor's.
Key takeaways:
- Get developers to first successful API call in <5 minutes
- Document every error code with how-to-fix instructions
- Provide code examples in 5+ languages
- Make docs interactive (API explorer, Postman collections)
- Keep docs updated (monthly reviews, automated tests)
- Learn from the best (Stripe, Twilio, GitHub)
Next steps:
- Audit your docs with the checklist
- Set up OpenAPI spec + auto-generated docs
- Add "Try it out" functionality
- Create getting-started tutorial
- Monitor API dependencies with API Status Check
Related guides:
- API Error Handling Guide
- API Rate Limiting Implementation
- Webhook Implementation Guide
- API Authentication & Security
Track uptime for Stripe, Twilio, GitHub, AWS, Auth0, and 160+ APIs with API Status Check.
๐ Tools We Use & Recommend
Tested across our own infrastructure monitoring 200+ APIs daily
Uptime Monitoring & Incident Management
Used by 100,000+ websites
Monitors your APIs every 30 seconds. Instant alerts via Slack, email, SMS, and phone calls when something goes down.
โWe use Better Stack to monitor every API on this site. It caught 23 outages last month before users reported them.โ
Secrets Management & Developer Security
Trusted by 150,000+ businesses
Manage API keys, database passwords, and service tokens with CLI integration and automatic rotation.
โAfter covering dozens of outages caused by leaked credentials, we recommend every team use a secrets manager.โ
SEO & Site Performance Monitoring
Used by 10M+ marketers
Track your site health, uptime, search rankings, and competitor movements from one dashboard.
โWe use SEMrush to track how our API status pages rank and catch site health issues early.โ
API Status Check
Stop checking API status pages manually
Get instant email alerts when OpenAI, Stripe, AWS, and 100+ APIs go down. Know before your users do.
14-day free trial ยท $0 due today ยท $9/mo after ยท Cancel anytime
Browse Free Dashboard โ