A useful API documentation example should let a developer make a request, understand the response, handle expected failures, and know what is safe to retry. A page that lists endpoint names but omits authentication, constraints, errors, or examples is only an inventory.
This article documents a fictional Reports API endpoint from start to finish. The API creates a documentation report for a connected repository. The format is representative; adapt the fields and guarantees to your own contract.
API documentation example overview
POST https://api.example.com/v1/reports
The endpoint creates an asynchronous report job and returns 202 Accepted. A client then retrieves the report resource until it reaches completed or failed.
What this endpoint guarantees:
- requests use bearer-token authentication;
- the caller must be allowed to read the repository;
Idempotency-Keyprevents an accidental duplicate for the same logical request;- a successful create response contains a stable report ID and status URL;
- the API keeps the last completed report separate from a newly queued attempt.
Authentication
Send the API token in the Authorization header:
Authorization: Bearer YOUR_API_TOKEN
Keep tokens on the server. Do not include them in client-side JavaScript, screenshots, example repositories, or support messages. The token for this example needs the reports:write scope and access to the requested repository.
A real API reference should state how to obtain, rotate, scope, and revoke credentials. Stripe’s authentication reference is a strong public example because it explains key types, test and live modes, transport requirements, and safe handling near the first request.
Create a report
Request
POST /v1/reports HTTP/1.1
Host: api.example.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Idempotency-Key: 5960d3d8-34b8-4f85-a3ef-d703ed87e4bd
{
"repository_id": "repo_01J8R4Z7N5A4FQ9K2V6C3M1T0P",
"format": "markdown",
"include_diagrams": true
}
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer token with reports:write and repository access |
Content-Type | Yes | Must be application/json |
Idempotency-Key | Recommended | Unique value for one logical create request; reuse it only when retrying that request |
X-Request-Id | No | Caller-generated correlation ID returned in the response |
JSON body
| Field | Type | Required | Rules |
|---|---|---|---|
repository_id | string | Yes | ID of a connected repository visible to the caller |
format | string | Yes | markdown or html |
include_diagrams | boolean | No | Defaults to false |
The field table does not replace an example. It tells the reader the allowed values, while the request shows how headers and fields fit together.
Successful response
HTTP/1.1 202 Accepted
Content-Type: application/json
Location: /v1/reports/rpt_01J8R55NAZ8JW2MB9D7T6Q4C3X
Retry-After: 3
X-Request-Id: req_01J8R55P0M51CV4KYB7N2H8DXF
{
"id": "rpt_01J8R55NAZ8JW2MB9D7T6Q4C3X",
"repository_id": "repo_01J8R4Z7N5A4FQ9K2V6C3M1T0P",
"format": "markdown",
"include_diagrams": true,
"status": "queued",
"created_at": "2026-09-07T08:30:00Z",
"status_url": "/v1/reports/rpt_01J8R55NAZ8JW2MB9D7T6Q4C3X"
}
The Location header and status_url show where to poll. Retry-After gives the client an initial delay rather than forcing it to guess.
Retrieve the report status
Request
GET /v1/reports/rpt_01J8R55NAZ8JW2MB9D7T6Q4C3X HTTP/1.1
Host: api.example.com
Authorization: Bearer YOUR_API_TOKEN
Completed response
{
"id": "rpt_01J8R55NAZ8JW2MB9D7T6Q4C3X",
"status": "completed",
"created_at": "2026-09-07T08:30:00Z",
"completed_at": "2026-09-07T08:31:42Z",
"download_url": "https://downloads.example.com/reports/rpt_01J8R55N...?expires=..."
}
The reference must say how long download_url remains valid and whether a client can request a replacement. Those details cannot be inferred from the JSON type.
Failed response
{
"id": "rpt_01J8R55NAZ8JW2MB9D7T6Q4C3X",
"status": "failed",
"created_at": "2026-09-07T08:30:00Z",
"failed_at": "2026-09-07T08:30:12Z",
"error": {
"code": "repository_unreachable",
"message": "The repository provider could not be reached.",
"retryable": true
}
}
The machine-readable code supports program logic. The message supports a human. The explicit retryable flag avoids forcing every client to maintain its own error classification.
Error responses
Use one stable error envelope across endpoints:
{
"error": {
"code": "invalid_request",
"message": "The request contains invalid fields.",
"details": [
{
"field": "format",
"reason": "must be one of: markdown, html"
}
],
"request_id": "req_01J8R5CW7F4TVA2N1Y6K9M3P0Q"
}
}
| Status | Code | Meaning | Client action |
|---|---|---|---|
400 | invalid_request | JSON or field validation failed | Correct the request; do not retry unchanged |
401 | unauthenticated | Token is missing, invalid, or expired | Obtain a valid token |
403 | repository_forbidden | Caller lacks repository access | Request permission; changing the report body will not help |
404 | repository_not_found | Repository ID is unknown or hidden from the caller | Confirm the ID without exposing other tenants |
409 | report_already_running | Another active report conflicts with this request | Retrieve the existing report or wait |
429 | rate_limited | Caller exceeded its limit | Wait for Retry-After, then retry |
503 | provider_unavailable | A required upstream provider is unavailable | Retry with backoff and the same idempotency key |
Do not describe every 4xx as “bad request.” Authentication, authorization, absence, conflict, and rate limits require different responses from a client.
Stripe’s error documentation is useful to study because it distinguishes error types and discusses indeterminate results after connection failures. A good API documentation example explains what the consumer should do, not only what the server reports.
Idempotency and safe retries
Creating a report changes server state. If a client times out after sending the request, it may not know whether the job was created. Retrying without an idempotency rule can create duplicates.
For this example:
- the client creates one
Idempotency-Keyfor one logical operation; - retries use the same key and the same request body;
- the server returns the original response when it recognizes the key;
- reusing the key with a different body returns
409 idempotency_conflict; - keys expire after 24 hours.
These are example guarantees, not universal HTTP behavior. Document the actual storage window and conflict rules your API implements.
Pagination example
A collection endpoint needs more than page=2 in a code sample. State ordering, cursor meaning, limits, and behavior when records change between requests.
GET /v1/reports?limit=20&after=rpt_01J8R55N HTTP/1.1
Authorization: Bearer YOUR_API_TOKEN
{
"data": [
{
"id": "rpt_01J8R68K",
"status": "completed"
}
],
"next_cursor": "rpt_01J8R68K",
"has_more": true
}
This example orders reports by creation time, newest first. limit accepts 1 through 100 and defaults to 20. The client passes next_cursor as after without inspecting its contents. Stripe’s pagination reference is a clear real-world API documentation example of cursor parameters, mutual exclusions, and list response behavior.
OpenAPI version of the create endpoint
The OpenAPI Specification defines a language-agnostic description for HTTP APIs. A shortened description for this endpoint looks like this:
openapi: 3.1.2
info:
title: Reports API
version: 1.0.0
paths:
/v1/reports:
post:
operationId: createReport
summary: Create a documentation report
security:
- bearerAuth: []
parameters:
- in: header
name: Idempotency-Key
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [repository_id, format]
properties:
repository_id:
type: string
format:
type: string
enum: [markdown, html]
include_diagrams:
type: boolean
default: false
responses:
"202":
description: Report accepted for asynchronous processing
"400":
description: Invalid request
"401":
description: Missing or invalid authentication
"403":
description: Repository access denied
"409":
description: Conflicting report or idempotency key
"429":
description: Rate limit exceeded
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
The complete specification should define reusable request, response, and error schemas rather than leaving them as prose. Generate a rendered reference from the machine-readable contract, then add the explanations, workflow examples, and operational guarantees that a schema cannot express clearly.
What strong API documentation includes
Use this checklist on every endpoint page:
- purpose and authorization boundary;
- method, base URL, and path;
- authentication and required scopes;
- headers, parameters, and request body constraints;
- one copyable request with safe placeholder credentials;
- success responses with realistic values;
- error codes and the action a client should take;
- idempotency and retry rules for state-changing operations;
- pagination and ordering for collections;
- rate-limit headers and backoff behavior;
- versioning, deprecation, and changelog links;
- an owner and a review trigger tied to contract changes.
From one endpoint to complete API documentation
An endpoint reference is one part of the documentation set. Add a five-minute quickstart, authentication guide, error model, webhook guide, SDK examples, and changelog around the reference. GitHub’s REST API getting-started guide shows how method, path, headers, parameters, requests, and responses can be introduced before the exhaustive endpoint catalog.
DocuWriter can generate API documentation as part of complete, structured documentation for a connected codebase, alongside architecture, modules, services, classes, functions, dependencies, diagrams, and READMEs. Teams can manage the result in Spaces and use Autopilot to help keep it aligned with repository changes. Review generated API docs against the implemented routes, validation, authorization, response resources, and real failure behavior before publishing them.
Use this API documentation example as a review standard: a consumer should be able to make the request, interpret every documented result, and retry safely without reading the server source code.