What This Template Is For
API documentation is the first thing developers evaluate when deciding whether to integrate with your product. If the docs are incomplete, poorly organized, or out of date, developers leave and pick a competitor with better documentation. The cost is invisible because you never see the signups that did not happen.
This template provides a structured format for documenting REST APIs. It covers authentication, endpoint descriptions, request and response schemas, error codes, rate limits, pagination, and versioning. The structure works for internal APIs consumed by your own frontend teams and for public APIs consumed by third-party developers. If you are building a developer platform, pair this with a getting started guide to walk developers through their first successful API call. For broader documentation strategy, see the Knowledge Base Template and the Technical PM Handbook for guidance on managing technical products.
The goal is a reference that developers can scan in under 60 seconds to find the endpoint they need, understand the request format, and handle errors correctly.
When to Use This Template
- Launching a new API. Document endpoints before the first external developer sees them.
- Onboarding internal teams. Frontend developers and mobile teams need the same clarity as external consumers.
- Preparing for a developer program. Public APIs require polished docs on day one. You do not get a second chance to make a first impression with developers.
- Migrating or versioning an API. Breaking changes need clear migration guides. This template includes a versioning section for that purpose.
- Auditing existing docs. If your current API docs are scattered across wikis, READMEs, and Slack threads, use this template to consolidate them into a single source of truth.
How to Use This Template
- Copy the blank template into your documentation platform (GitBook, ReadMe, Notion, or a docs-as-code repo).
- Start with the authentication section. Every developer needs this before they can call a single endpoint.
- Document each endpoint group. Use one section per resource (users, projects, invoices).
- Include real request and response examples. Developers copy and paste from docs. Make it easy.
- Define your error code table. Consistent error responses reduce support tickets by 30-40%.
- Document rate limits upfront. Developers build retry logic based on what you tell them here.
- Review with an engineer who did not build the API. If they can follow the docs, external developers can too.
The Template
API Overview
- Base URL:
https://api.yourproduct.com/v1 - Protocol: HTTPS only
- Format: JSON (request and response bodies)
- Character Encoding: UTF-8
- API Version: v1
Authentication
- ☐ Document the authentication method (API key, OAuth 2.0, JWT, or bearer token)
- ☐ Explain where to find or generate credentials
- ☐ Show the header format for authenticated requests
- ☐ List the available scopes or permissions (if using OAuth)
- ☐ Note token expiration and refresh procedures
Authentication Header Format:
Authorization: Bearer YOUR_API_KEY
| Auth Method | Use Case | Token Lifetime |
|---|---|---|
| API Key | Server-to-server integrations | No expiration (revocable) |
| OAuth 2.0 | User-context requests | Access token: 1 hour, Refresh token: 30 days |
| JWT | Session-based authentication | Configurable (default: 24 hours) |
Endpoints
For each endpoint, document the following:
[Resource Name] (e.g., Users, Projects, Invoices)
[METHOD] /resource
| Field | Value |
|---|---|
| Description | [What this endpoint does] |
| Authentication | [Required / Optional / None] |
| Rate Limit | [Requests per minute] |
Request Headers:
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer token |
Content-Type | Yes (POST/PUT) | application/json |
X-Request-Id | No | Idempotency key for retries |
Request Parameters:
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
| [param] | [string/integer/boolean] | [Yes/No] | [What it controls] | [Default value] |
Request Body (POST/PUT):
{
"field_name": "value",
"nested_object": {
"sub_field": "value"
}
}
Response (200 OK):
{
"id": "abc123",
"field_name": "value",
"created_at": "2026-03-05T12:00:00Z",
"updated_at": "2026-03-05T12:00:00Z"
}
Error Responses:
| Status | Code | Message | Resolution |
|---|---|---|---|
| 400 | invalid_request | [Description] | [How to fix] |
| 401 | unauthorized | [Description] | [How to fix] |
| 404 | not_found | [Description] | [How to fix] |
| 429 | rate_limited | [Description] | [How to fix] |
Error Codes
- ☐ Define a consistent error response format across all endpoints
- ☐ Include a machine-readable error code and a human-readable message
- ☐ Document every possible error code with resolution steps
Standard Error Response Format:
{
"error": {
"code": "invalid_request",
"message": "The 'email' field is required.",
"status": 400,
"request_id": "req_abc123"
}
}
| Status Code | Category | Description |
|---|---|---|
| 400 | Client Error | Malformed request. Check required fields and data types. |
| 401 | Authentication | Missing or invalid credentials. |
| 403 | Authorization | Valid credentials but insufficient permissions. |
| 404 | Not Found | Resource does not exist or was deleted. |
| 409 | Conflict | Resource already exists (e.g., duplicate email). |
| 422 | Validation | Request is well-formed but contains invalid values. |
| 429 | Rate Limited | Too many requests. Retry after the period in the Retry-After header. |
| 500 | Server Error | Unexpected server failure. Contact support with the request_id. |
Rate Limits
- ☐ Document the rate limit per authentication level (free, standard, enterprise)
- ☐ Explain the response headers that communicate limit status
- ☐ Describe the retry strategy developers should implement
| Plan | Requests per Minute | Burst Limit | Daily Limit |
|---|---|---|---|
| Free | 60 | 10 | 10,000 |
| Standard | 300 | 50 | 100,000 |
| Enterprise | 1,000 | 200 | Unlimited |
Rate Limit Response Headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Retry-After | Seconds to wait before retrying (only on 429) |
Pagination
- ☐ Choose a pagination strategy (offset, cursor, or keyset)
- ☐ Document the pagination parameters and response metadata
- ☐ Explain default and maximum page sizes
| Parameter | Type | Default | Maximum | Description |
|---|---|---|---|---|
page | integer | 1 | - | Page number (offset-based) |
per_page | integer | 25 | 100 | Items per page |
cursor | string | - | - | Cursor for next page (cursor-based) |
Pagination Response Metadata:
{
"data": [...],
"meta": {
"total": 342,
"page": 1,
"per_page": 25,
"total_pages": 14,
"next_cursor": "eyJpZCI6MTAwfQ=="
}
}
Versioning
- ☐ Document the current API version and how it is specified
- ☐ Explain the deprecation policy and timeline for old versions
- ☐ Describe what constitutes a breaking change
| Version | Status | Sunset Date |
|---|---|---|
| v1 | Current | - |
| v0 (legacy) | Deprecated | 2026-06-30 |
Versioning method: URL path (/v1/resource). The API version is part of the base URL. When a new major version is released, the previous version remains available for at least 12 months.
Filled Example: TaskManager API v1
API Overview
- Base URL:
https://api.taskmanager.io/v1 - Protocol: HTTPS only
- Format: JSON
- Authentication: Bearer token (API key)
Authentication
All requests require an API key passed in the Authorization header:
Authorization: Bearer tm_live_abc123def456
API keys are generated in Settings > Developer > API Keys. Each key is scoped to a workspace. Never share keys in client-side code. Use environment variables on the server.
GET /tasks
Retrieve a paginated list of tasks for the authenticated workspace.
Parameters:
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
status | string | No | Filter by status: open, in_progress, done | All |
assignee_id | string | No | Filter by assignee user ID | All |
per_page | integer | No | Items per page (max 100) | 25 |
cursor | string | No | Pagination cursor from previous response | - |
Response (200 OK):
{
"data": [
{
"id": "task_001",
"title": "Implement OAuth 2.0 login",
"status": "in_progress",
"assignee": {
"id": "user_042",
"name": "Sarah Chen"
},
"priority": "high",
"created_at": "2026-03-01T09:00:00Z",
"updated_at": "2026-03-04T14:30:00Z"
}
],
"meta": {
"total": 187,
"per_page": 25,
"next_cursor": "eyJpZCI6InRhc2tfMDI2In0="
}
}
POST /tasks
Create a new task.
Request Body:
{
"title": "Add bulk export to CSV",
"description": "Users need to export task lists to CSV for reporting.",
"status": "open",
"priority": "medium",
"assignee_id": "user_042",
"due_date": "2026-03-15"
}
Response (201 Created):
{
"id": "task_188",
"title": "Add bulk export to CSV",
"status": "open",
"priority": "medium",
"created_at": "2026-03-05T10:00:00Z"
}
Error (422 Validation):
{
"error": {
"code": "validation_error",
"message": "The 'title' field is required and must be between 1 and 255 characters.",
"status": 422,
"request_id": "req_789xyz"
}
}
This example follows the same patterns described in the Technical PM Handbook, where API design decisions are treated as product decisions. The error response format aligns with the documentation standards that most developer-facing products adopt.
Key Takeaways
- Start with authentication. Developers cannot call anything until they understand how to authenticate.
- Show real request and response examples for every endpoint. Developers copy and paste from docs. If your examples are wrong or missing, integration takes 3x longer.
- Define a consistent error format. Machine-readable error codes reduce debugging time and support tickets.
- Document rate limits before developers hit them. Surprises cause frustration and poorly built retry logic.
- Use a versioning strategy from day one. Retrofitting versioning onto an unversioned API is painful for everyone.
- Review docs with an engineer who did not build the API. Fresh eyes catch assumptions that insiders overlook.
About This Template
Created by: Tim Adair
Last Updated: 3/5/2026
Version: 1.0.0
License: Free for personal and commercial use
