Postman Contract Testing
A contract is a written agreement between an API provider and the apps that use it. The contract states which endpoints exist, which fields appear, and which types those fields carry. Contract testing checks that the real API still keeps its promises, so a change on the server never breaks a mobile app by surprise.
The Restaurant Menu Promise
A restaurant prints a menu. Customers order from it and expect the dishes to match the descriptions. If the kitchen quietly swaps chicken for fish, customers get unhappy. The menu is the contract, and the kitchen is the provider. Contract tests act as the inspector who compares served dishes with the menu.
CONTRACT (OpenAPI file) REAL API RESPONSE
─────────────────────── ─────────────────
GET /users/{id} GET /users/1
id : integer "id": 1 ✅
name : string "name": "Asha" ✅
email : string "email": 12345 ❌ type changedWho Depends on the Contract
- Provider: the team that builds and runs the API.
- Consumers: mobile apps, websites, and partner systems that call the API.
Consumers write code that expects a certain shape. A silent change breaks that code. Contract tests protect consumers and give providers confidence to release faster.
Breaking and Safe Changes
| Change | Impact |
|---|---|
| Remove a field | Breaking, consumers may need it |
| Rename a field | Breaking |
| Change a field type, such as number to text | Breaking |
| Make an optional field required | Breaking for requests |
| Add a new optional field | Usually safe |
| Add a new endpoint | Safe |
Create the Contract
Postman stores contracts as API definitions in OpenAPI format. Import an existing OpenAPI file through the Import button, or write a new definition in the API builder. The definition lists every path, method, parameter, request body, and response schema.
Build Contract Tests with Schemas
Copy the response schema from the contract into a test script. Use one schema per response type.
const userContract = {
type: "object",
required: ["id", "name", "email"],
properties: {
id: { type: "integer" },
name: { type: "string" },
email: { type: "string" }
}
};
pm.test("User response follows the contract", function () {
pm.response.to.have.jsonSchema(userContract);
});Add checks for status codes and headers listed in the contract.
pm.test("Contract status is 200", function () {
pm.response.to.have.status(200);
});
pm.test("Content-Type matches the contract", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include("application/json");
});Test Error Responses Too
Contracts describe failures as well as successes. A 404 response should follow the documented error shape.
const errorContract = {
type: "object",
required: ["error"],
properties: { error: { type: "string" } }
};
pm.test("Missing user returns the documented error", function () {
pm.response.to.have.status(404);
pm.response.to.have.jsonSchema(errorContract);
});Contract Test Workflow
1. Agree on the contract (OpenAPI file)
│
2. Write schema tests for every endpoint
│
3. Run tests in a pipeline after each code change
│
├── Pass ──► Release safely
└── Fail ──► Fix the code or update the contract together with consumersLink the Pipeline
Run the contract collection with Newman or Postman CLI on every code change. A failing contract test stops the release before consumers notice. Store the OpenAPI file in the same repository as the server code, so the contract changes together with the implementation.
Good Contract Habits
- Update the contract first, then change the code.
- Announce breaking changes to consumers well before release.
- Version the API, such as
/v1and/v2, so old consumers keep working. - Test both required and optional fields.
- Keep example data in the contract realistic and free of personal details.
Key Points
- A contract states what an API promises to its consumers.
- Contract tests compare real responses with the agreed schema.
- Removing, renaming, or retyping fields breaks consumers.
- Automated runs catch contract drift before release.
- Versioning lets providers evolve APIs safely.
