API documentation determines how quickly developers can integrate with your service. Poor documentation creates support burden, slows adoption, and frustrates users. Good documentation enables self-service, reduces integration time, and builds developer trust. The investment in documentation pays dividends through reduced support costs and increased adoption.
Documentation serves multiple audiences with different needs. New developers need getting started guides and tutorials. Experienced integrators need comprehensive reference documentation. Troubleshooters need error explanations and debugging guides. Designing for these different use cases improves documentation effectiveness.
Documentation Structure
Organize documentation into layers that serve different needs. The Divio documentation system provides a useful framework: tutorials, how-to guides, explanation, and reference.
Tutorials walk beginners through their first successful API call. They're learning-oriented and focus on doing rather than understanding. Keep tutorials simple and achievable in minutes.
# Quick Start: Your First API Call
This tutorial helps you make your first API call in under 5 minutes.
## Prerequisites
- An API key (get one at dashboard.example.com)
- cURL or any HTTP client
## Step 1: Set Up Authentication
Export your API key as an environment variable:
```bash
export API_KEY="your-api-key-here"
Step 2: Make Your First Request
Fetch your account details:
curl -H "Authorization: Bearer $API_KEY" \
https://api.example.com/v1/account
You should see a response like:
{
"id": "acct_123",
"email": "developer@example.com",
"plan": "developer"
}
Congratulations! You've made your first API call.
How-to guides solve specific problems. They're goal-oriented and assume basic familiarity. Focus on the task, not background explanation.
Reference documentation provides complete, accurate technical details. Every endpoint, parameter, and response field should be documented. Reference is meant for lookup, not reading.
Explanation (conceptual guides) provides background understanding. Authentication concepts, rate limiting philosophy, versioning strategy—these help developers make good decisions.
## OpenAPI Specification
OpenAPI (formerly Swagger) provides a standard format for API documentation. It enables automatic generation of interactive documentation, client libraries, and testing tools.
```yaml
openapi: 3.1.0
info:
title: Orders API
version: 1.0.0
description: |
The Orders API allows you to create, retrieve, and manage orders.
## Authentication
All requests require a Bearer token in the Authorization header.
servers:
- url: https://api.example.com/v1
description: Production
paths:
/orders:
post:
summary: Create an order
description: |
Creates a new order for the authenticated customer.
Orders are created in `pending` status and must be confirmed
within 30 minutes or they will be automatically cancelled.
operationId: createOrder
tags:
- Orders
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateOrderRequest'
examples:
simple:
summary: Simple order
value:
items:
- product_id: "prod_123"
quantity: 2
withShipping:
summary: Order with shipping address
value:
items:
- product_id: "prod_123"
quantity: 2
shipping_address:
line1: "123 Main St"
city: "San Francisco"
state: "CA"
postal_code: "94102"
responses:
'201':
description: Order created
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
components:
schemas:
CreateOrderRequest:
type: object
required:
- items
properties:
items:
type: array
description: Line items for the order
minItems: 1
items:
$ref: '#/components/schemas/OrderItem'
shipping_address:
$ref: '#/components/schemas/Address'
description: Required for physical products
Order:
type: object
properties:
id:
type: string
description: Unique order identifier
example: "ord_abc123"
status:
type: string
enum: [pending, confirmed, shipped, delivered, cancelled]
description: Current order status
items:
type: array
items:
$ref: '#/components/schemas/OrderItem'
total:
type: integer
description: Total in cents
example: 2499
created_at:
type: string
format: date-time
description: When the order was created
Code Examples
Code examples are the most-used part of documentation. Provide examples in multiple languages and make them copy-pasteable.
# Creating an Order
<tabs>
<tab title="cURL">
```bash
curl -X POST https://api.example.com/v1/orders \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{"product_id": "prod_123", "quantity": 2}
]
}'
$response = $client->post('orders', [ 'json' => [ 'items' => [ ['product_id' => 'prod_123', 'quantity' => 2], ], ], ]);
$order = json_decode($response->getBody(), true);
</tab>
<tab title="Python">
```python
import requests
response = requests.post(
'https://api.example.com/v1/orders',
headers={'Authorization': f'Bearer {api_key}'},
json={
'items': [
{'product_id': 'prod_123', 'quantity': 2}
]
}
)
order = response.json()
Test your code examples. Broken examples destroy trust. Automate example testing in CI to catch drift.
// Test that documentation examples work
class DocumentationExampleTest extends TestCase
{
/** @test */
public function create_order_example_works(): void
{
$response = $this->postJson('/v1/orders', [
'items' => [
['product_id' => 'prod_123', 'quantity' => 2],
],
]);
$response->assertStatus(201)
->assertJsonStructure([
'id',
'status',
'items',
'total',
'created_at',
]);
}
}
Error Documentation
Document errors thoroughly. Developers spend significant time debugging errors; good error documentation reduces this time.
# Error Handling
The API uses standard HTTP status codes and returns detailed error objects.
## Error Response Format
```json
{
"error": {
"code": "invalid_parameter",
"message": "The 'quantity' parameter must be a positive integer",
"param": "items[0].quantity",
"doc_url": "https://docs.example.com/errors/invalid_parameter"
}
}
Common Errors
400 Bad Request
| Code | Description | Resolution |
|---|---|---|
invalid_parameter |
A parameter has an invalid value | Check the param field and correct the value |
missing_parameter |
A required parameter is missing | Add the required parameter |
invalid_json |
Request body is not valid JSON | Verify JSON syntax |
401 Unauthorized
| Code | Description | Resolution |
|---|---|---|
invalid_api_key |
The API key is invalid or revoked | Generate a new API key in the dashboard |
expired_token |
The access token has expired | Refresh the token |
429 Too Many Requests
| Code | Description | Resolution |
|---|---|---|
rate_limit_exceeded |
You've exceeded the rate limit | Wait and retry with exponential backoff |
The Retry-After header indicates how long to wait before retrying.
## Interactive Documentation
Interactive documentation lets developers try endpoints without writing code. Tools like Swagger UI, Redoc, or Stoplight render OpenAPI specs into interactive interfaces.
```php
// Serve OpenAPI spec for documentation tools
Route::get('/openapi.json', function () {
return response()->file(base_path('docs/openapi.json'));
});
Route::get('/docs', function () {
return view('api-docs', [
'specUrl' => url('/openapi.json'),
]);
});
Provide a sandbox environment for safe experimentation:
# Sandbox Environment
Use the sandbox to test your integration without affecting real data.
**Sandbox URL:** `https://sandbox.api.example.com/v1/`
**Test Credentials:**
- API Key: `sk_test_sandbox123`
- Test credit card: `4242 4242 4242 4242`
The sandbox resets nightly. Don't store important data there.
Versioning Documentation
Document API versioning strategy clearly. Developers need to know how changes are communicated and how long old versions are supported.
# API Versioning
The API version is specified in the URL path (`/v1/`, `/v2/`).
## Version Lifecycle
| Version | Status | End of Life |
|---------|--------|-------------|
| v2 | Current | - |
| v1 | Deprecated | 2025-06-01 |
## Changelog
### v2.1.0 (2024-02-15)
- Added `metadata` field to orders
- `shipping_address` now accepts `country_code`
### v2.0.0 (2024-01-01)
**Breaking changes:**
- Removed `legacy_id` field from all resources
- Renamed `customer` to `customer_id`
- Changed error response format
See [migration guide](/docs/v1-to-v2) for upgrade instructions.
Maintaining Documentation
Documentation requires ongoing maintenance. Outdated documentation is worse than no documentation—it actively misleads.
Generate documentation from code where possible:
// Generate OpenAPI from route definitions
class OpenApiGenerator
{
public function generate(): array
{
$routes = Route::getRoutes();
foreach ($routes as $route) {
if ($this->isApiRoute($route)) {
$this->documentRoute($route);
}
}
return $this->spec;
}
}
Review documentation with code changes. Include documentation updates in pull request checklists.
Conclusion
API documentation is a product, not an afterthought. Structure documentation for different audiences and use cases. Use OpenAPI for standardized, tooling-friendly specs. Provide tested code examples in multiple languages. Document errors thoroughly. Make documentation interactive and provide sandboxes.
Good documentation reduces support costs, accelerates adoption, and builds developer trust. The effort invested in documentation returns value throughout the API's lifetime.