Skip to content

FRD: Write and Ratify ADR-061 API Design

FieldValue
IDFRD-041
OwnerDavid Holmes
StatusDraft
Last Updated2026-05-26
RelatedADR-027 (Default Tech Stack)
Target Releasev2.1.0
TypeInfra
ComplexityM

Document Summary

This FRD covers authoring, reviewing, and ratifying ADR-061, which will codify the platform’s API design standards: request/response shape conventions, versioning strategy, error envelope format, pagination patterns, and idempotency key requirements. The ADR formalizes patterns already partially expressed in src/lib/api-types.ts and the api-shared-contract.mdx guide, making them enforceable and discoverable.


Introduction

Overview

The platform has ad-hoc API conventions scattered across code (src/lib/api-types.ts), a shared-contract guide (docs/devops/guides/api-shared-contract.mdx), and tribal knowledge. No single ADR governs API design decisions. This creates ambiguity when building new endpoints: developers must reverse-engineer conventions from existing code. ADR-061 will be the authoritative reference for all API design questions.

Goals

  • Define the canonical request and response shapes for all platform APIs.
  • Specify the versioning strategy (URL path vs. header, breaking-change policy).
  • Codify the error envelope schema (matching apiErrorSchema in api-types.ts).
  • Standardize pagination (cursor-based and offset-based, matching paginationSchema).
  • Require idempotency keys for all mutating endpoints.
  • Link the ADR to src/lib/api-types.ts as the TypeScript source of truth for these shapes.

Non-Goals

  • Implementing new API endpoints (ADR is governance, not implementation).
  • Defining authentication or authorization patterns (covered by ADR-025).
  • Specifying API integration/client patterns (covered by ADR-062).

Scope

In Scope

ItemDescription
ADR-061 MDX documentFull ADR following the project’s ADR template with frontmatter tags.
Request shape conventionsStandard envelope for request bodies, query parameter naming.
Response shape conventionsSuccess envelope ({ data } for single, { data, pagination } for lists), error envelope (ApiError).
Versioning strategyURL path prefix (/v1/), header-based negotiation for minor versions.
Error envelopeCodifies apiErrorSchema from api-types.ts: code, message, details, request_id.
PaginationCursor-based (primary) and offset-based (fallback), matching paginationSchema.
Idempotency keysIdempotency-Key header required on POST/PUT/PATCH, with server-side deduplication semantics.
ADR routing updateRegenerate docs/adrs/docs-index.json and Storybook Docs/ADRs/Overview.

Out of Scope

ItemReason
Client-side API integration patternsCovered by ADR-062.
Rate limiting designInfra concern, not API shape.
Authentication headersCovered by ADR-025.
GraphQL or gRPC conventionsPlatform uses REST; other protocols are not currently in scope.

Users and Pain Points

UserPain Point
Backend developerNo authoritative reference for how to structure a new endpoint’s request/response. Must copy patterns from existing code.
Frontend developerInconsistent error shapes across endpoints force per-endpoint error handling rather than a shared error boundary.
API reviewerNo ADR to cite when requesting changes during code review; conventions are implicit.
Platform maintainerVersioning strategy is undocumented, making breaking-change decisions ad hoc.

Definitions

TermDefinition
Error envelopeThe standard JSON shape returned for all 4xx and 5xx responses, defined by apiErrorSchema.
Idempotency keyA client-generated unique identifier sent via the Idempotency-Key header to ensure that retried mutating requests produce the same result.
Cursor-based paginationPagination using an opaque next_cursor token rather than page numbers. Preferred for large or frequently changing datasets.
ADRArchitecture Decision Record. An immutable document capturing a design decision, its context, and consequences.

Current State

src/lib/api-types.ts defines Zod schemas for ApiError, Pagination, and paginatedResponseSchema. The docs/devops/guides/api-shared-contract.mdx guide describes the shared contract informally. However:

  • No ADR exists to make these conventions enforceable.
  • The versioning strategy is not documented anywhere.
  • Idempotency key requirements are not specified.
  • Query parameter naming conventions (snake_case vs. camelCase) are inconsistent across endpoints.
  • Error code values are not enumerated or governed.

Proposed Solution

Author docs/adr-061-api-design.mdx with the following sections:

  1. Context — The platform exposes REST APIs consumed by the design-system frontend. Consistent shapes reduce integration friction and enable shared error handling.
  2. Decision — All APIs follow the conventions below.
  3. Request conventions — JSON request bodies use camelCase keys. Query parameters use snake_case. Array parameters use bracket notation (ids[]=1&ids[]=2).
  4. Response conventions — Single-resource responses: { data: T }. List responses: { data: T[], pagination: Pagination }. Error responses: { error: ApiError }.
  5. Versioning — Major version in URL path (/api/v1/). Minor/patch changes are backward-compatible and do not require a new path. Deprecation communicated via Sunset header.
  6. Error envelope — Matches apiErrorSchema: { code: string, message: string, details?: Record<string, unknown>, request_id: string }. Error codes follow a dot-separated namespace (e.g., validation.required_field, auth.invalid_token).
  7. Pagination — Cursor-based by default (next_cursor in response, cursor query param). Offset-based fallback (page and page_size query params) for simple use cases. Both shapes match paginationSchema.
  8. Idempotency — All POST, PUT, and PATCH requests must accept an Idempotency-Key header. The server stores the response for a key and returns it on retry within a 24-hour window.
  9. Consequences — All existing endpoints must be audited for compliance. New endpoints must pass review against this ADR.

The ADR frontmatter will include:

tags: [api, api-design]
applies_when: "Building or reviewing any REST API endpoint"
status: ratified

Requirements

IDPriorityRequirement
API61-01P0ADR-061 MDX file created with full ADR template and frontmatter.
API61-02P0Request and response shape conventions documented with examples.
API61-03P0Error envelope specification matches apiErrorSchema from api-types.ts.
API61-04P0Pagination conventions documented for both cursor-based and offset-based.
API61-05P0Versioning strategy documented (URL path prefix, Sunset header for deprecation).
API61-06P0Idempotency key requirements documented.
API61-07P1ADR index updated with ADR-061 entry.
API61-08P1Cross-reference from api-types.ts TSDoc to ADR-061.

Functional Requirements

  1. The ADR must include at least one request and one response example in TypeScript for each convention (single resource, list, error).
  2. The ADR must specify the exact Content-Type header expected (application/json).
  3. The ADR must list the canonical HTTP status codes for success (200, 201, 204) and error (400, 401, 403, 404, 409, 422, 429, 500).
  4. The ADR must define the format of error code strings (dot-separated namespace, lowercase).
  5. The ADR must specify that request_id is generated server-side and included in both success and error responses.

Non-Functional Requirements

CategoryRequirement
DiscoverabilityADR frontmatter tags include api and api-design so routing table lookups work.
ConsistencyAll conventions must align with existing api-types.ts schemas. Conflicts require updating the code, not the ADR.
EnforceabilityConventions must be specific enough to serve as a code-review checklist.

API/Interface Requirements

The ADR itself defines API interface requirements. No code API changes are introduced by this FRD; the ADR codifies existing patterns.


Accessibility Requirements

Not applicable. This is a governance document, not a UI component.


Content and Documentation Requirements

  • ADR-061 written as docs/adr-061-api-design.mdx following the project ADR template.
  • docs/adrs/docs-index.json and Storybook Docs/ADRs/Overview updated with ADR-061.
  • CLAUDE.md routing table already maps api tag to ADR-061; verify after creation.
  • TSDoc @remarks in api-types.ts updated to reference ADR-061.

Dependencies

DependencyTypeNotes
src/lib/api-types.tsInternalExisting schemas that the ADR codifies. Must stay in sync.
docs/devops/guides/api-shared-contract.mdxInternalExisting informal guide; ADR-061 supersedes it for normative decisions.
ADR-025GovernanceAuth-related API conventions are deferred to ADR-025.
ADR-062 (pending)GovernanceClient-side integration patterns will reference ADR-061 shapes.

Risks and Tradeoffs

RiskLikelihoodImpactMitigation
Existing endpoints do not conform to the ADR.HighMediumADR includes a “compliance timeline” section giving existing endpoints two release cycles to conform.
Idempotency key requirement adds server-side complexity.MediumMediumADR specifies a simple key-value store pattern (Redis or database) with 24-hour TTL. Libraries exist for this.
Cursor-based pagination is harder to implement than offset.MediumLowADR allows offset-based fallback for simple cases. Cursor-based is required only for datasets exceeding 1,000 items.

Open Questions

  1. Should the ADR mandate a specific request_id format (e.g., UUIDv7) or leave it implementation-defined?
  2. Should error details be strongly typed per error code, or remain Record<string, unknown>?
  3. Should the Sunset header include a link to a migration guide, or just the deprecation date?

Acceptance Criteria

  • docs/adr-061-api-design.mdx exists with full ADR template, frontmatter tags [api, api-design], and applies_when field.
  • Request, response, error, pagination, versioning, and idempotency conventions are documented with TypeScript examples.
  • Error envelope specification matches apiErrorSchema exactly.
  • docs/adrs/docs-index.json and Storybook Docs/ADRs/Overview include ADR-061.
  • src/lib/api-types.ts TSDoc references ADR-061.
  • pnpm build-storybook passes (MDX renders without errors).

LLM Handoff Instructions

When implementing this FRD:

  1. Use the project’s ADR template. Check an existing ratified ADR (e.g., docs/adr-025-identity-auth-and-secrets.mdx) for the expected structure and frontmatter format.
  2. Create docs/adr-061-api-design.mdx with frontmatter: tags: [api, api-design], applies_when: "Building or reviewing any REST API endpoint", status: ratified.
  3. Reference the Zod schemas in src/lib/api-types.ts directly. The ADR must not contradict those schemas.
  4. Include TypeScript code examples for: a single-resource response, a paginated list response, an error response, and an idempotency key header.
  5. Run pnpm run docs:index and pnpm run adrs so ADR-061 appears in machine-readable routing and the Storybook overview.
  6. Add @remarks Governed by ADR-061. to the TSDoc for apiErrorSchema, paginationSchema, and paginatedResponseSchema in api-types.ts.
  7. Run pnpm build-storybook to confirm the MDX renders.

Decision Log

DateDecisionRationale
2026-05-26URL path versioning over header versioning.Simpler for clients, easier to route at the gateway level, widely adopted convention.
2026-05-26Cursor-based pagination as primary, offset as fallback.Cursor-based avoids skip-scan performance issues on large datasets. Offset remains available for simpler use cases.
2026-05-2624-hour idempotency key TTL.Balances storage cost against retry windows for long-running operations.

Document History

VersionDateAuthorChanges
0.12026-05-26David HolmesInitial draft.