Use this skill for contract-first API design across REST, GraphQL, gRPC, tRPC, AsyncAPI, and agent-facing interfaces. It owns contract choice, auth boundaries, versioning, errors, pagination, rate limits, idempotency, and validation; it does not replace backend implementation or security review.
Style Decision Table
| API style | Choose when | Avoid when | Canonical artifact |
|---|---|---|---|
| REST + OpenAPI | Public APIs, broad tooling compatibility, cacheable resources | Streaming-first service contracts | OpenAPI 3.x |
| GraphQL | Complex client-driven query shapes, multi-team schema ownership | Simple CRUD, caching is critical, single-team | GraphQL SDL |
| gRPC | Internal services, bidirectional streaming, type-critical boundaries | Public internet consumers, browser-native clients | protobuf |
| tRPC | TypeScript monorepos with shared server+client | Non-TS stacks, public third-party consumers | TypeScript types |
| AsyncAPI + webhooks | Event-driven contracts, pub/sub, push notifications | Synchronous request-reply | AsyncAPI 3.x |
| MCP tool layer | Agent or LLM is the primary consumer | Human-only clients | MCP tool schema |
Quick Reference
| API style | Load |
|---|---|
| REST + OpenAPI | references/restful-design-patterns.md, references/openapi-guide.md |
| GraphQL | references/graphql-patterns.md |
| gRPC | references/grpc-patterns.md |
| tRPC | references/trpc-patterns.md |
| AsyncAPI and webhooks | references/asyncapi-patterns.md, references/webhook-patterns.md |
| Core cross-cutting | references/error-handling-patterns.md, references/authentication-patterns.md, references/pagination-filtering.md, references/rate-limiting-patterns.md, references/api-testing-patterns.md |
Contract Review Checklist
Run on every API contract before handoff:
- Canonical spec artifact exists (OpenAPI, AsyncAPI, protobuf, GraphQL SDL, or MCP schema)
- Compatibility and versioning model named: evolutionary changes, URL path (
/v1/), header, or content-type negotiation - Deprecation timeline written into the spec or linked doc;
Deprecationheader uses the RFC 9745@<unix-seconds>form,Sunsetuses RFC 8594 - Error model: for REST/HTTP, use RFC 9457 Problem Details with stable
typeURI and an applicationcodeextension when clients need one; for GraphQL, gRPC, and events, define errors in their native contract - Auth boundary: which endpoints require which scopes; token type (JWT, opaque); revocation path
- Pagination: cursor-based for high-cardinality; offset only for small, stable sets
- Rate limits: either the IETF httpapi
RateLimit/RateLimit-Policyfields or a documented legacyX-RateLimit-*triad; 429 includesRetry-After. The IETF fields have changed shape between drafts: look up the current revision and RFC status on the IETF datatracker and copy the syntax from that revision, and name the revision in the spec - Idempotency: POST/PATCH operations document idempotency key or mark non-idempotent explicitly; whatever the IETF
Idempotency-Keyheader's status (check datatracker), the spec must define key scope, retention, and the reused-key response - Long-running jobs: 202 +
Locationpoll URL;stateenum with terminal states named - Webhooks: HMAC signature; replay protection;
trace_idon payload - Breaking-change detection: oasdiff or equivalent configured in CI
- Contract tests: Schemathesis (property-based) or Pact (consumer-driven) wired up
Workflow
- Choose the API style using the decision table above.
- Define the canonical contract artifact.
- Run the contract review checklist.
- Add contract validation, breaking-change detection, and documentation.
- Hand off spec, examples, and rollout notes.
Compatibility evidence by change class
Classify each change before calling the contract compatible:
| Change class | Required evidence |
|---|---|
| shape change | schema diff plus generated-client compile or consumer contract test |
| semantic change with stable shape | before/after examples and a named behavioral assertion |
| default, ordering, quota, or timeout change | production-like consumer test and rollout note |
| removal or narrowing | usage evidence, deprecation window, and rollback or compatibility shim |
For provider/consumer deployments, derive the safe order from message direction, changed payload side, and actual consumer tolerance. For a new optional request capability, ship provider support before consumers send it. For response enum/event expansion, or whenever a consumer may reject unknown fields or variants, ship and verify tolerant consumers before the provider emits the new value. For removals, ship consumers first, confirm old-field traffic is gone, then remove the provider behavior. Prove the relevant consumer behavior rather than inferring safety from schema additivity; a green schema diff alone is insufficient evidence for semantic compatibility or deploy order.
Route Elsewhere
- Backend implementation: software-backend
- AppSec review and auth hardening: software-security-appsec
- System-wide architecture: software-architecture-design
- Rollout and migration sequencing: dev-workflow-planning
Defaults
- Define the contract before implementation or code generation.
- Use RFC 9457 Problem Details for REST/HTTP errors that need a response body; define native error shapes for other API styles.
- Make versioning, deprecation, idempotency, pagination, and rate limits explicit in the spec.
- Prefer OpenAPI 3.x or AsyncAPI as the canonical source for HTTP or event-driven interfaces; pin the newest minor that every validator, linter, and generator in your pipeline supports.
- Treat agent APIs as domain contracts with clear side effects, not thin wrappers around random endpoints.
- Use MCP as the tool-exposure layer when an agent is the primary consumer. Its authorization model builds on OAuth resource-server standards (RFC 9728 Protected Resource Metadata, RFC 8707 Resource Indicators), but session, handshake, and auth requirements change between spec revisions: look up the current revision at modelcontextprotocol.io before designing around sessions or the
initializehandshake. See references/llm-agent-api-contracts.md.
Versioning Strategy Table
| Approach | When to use | Breaking-change gate |
|---|---|---|
URL path versioning (/v2/) |
Public APIs, broad client install base | oasdiff --fail-on ERR in CI |
Header versioning (API-Version: 2) |
Internal APIs, frequent iteration | oasdiff on each PR |
| Content-type negotiation | Hypermedia or media-type-driven APIs | Manual review + tests |
| Evolutionary (GraphQL, gRPC) | Teams own schema, introspection tools run | GraphQL Inspector / protobuf compatibility |
Expert Judgment
Versioning strategy — pick based on who controls the client, not team preference.
- If you do not control every client (public API, third-party integrators, mobile apps you cannot force-update), publish a version policy and a support window based on observed consumer use and migration lead time; you cannot silently migrate callers.
- If you control every client (internal service mesh, monorepo with generated clients), prefer evolutionary compatibility (additive fields, deprecate-then-remove) over versioning — a new version number is a coordination tax you don't need to pay.
- Dated versions can be useful when each account or request pins behavior independently. If requests omit a version, resolve to a documented pinned default rather than silently upgrading callers, and echo the resolved version in a response header.
- Never let "evolutionary" become an excuse to skip a compatibility gate — GraphQL and gRPC still need CI-enforced schema diffing (GraphQL Inspector,
buf breaking); "no versioning" is not "no discipline."
Rule: rules/api/contracts.md loads this invariant when Claude edits a matching file.
Breaking-change detection instincts — what schema-diff tools structurally cannot catch:
The instances below are all applications of Hyrum's Law: with enough consumers of an API, every observable behavior — not just the documented schema — becomes a de facto contract, whether or not you ever promised it. (Same law, applied to schema deploy-sequencing rather than API surface, in software-database-design/references/migration-strategies.md.) That is why a clean schema diff is not proof of compatibility:
- Semantic changes with no shape change: tightening an existing enum's allowed values, narrowing a previously-permissive validation rule, or changing what a field means while keeping its type —
oasdiff/buf breakingwill report zero diff. - Behavioral defaults: changing a default sort order, default page size, or default timeout is a breaking change for callers who rely on the default, even though the schema is untouched.
- Cross-field coupling: a field that used to be optional-but-ignored becoming optional-but-enforced (e.g., a previously-cosmetic
regionfield now affecting routing). - Rate-limit and quota tightening: not a contract break in the schema sense, but it breaks production traffic identically to a removed field — treat quota changes with the same deprecation-notice discipline as field removal.
- Error-code reclassification: moving a case from
404to410, or from a genericcodeto a more specific one, breaks clients that pattern-match on the old code even though the Problem Details shape is unchanged. - Treat automated diffing (oasdiff, GraphQL Inspector,
buf breaking, Pact) as a floor, not a ceiling — pair it with a changelog review by someone who understands what callers actually depend on.
Hyrum's Law framing adapted from addyosmani/agent-skills (MIT), commit 7676817, 2026-08-09.
When GraphQL, gRPC, or event-driven contracts are the wrong choice:
- GraphQL is wrong for simple CRUD with one client shape, for teams that need HTTP-cache semantics (the GraphQL-over-HTTP spec requires POST support and makes GET optional, so many servers accept only POST; HTTP caching then needs GET plus persisted queries), and for single-team ownership where the query-flexibility payoff is never realized — you inherit N+1 risk, query-complexity DoS surface, and federation tooling cost for no client benefit.
- Native gRPC is a poor default for browser clients, which need gRPC-Web or a compatible transport layer. For public third-party integrators, account for protobuf tooling and transport support; choose REST+OpenAPI when broad HTTP interoperability and discoverability matter more.
- AsyncAPI/event contracts are wrong when the caller needs an immediate, correlated answer to a specific request — forcing request/response workflows through pub/sub adds correlation-ID bookkeeping and timeout ambiguity that plain synchronous HTTP avoids.
- The tell that a style choice was fashion, not fit: nobody on the team can name the specific latency budget, client platform constraint, or multi-team ownership problem the chosen style solves.
Known Traps
- Picking GraphQL, gRPC, or AsyncAPI for architectural fashion instead of actual client, latency, or interoperability constraints.
- Designing happy-path resources without an explicit idempotency and retry story for duplicated or partial-failure requests.
- Letting auth stay implicit until implementation, producing inconsistent enforcement across endpoints.
- Reusing pagination models that leak internal storage semantics into the public contract.
- Treating webhook or event delivery as reliable push without signature validation, replay protection, or consumer backpressure.
- Generating a spec from code after implementation and calling it contract-first.
- Wrapping arbitrary internal endpoints as agent APIs without stable side-effect, auth, and validation rules.
Navigation
Core patterns:
- references/restful-design-patterns.md — HTTP method semantics, URL structure, idempotency
- references/pagination-filtering.md — cursor vs offset, filtering contracts
- references/error-handling-patterns.md — RFC 9457, error taxonomy
- references/authentication-patterns.md — OAuth 2.1, JWT, API keys, mTLS
- references/rate-limiting-patterns.md — headers, 429 handling, burst strategies
Style-specific:
- references/api-design-best-practices.md — cross-style DX and governance
- references/versioning-strategies.md — breaking change detection, deprecation
- references/api-security-checklist.md — OWASP API Top 10 checklist
- references/graphql-patterns.md — schema design, federation, when to adopt a supergraph
- references/grpc-patterns.md — protobuf design, streaming, deadlines
- references/trpc-patterns.md — TypeScript end-to-end type sharing
- references/openapi-guide.md — OpenAPI 3.x authoring, linting, bundling
- references/openapi-32-arazzo-101.md — what OpenAPI 3.2 added over 3.1 (streaming types, QUERY method, OAuth flows) and Arazzo multi-step workflow chains; load when specifying multi-call API sequences or adopting 3.2 features
- references/asyncapi-patterns.md — event-driven contracts, pub/sub
- references/webhook-patterns.md — HMAC signing, replay protection, delivery guarantees
- references/real-time-api-patterns.md — SSE, WebSocket, long-polling tradeoffs
- references/api-testing-patterns.md — contract tests, property-based testing, Schemathesis
- references/llm-agent-api-contracts.md — MCP integration, AX design, agent-first patterns, LLM-consumer rules (summary-stat endpoints, language-first search, payload pruning as accuracy control)
Assets and templates:
- assets/openapi-template.yaml
- assets/spectral-ruleset.yaml — custom Spectral lint ruleset for OpenAPI
- assets/oasdiff-ci.yml — CI workflow for oasdiff breaking-change detection
- Full-stack framework scaffolds (FastAPI, Express, Django REST, Spring Boot) are implementation, not contract design — moved to
software-backend:assets/python/template-python-fastapi-sqlalchemy.md,assets/nodejs-express/template-nodejs-express.md,assets/python-django/template-python-django-rest.md,assets/java/template-java-spring-boot.md - assets/cross-platform/api-patterns-universal.md
- assets/cross-platform/template-api-governance.md
- assets/cross-platform/template-api-design-review-checklist.md
- assets/cross-platform/template-api-error-model.md
- data/sources.json
Related skills:
- software-backend, software-security-appsec, data-sql-optimization, qa-testing-strategy, qa-observability, docs-codebase, docs-ai-prd, dev-workflow-planning, software-architecture-design
Learnings Loop
When prior decisions or pitfalls are relevant, consult learnings.consolidated.md if present; use learnings.md only for needed history or as the available fallback. Otherwise skip both.
After applying it, if you encountered a pattern worth remembering, a mistake worth preventing, or a domain fact that surprised you, append one dated bullet to learnings.md via agents-skills-feedback-loop/scripts/append_learning.py. Do not modify SKILL.md itself.