An API contract is the agreed, machine-readable description of how an API behaves: which endpoints exist, what each request must contain, and what each response is guaranteed to return. The provider promises to honour it and consumers build against it, so each side can change its own code freely as long as the contract still holds. For REST APIs, the contract is usually written as an OpenAPI file.
A complete contract for a small Orders API, written as an OpenAPI 3.1 file. Copy it as a template: rename the paths and schemas, keep the structure.
openapi: 3.1.0
info:
title: Orders API
version: 1.0.0
description: The contract between the Orders service and its consumers.
servers:
- url: https://api.example.com/v1
security:
- bearerAuth: []
tags:
- name: Orders
paths:
/orders:
get:
tags: [Orders]
operationId: listOrders
summary: List orders
parameters:
- name: status
in: query
description: Only return orders in this status.
schema:
$ref: "#/components/schemas/OrderStatus"
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
"200":
description: A page of orders
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Order"
"401":
$ref: "#/components/responses/Unauthorized"
post:
tags: [Orders]
operationId: createOrder
summary: Create an order
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NewOrder"
responses:
"201":
description: The created order
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
"400":
description: The request body failed validation
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"401":
$ref: "#/components/responses/Unauthorized"
/orders/{orderId}:
get:
tags: [Orders]
operationId: getOrder
summary: Get an order
parameters:
- name: orderId
in: path
required: true
schema:
type: string
responses:
"200":
description: The order
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
description: No order with this id
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
responses:
Unauthorized:
description: Missing or invalid access token
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
schemas:
OrderStatus:
type: string
enum: [pending, paid, shipped, cancelled]
NewOrder:
type: object
required: [customerId, items]
properties:
customerId:
type: string
example: cus_81a2
items:
type: array
minItems: 1
items:
$ref: "#/components/schemas/OrderItem"
OrderItem:
type: object
required: [sku, quantity]
properties:
sku:
type: string
example: TSHIRT-M-BLK
quantity:
type: integer
minimum: 1
example: 2
Order:
type: object
required: [id, status, items, total, createdAt]
properties:
id:
type: string
example: ord_5f3c
status:
$ref: "#/components/schemas/OrderStatus"
items:
type: array
items:
$ref: "#/components/schemas/OrderItem"
total:
type: integer
description: Order total in minor units (cents).
example: 4998
createdAt:
type: string
format: date-time
Error:
type: object
required: [code, message]
properties:
code:
type: string
example: order_not_found
message:
type: string
example: No order with this id.
pathsparameters, requestBodyresponsescomponents.schemassecurityinfo.versionTwo questions decide whether a contract can be trusted: is it a valid contract, and did the latest change break it? Paste your own OpenAPI or Swagger file over the example to answer both.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
1It is a written promise about how an API behaves. It lists the endpoints, the inputs each one accepts and the outputs each one returns, in a format both people and tools can read. Anyone calling the API can rely on that promise instead of reading the server code.
Yes, when both sides treat it as the source of truth. OpenAPI is the most common format for writing a REST API contract. The file becomes a contract, rather than just documentation, once the provider commits to it and changes are checked against it.
Documentation explains an API to people. A contract is the precise, machine-readable agreement that documentation, mock servers, client code and tests can all be generated from or checked against. Good documentation is usually rendered from the contract.
Any change that makes a previously correct consumer fail. Typical cases are removing an endpoint or a response field, renaming a field, making an optional parameter required, adding a required request field, changing a type, and removing an enum value the consumer may still send.
Additive changes are normally safe: a new endpoint, a new optional parameter, or a new optional field in a response. Consumers that follow the original contract keep working because nothing they depend on has changed.
Contract testing checks that the provider and its consumers still agree with the contract. On the provider side that means the real responses match the documented schemas, and on the change side it means a new version of the contract introduces no breaking changes compared with the last one.
OpenAPI Validator
Check a contract against the official schema, with line numbers and fixes.
OpenAPI Diff
Compare two versions of a contract and flag every breaking change.
GitHub Action
Run both checks on every pull request and block breaking merges.
Changelog Generator
Turn contract changes into release notes consumers can read.