Platform API Design

Production engineering guide for platform api design covering patterns, implementation strategies, and operational best practices.

Platform API Design is the discipline of defining the public interfaces that a internal platform exposes to its consumers—typically first-party applications, downstream services, or partner integrations. It matters when the cost of changing an interface outweighs the cost of maintaining it, or when multiple teams depend on a shared set of endpoints without a centralized governance mechanism. A well-designed platform API reduces onboarding friction, limits the surface area of breaking changes, and provides a stable contract that allows consumers to evolve independently of the provider’s release cycle.

This reference page is organized around the typical goals a platform engineer or API designer encounters, rather than a taxonomic list of concepts. Each section answers “what am I trying to do?” and provides the concrete mechanics required to accomplish it.

Defining an endpoint contract

When designing a new endpoint, the primary responsibility is specifying the shape of the request and the shape of the response. The HTTP method (GET, POST, PUT, DELETE) dictates the semantics, but the platform designer must still define the path, query parameters, request body, and response payload.

A concrete example of a POST endpoint to create a resource, tested with a standard HTTP client:

curl -X POST https://platform.example.com/api/v1/resources \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"type":"compute","size":"large"}'

If the payload violates the defined schema, the server should reject the request before any state-changing work occurs. A typical validation error response might read:

{
  "error": "validation_failed",
  "message": "1 error(s) on body: type is required",
  "status": 400
}

Sharp edge: Relying on generic “200 OK” for both success and failure. Some platforms return 200 OK with an error field in the JSON body; others return 4xx/5xx. Consumers cannot rely on the HTTP status code alone to determine success without parsing the body, which introduces brittleness.

Versioning without breaking consumers

API versioning is the most common source of friction in platform design. The three principal strategies are URI versioning, header versioning, and deprecation with sunset.

URI versioning is the most explicit but increases URL surface area:

GET /api/v1/resources
GET /api/v2/resources

Header versioning keeps the URL clean but requires consumers to remember to set a header:

Accept: application/vnd.myapi.v2+json

A safer pattern for long-lived platforms is “deprecation by default.” When a new version is released, the old version is not immediately removed. Instead, it receives a Deprecation header with a date, and a Link header pointing to the replacement:

curl -I https://platform.example.com/api/resources

A sample response header might include:

Deprecation: Fri, 01 Jan 2026 00:00:00 GMT
Link: <https://platform.example.com/api/v2/resources>; rel="successor"

Sharp edge: Consumers ignoring deprecation headers. If a team automates API discovery and does not parse Deprecation or Link headers, they may continue calling a removed endpoint until the provider hard-cuts access, resulting in 404 or 410 responses with no prior warning in the application logic.

Authenticating the caller

Platform APIs commonly use one of two patterns for authentication: API keys passed as query parameters or headers, and bearer tokens (typically JWTs) passed in the Authorization header.

An API key example:

curl "https://platform.example.com/api/data?key=SK_live_abc123"

A bearer token example:

curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." https://platform.example.com/api/data

Authorization logic typically distinguishes between authentication (who is calling) and authorization (what they can access). A 401 status indicates the token or key is missing or malformed. A 403 status indicates the caller is authenticated but lacks the required scope or role.

Sharp edge: Confusing 401 and 403. In production outages, engineers often misdiagnose a 403 (permission denied) as a 401 (authentication failed), leading to unnecessary token rotation or key regeneration when the caller simply lacks the read:resources scope.

Paginating large collections

When an endpoint returns a list of items that may exceed a reasonable payload size, pagination is required. Two dominant patterns exist: offset-based pagination and cursor-based pagination.

Offset-based pagination uses limit and offset query parameters:

curl "https://platform.example.com/api/resources?limit=50&offset=100"

Cursor-based pagination uses a token returned from the previous response, typically as a next_cursor query parameter or a Link header:

curl "https://platform.example.com/api/resources?cursor=VGVzdC1jb3V0dGxlMA"

Cursor-based pagination is generally safer for mutable datasets. If a new item is inserted at the beginning of the list while a consumer is iterating via offset, the consumer may skip or double-read items. Cursor-based schemes, which typically anchor on a unique identifier or timestamp, are immune to this specific race condition.

Sharp edge: Infinite loops caused by an unbounded limit. If a client sets limit=0 or a negative value, some implementations return the entire dataset, potentially causing memory exhaustion on the client or unexpected performance characteristics on the server. Validating the limit parameter against a maximum (e.g., 100) is a common defensive measure.

Standardizing error shapes

Consumers should be able to parse errors without guessing the structure. A common pattern across well-designed platform APIs is a consistent error envelope:

{
  "error": "not_found",
  "message": "Resource with id 'R-550' does not exist",
  "status": 404,
  "request_id": "c3e8f9a2-7b6d-4f1a-a8e2-d5b9c1a3f7e0"
}

The inclusion of a request_id (or correlation_id) is critical for distributed tracing. When a platform fan-outs a request to multiple internal services, attaching the same request_id to every downstream API call allows the consumer to reconstruct the full flow in a tracing system like Jaeger or Datadog.

Sharp edge: Leaking internal details in error messages. Phrases like “Failed to connect to database host db-123.internal” reveal infrastructure topology. Error messages should be user-facing and generic, while internal logging captures the full stack trace.

Documenting for discovery

The gold standard for platform API discoverability is a machine-readable specification, typically OpenAPI (formerly Swagger). An OpenAPI document describes paths, methods, parameters, request bodies, and response schemas in YAML or JSON. Tools can generate client SDKs, server stubs, and interactive documentation from a single source of truth.

A minimal OpenAPI snippet for a GET resource list:

openapi: 3.0.1
info:
  title: Platform API
  version: v1.0.0
paths:
  /api/resources:
    get:
      summary: List resources
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: A list of resources
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Resource'

Platforms that maintain an OpenAPI spec enjoy a lower “integration tax.” New teams can generate a client library automatically rather than manually mapping query parameters and response fields.

Sharp edge: Drift between the code annotations and the published spec. If the implementation adds a field to the response JSON but the OpenAPI spec is not updated, the generated client will not deserialize the new field, leading to silent data loss or runtime errors depending on the language’s type system.

Summary of failure modes

This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.