API Contract

Standards Jan 9, 2026 YAML
contract api-design specification interface agreement

Definition

An API contract is a formal, machine-readable specification that precisely defines how an API works. It describes every endpoint, what inputs each accepts (request schemas), what outputs each returns (response schemas), authentication requirements, error codes, rate limits, and behavioral guarantees. Think of it as a legal contract between API provider and consumer - it specifies exactly what both parties can expect from the interaction.

Unlike informal documentation that might describe an API in prose, a contract is unambiguous and enforceable. Tools can validate that implementations actually match the contract, that client code correctly uses the API, and that changes to either side maintain backward compatibility. Contracts enable parallel development - backend teams implement the contract while frontend teams code against it simultaneously, using mock servers that follow the contract.

In practice, API contracts are typically written as OpenAPI specifications, GraphQL schemas, Protocol Buffers, or similar formats. The contract becomes the single source of truth - documentation is generated from it, SDKs are generated from it, tests validate against it, and API gateways enforce it.

Example

Microservices Communication: A payment service and order service need to communicate. Before writing code, teams define a contract: POST /payments accepts orderId (UUID), amount (number), currency (3-letter code), returns paymentId and status. Both teams code to this contract. Integration tests validate actual API calls match the contract.

Third-Party API Integration: Stripe publishes their API contract as an OpenAPI spec. When you integrate Stripe payments, you download their contract, generate a type-safe SDK from it, and your IDE autocompletes method calls with correct parameters. If Stripe changes their contract (breaking change), your SDK generation fails, alerting you immediately.

Mobile App Development: A team building iOS and Android apps needs a backend API. Backend defines the contract first: GET /users/{id} returns User object with specific fields. Mobile teams immediately start building UI using the contract to generate mock data, without waiting for backend implementation.

SLA Enforcement: A contract specifies that GET /products must respond within 200ms at 99th percentile, handle 10,000 requests/second, and maintain 99.9% uptime. Monitoring tools validate the live API against these contract terms, triggering alerts when SLA violations occur.

Breaking Change Detection: A team wants to rename “userId” to “id” in API responses. Contract testing tools compare the proposed change against the existing contract and flag it as a breaking change - existing clients expect userId. The team either keeps userId for backward compatibility or versions the API properly.

Analogy

The Building Blueprint: Before constructing a building, architects create detailed blueprints specifying every room’s dimensions, door placements, electrical outlets, plumbing connections. Contractors from different trades (electrical, plumbing, framing) work simultaneously using the blueprint as the contract. Inspectors verify work matches the blueprint. An API contract is the same - it’s the blueprint that multiple teams follow to ensure everything connects correctly.

The Restaurant Menu: A menu is a contract between restaurant and customer. It specifies what dishes are available (endpoints), what’s in each dish (request/response schemas), prices (rate limits), and preparation time (SLAs). Customers order based on the menu contract. If the kitchen changes a recipe significantly without updating the menu, customers who ordered based on the old contract will be surprised.

The Rental Agreement: When renting an apartment, you sign a contract specifying rent amount, due date, maintenance responsibilities, termination conditions. Both landlord and tenant know exactly what’s expected. If the landlord suddenly changes rent mid-lease without contract amendment, they’re in breach. API contracts work the same way - changes require negotiation (versioning).

Code Example


# API Contract as OpenAPI Specification
openapi: 3.1.0
info:
  title: Order Management API
  version: 2.1.0
  description: |
    Contract for order processing system.

    **SLA Guarantees:**
    - Response time: 200ms (p99)
    - Availability: 99.9%
    - Rate limit: 1000 requests/min per client
  contact:
    name: API Support
    email: [email protected]

servers:
  - url: https://api.example.com/v2
    description: Production server

paths:
  /orders:
    post:
      summary: Create a new order
      description: |
        Creates an order and returns immediately with status "pending".
        Order processing happens asynchronously.
      operationId: createOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Order created successfully
          headers:
            X-Request-ID:
              schema:
                type: string
                format: uuid
              description: Unique request identifier for tracking
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          description: Invalid request data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Requests allowed per minute
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Requests remaining in current window
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /orders/{orderId}:
    get:
      summary: Get order by ID
      operationId: getOrder
      parameters:
        - name: orderId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Order found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          description: Order not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    CreateOrderRequest:
      type: object
      required:
        - customerId
        - items
      properties:
        customerId:
          type: string
          format: uuid
          description: UUID of the customer placing the order
        items:
          type: array
          minItems: 1
          maxItems: 100
          items:
            type: object
            required: [productId, quantity]
            properties:
              productId:
                type: string
                format: uuid
              quantity:
                type: integer
                minimum: 1
                maximum: 1000
        shippingAddress:
          $ref: '#/components/schemas/Address'

    Order:
      type: object
      required:
        - id
        - customerId
        - items
        - status
        - total
        - createdAt
      properties:
        id:
          type: string
          format: uuid
        customerId:
          type: string
          format: uuid
        items:
          type: array
          items:
            type: object
            required: [productId, quantity, price]
            properties:
              productId:
                type: string
                format: uuid
              quantity:
                type: integer
              price:
                type: number
                description: Price per unit in USD
        status:
          type: string
          enum:
            - pending
            - processing
            - shipped
            - delivered
            - cancelled
          description: Current order status
        total:
          type: number
          description: Total order amount in USD
        createdAt:
          type: string
          format: date-time
        shippingAddress:
          $ref: '#/components/schemas/Address'

    Address:
      type: object
      required:
        - street
        - city
        - postalCode
        - country
      properties:
        street:
          type: string
          maxLength: 200
        city:
          type: string
          maxLength: 100
        postalCode:
          type: string
          pattern: "^[0-9]{5}(-[0-9]{4})?$"
        country:
          type: string
          pattern: "^[A-Z]{2}$"
          description: ISO 3166-1 alpha-2 country code

    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Machine-readable error code
        message:
          type: string
          description: Human-readable error message
        details:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
              issue:
                type: string

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - BearerAuth: []

Diagram

graph TB
    subgraph "API Contract"
        CONTRACT[OpenAPI Spec]

        CONTRACT --> ENDPOINTS[Endpoints
Paths & Methods] CONTRACT --> REQ[Request Schemas
Input Validation] CONTRACT --> RESP[Response Schemas
Output Format] CONTRACT --> AUTH[Authentication
Security Schemes] CONTRACT --> SLA[SLA Terms
Performance, Limits] end subgraph "Provider Side" IMPL[Implementation] TESTS[Contract Tests] IMPL -.Validates Against.-> CONTRACT TESTS -.Enforces.-> CONTRACT end subgraph "Consumer Side" SDK[Generated SDK] MOCK[Mock Server] CLIENT[Client Code] CONTRACT -.Generates.-> SDK CONTRACT -.Powers.-> MOCK SDK --> CLIENT end CONTRACT --> DOCS[Auto-Generated
Documentation] style CONTRACT fill:#90EE90 style IMPL fill:#87CEEB style SDK fill:#FFD700

Best Practices

  1. Contract-first development - Define the contract before writing implementation code
  2. Version explicitly - Use semantic versioning in the contract (1.0.0, 2.0.0)
  3. Test against contract - Run contract tests ensuring implementation matches spec
  4. Generate SDKs from contract - Don’t hand-code clients, generate them to stay in sync
  5. Document SLAs in contract - Include performance guarantees, rate limits as metadata
  6. Use contract for mocking - Generate mock servers from contract for parallel development
  7. Detect breaking changes - Use tools to compare contract versions and flag breaking changes
  8. Make contracts discoverable - Publish contracts in a central registry or API catalog

Common Mistakes

No contract at all: Building APIs with just informal docs or README files. This leads to mismatches between documentation and implementation.

Implementation-first: Writing code first, then extracting a contract from it. This misses the main benefit - contracts enable parallel development and design discussions before coding.

Stale contracts: Writing a contract once then letting it drift as the API evolves. Contract and implementation must stay synchronized.

Incomplete contracts: Only documenting happy paths (200 responses) and ignoring error cases, edge cases, rate limits, authentication details.

Not testing against contract: Treating the contract as documentation only, not as enforceable tests. Contract tests should run in CI/CD.

Breaking changes without versioning: Modifying the contract in backward-incompatible ways without bumping major version, breaking existing clients.

Overly rigid contracts: Making contracts so specific they’re hard to evolve. Balance precision with flexibility for non-breaking additions.

Standards & RFCs

Standards & RFCs
1)- [OpenAPI 3](https://reference.apios.info/terms/openapi-3/).1.0 Specification
2)- JSON [Schema](https://reference.apios.info/terms/schema/) Draft 2020-12
3)- GraphQL Schema Definition Language
4)- Protocol Buffers (protobuf)