API Documentation Best Practices

If you've ever stared at a wall of text trying to figure out how to make your first API call, you know exactly why documentation matters. Good API docs can make or break developer adoption. Great docs turn a curious developer into a loyal user in under 30 minutes. This

TRY NANO BANANA FOR FREE

API Documentation Best Practices

TRY NANO BANANA FOR FREE
Contents

If you've ever stared at a wall of text trying to figure out how to make your first API call, you know exactly why documentation matters. Good API docs can make or break developer adoption. Great docs turn a curious developer into a loyal user in under 30 minutes.

This guide walks through what actually makes API documentation work — not just look good — with practical examples using the PetStore API as a reference.


Why API Documentation Is a Product, Not an Afterthought

Most teams treat documentation as something you write after the API is done. That's backwards. Docs are part of the developer experience, and developer experience is part of your product.

The PetStore API is a classic example used across the OpenAPI ecosystem. It's simple enough to understand quickly, but rich enough to demonstrate real patterns. Let's use it to explore what great documentation looks like in practice.


1. Start with a Clear Overview

The first thing a developer sees should answer three questions immediately:

  • What does this API do?
  • Who is it for?
  • How do I get started in 5 minutes?

Here's what a solid overview section looks like for a PetStore-style API:

## PetStore API

The PetStore API lets you manage a pet store's inventory, handle customer orders,
and manage user accounts. It follows REST conventions and returns JSON responses.

Base URL: https://petstore3.swagger.io/api/v3
Authentication: OAuth2 / API Key
Rate Limit: 1000 requests/hour

Short. Scannable. Answers the basics before the developer has to dig.


2. Use OpenAPI/Swagger for Machine-Readable Specs

OpenAPI (formerly Swagger) is the industry standard for describing REST APIs. A well-written OpenAPI spec does double duty: it's both human-readable documentation and a machine-readable contract that tools can use to generate client SDKs, mock servers, and test suites.

Here's a minimal but complete OpenAPI 3.0 definition for the PetStore's GET /pet/{petId} endpoint:

openapi: 3.0.3
info:
  title: PetStore API
  version: 1.0.0
  description: A sample API for managing a pet store

paths:
  /pet/{petId}:
    get:
      summary: Find pet by ID
      description: Returns a single pet by its numeric ID.
      operationId: getPetById
      parameters:
        - name: petId
          in: path
          required: true
          description: ID of the pet to retrieve
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        '404':
          description: Pet not found
        '400':
          description: Invalid ID supplied

components:
  schemas:
    Pet:
      type: object
      required:
        - name
        - photoUrls
      properties:
        id:
          type: integer
          format: int64
          example: 10
        name:
          type: string
          example: "doggie"
        status:
          type: string
          enum: [available, pending, sold]

A few things worth noting here:

  • operationId gives each endpoint a stable identifier — useful for SDK generation
  • example values in schemas show up directly in generated docs
  • $ref keeps schemas DRY and reusable across endpoints
  • Response codes are documented explicitly, not just the happy path

The more complete your OpenAPI spec, the more your tooling can do for you automatically.


3. Code Examples in Multiple Languages

Developers work in different languages. If your docs only show curl, you're making everyone else do translation work in their head. The best API docs include examples in at least 3-4 languages.

Here's the same PetStore request — fetching a pet by ID — in four languages:

curl

curl -X GET "https://petstore3.swagger.io/api/v3/pet/10" \
  -H "Accept: application/json" \
  -H "api_key: your-api-key"

Python (requests)

import requests

url = "https://petstore3.swagger.io/api/v3/pet/10"
headers = {
    "Accept": "application/json",
    "api_key": "your-api-key"
}

response = requests.get(url, headers=headers)

if response.status_code == 200:
    pet = response.json()
    print(f"Found pet: {pet['name']}")
elif response.status_code == 404:
    print("Pet not found")
else:
    print(f"Error: {response.status_code}")

JavaScript (fetch)

const petId = 10;

const response = await fetch(`https://petstore3.swagger.io/api/v3/pet/${petId}`, {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'api_key': 'your-api-key'
  }
});

if (response.ok) {
  const pet = await response.json();
  console.log(`Found pet: ${pet.name}`);
} else if (response.status === 404) {
  console.log('Pet not found');
}

Go

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
)

type Pet struct {
    ID     int64  `json:"id"`
    Name   string `json:"name"`
    Status string `json:"status"`
}

func getPet(petID int64, apiKey string) (*Pet, error) {
    url := fmt.Sprintf("https://petstore3.swagger.io/api/v3/pet/%d", petID)

    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        return nil, err
    }

    req.Header.Set("Accept", "application/json")
    req.Header.Set("api_key", apiKey)

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    if resp.StatusCode == http.StatusNotFound {
        return nil, fmt.Errorf("pet not found")
    }

    var pet Pet
    if err := json.NewDecoder(resp.Body).Decode(&pet); err != nil {
        return nil, err
    }

    return &pet, nil
}

Notice that each example handles errors — not just the success case. That's important. Developers copy-paste from docs, and if your examples don't handle errors, neither will their first implementation.


4. Interactive Documentation

Static docs are fine. Interactive docs are better. Tools like Swagger UI, Redoc, and Stoplight let developers make real API calls directly from the documentation page.

The PetStore API's official demo at https://petstore3.swagger.io is a good example of Swagger UI in action. Developers can:

  • Browse all endpoints in a structured list
  • Expand any endpoint to see parameters, request body schema, and response schemas
  • Click "Try it out" to fill in parameters and execute real requests
  • See the actual response, including headers and status codes

To set up Swagger UI for your own API, you just need your OpenAPI spec and a few lines of HTML:

<!DOCTYPE html>
<html>
<head>
  <title>PetStore API Docs</title>
  <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css" />
</head>
<body>
  <div id="swagger-ui"></div>
  <script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
  <script>
    SwaggerUIBundle({
      url: "/openapi.yaml",
      dom_id: '#swagger-ui',
      presets: [SwaggerUIBundle.presets.apis],
      layout: "BaseLayout"
    });
  </script>
</body>
</html>

For a more polished look, Redoc is worth considering — it renders the same OpenAPI spec with a cleaner three-panel layout that's easier to navigate for large APIs.


5. Authentication Documentation

Authentication is where most developers get stuck first. Document it clearly, with examples.

The PetStore API supports both API key and OAuth2. Here's how to document both:

## Authentication

### API Key

Pass your API key in the `api_key` header:

api_key: your-api-key-here

### OAuth2

The PetStore API uses OAuth2 with the following scopes:

| Scope         | Description                    |
|---------------|--------------------------------|
| `write:pets`  | Add and modify pets            |
| `read:pets`   | Read pet data                  |

**Getting a token:**

```bash
curl -X POST "https://petstore3.swagger.io/oauth/token" \
  -d "grant_type=client_credentials" \
  -d "client_id=your-client-id" \
  -d "client_secret=your-client-secret"
Always include a note about token expiry and how to refresh. Developers will hit auth errors eventually — make it easy to diagnose.

---

## 6. Error Documentation

Document your errors as thoroughly as your success responses. For each error code, explain:

- What caused it
- How to fix it
- What the response body looks like

```markdown
## Error Reference

### 400 Bad Request

The request was malformed. Check that all required parameters are present
and correctly formatted.

**Example response:**
```json
{
  "code": 400,
  "type": "error",
  "message": "Invalid ID supplied"
}

404 Not Found

The requested resource doesn't exist. For /pet/{petId}, this means no pet with that ID exists in the store.

405 Method Not Allowed

You used an HTTP method that isn't supported for this endpoint. Check the API reference for the correct method.

---

## 7. Versioning and Changelog Documentation

APIs change. How you communicate those changes matters a lot for developer trust.

**Version your API in the URL:**

https://petstore3.swagger.io/api/v3/pet

This makes it obvious which version a developer is using and allows you to maintain multiple versions simultaneously during transitions.

**Keep a changelog:**

```markdown
## Changelog

### v3.0.0 (2024-01-15)
- BREAKING: `photoUrls` field is now required when creating a pet
- Added `tags` array to Pet schema
- Deprecated `status` field in favor of `availability` (removal in v4)

### v2.1.0 (2023-09-01)
- Added bulk pet creation endpoint: POST /pet/bulk
- Improved error messages for invalid pet IDs

### v2.0.0 (2023-03-10)
- BREAKING: Authentication now requires OAuth2 (API key still supported)
- New endpoint: GET /store/inventory/summary

Mark breaking changes clearly. Developers need to know what will break their integration before they upgrade.


8. Getting Started Guide

Beyond the reference docs, include a narrative getting-started guide that walks through a complete workflow. For the PetStore API, that might look like:

  1. Get your API key
  2. Add a pet to the store
  3. Update the pet's status
  4. Place an order for the pet
  5. Check the order status

This gives developers a mental model of how the pieces fit together before they dive into the reference.


Common Documentation Mistakes to Avoid

  • Documenting only happy paths — always show error responses
  • Stale examples — code examples that don't match the current API break trust fast
  • Missing authentication details — this is the #1 place developers get stuck
  • No search — large API docs without search are painful to navigate
  • Inconsistent terminology — pick one word for each concept and stick to it

Tools Worth Knowing

  • Swagger UI / Redoc — render OpenAPI specs as interactive docs
  • Stoplight — full API design and documentation platform
  • Postman — API testing with built-in documentation features
  • ReadMe — developer hub platform with analytics on doc usage
  • Docusaurus — static site generator that works well for API docs

Wrapping Up

Great API documentation isn't about writing more — it's about writing the right things in the right order. Start with a clear overview, use OpenAPI to define your contract, show code examples in multiple languages, document your errors as carefully as your successes, and keep your changelog up to date.

The PetStore API has been a reference implementation for the OpenAPI ecosystem for years precisely because it demonstrates these patterns clearly. Use it as a benchmark when evaluating your own docs.

The best test: hand your docs to a developer who's never seen your API and watch them try to make their first call. Where they get stuck is where your docs need work.