API Contract Testing
API contracts define the expected structure, behavior, and constraints of your APIs. SureStage validates mock responses against contracts to ensure they match real API specifications, catching integration issues before they reach production.
Why Use Contract Testing
- Prevent breaking changes - Ensure mocks match production API contracts
- Catch drift early - Detect when mocks diverge from real APIs
- Enforce standards - Require specific response formats or headers
- Document expectations - Contracts serve as executable API documentation
- Enable parallel development - Frontend teams trust mocks match production
How It Works
- Define a contract specifying expected API behavior (schema, status codes, headers)
- Attach the contract to a Sandbox
- SureStage validates mock responses against the contract when routes are created or modified
- Violations are logged and can trigger alerts or block changes
Creating a Contract
API Request
curl -X POST https://api.surestage.com/v1/simulations/sandbox_abc123/contracts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "User API Contract",
"version": "1.0",
"rules": [
{
"path": "/users/:id",
"method": "GET",
"expectedStatus": 200,
"responseSchema": {
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"email": { "type": "string", "format": "email" }
},
"required": ["id", "name", "email"]
},
"requiredHeaders": ["Content-Type"]
}
],
"enforcement": "warn"
}'
Response 201 Created
{
"id": "contract_xyz789",
"name": "User API Contract",
"version": "1.0",
"rules": [ /* ... */ ],
"enforcement": "warn",
"createdAt": "2026-03-21T10:00:00Z"
}
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Contract name |
| version | string | Yes | Contract version (semantic versioning recommended) |
| rules | array | Yes | Array of contract rules (see below) |
| enforcement | string | No | warn or block (default: warn) |
Rule Structure
| Field | Type | Required | Description |
|---|---|---|---|
| path | string | Yes | API path (supports params like :id) |
| method | string | Yes | HTTP method |
| expectedStatus | number | Yes | Expected response status code |
| responseSchema | object | No | JSON Schema for response body |
| requiredHeaders | array | No | Required response headers |
| forbiddenHeaders | array | No | Headers that must not be present |
Enforcement Modes
Warn Mode
Violations are logged but do not block route creation:
{
"enforcement": "warn"
}
When a route violates the contract, you see a warning in the response:
{
"routeId": "route_123",
"created": true,
"warnings": [
{
"contractId": "contract_xyz789",
"rule": "/users/:id GET",
"violation": "Response schema missing required field: email"
}
]
}
Block Mode
Violations prevent route creation:
{
"enforcement": "block"
}
{
"error": "CONTRACT_VIOLATION",
"message": "Route violates contract: User API Contract",
"violations": [
{
"rule": "/users/:id GET",
"issue": "Response schema missing required field: email"
}
]
}
Response Schema Validation
Use JSON Schema to define expected response structure:
Example Schema
{
"responseSchema": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"status": { "type": "string", "enum": ["active", "inactive"] }
},
"required": ["id", "status"]
}
},
"pagination": {
"type": "object",
"properties": {
"page": { "type": "integer", "minimum": 1 },
"total": { "type": "integer", "minimum": 0 }
},
"required": ["page", "total"]
}
},
"required": ["data", "pagination"]
}
}
This validates that responses include:
- A
dataarray with objects containingidandstatus - A
paginationobject withpageandtotalfields
Contract Exceptions
Temporarily bypass contract validation for specific routes using exceptions.
Create Exception
curl -X POST https://api.surestage.com/v1/simulations/sandbox_abc123/contracts/contract_xyz789/exceptions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"routeId": "route_456",
"reason": "Legacy route uses deprecated format",
"expiresAt": "2026-06-01T00:00:00Z"
}'
Response 201 Created
{
"id": "exception_abc123",
"contractId": "contract_xyz789",
"routeId": "route_456",
"reason": "Legacy route uses deprecated format",
"expiresAt": "2026-06-01T00:00:00Z",
"createdAt": "2026-03-21T10:30:00Z"
}
Routes with active exceptions bypass contract validation until the exception expires.
List Exceptions
curl https://api.surestage.com/v1/simulations/sandbox_abc123/contracts/contract_xyz789/exceptions \
-H "Authorization: Bearer $TOKEN"
Delete Exception
curl -X DELETE https://api.surestage.com/v1/simulations/sandbox_abc123/contracts/contract_xyz789/exceptions/exception_abc123 \
-H "Authorization: Bearer $TOKEN"
Managing Contracts
List Contracts
curl https://api.surestage.com/v1/simulations/sandbox_abc123/contracts \
-H "Authorization: Bearer $TOKEN"
Get Contract
curl https://api.surestage.com/v1/simulations/sandbox_abc123/contracts/contract_xyz789 \
-H "Authorization: Bearer $TOKEN"
Update Contract
curl -X PATCH https://api.surestage.com/v1/simulations/sandbox_abc123/contracts/contract_xyz789 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enforcement": "block",
"version": "1.1"
}'
Delete Contract
curl -X DELETE https://api.surestage.com/v1/simulations/sandbox_abc123/contracts/contract_xyz789 \
-H "Authorization: Bearer $TOKEN"
Deleting a contract removes validation but does not affect existing routes.
Importing Contracts from OpenAPI
Generate contracts automatically from OpenAPI specs:
curl -X POST https://api.surestage.com/v1/simulations/sandbox_abc123/contracts/import \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source": "openapi",
"spec": {
"openapi": "3.0.0",
"paths": {
"/users/{id}": {
"get": {
"responses": {
"200": {
"description": "User object",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" }
}
}
}
}
}
}
}
}
}
}
}'
SureStage converts the OpenAPI spec into contract rules automatically.
Security
- All contract operations are protected by
JwtAuthGuardandTenantGuard - Contracts are scoped to Sandboxes — you cannot apply a contract across Tenants
- Contract violations are logged for audit purposes
Common Issues
Problem: Contract validation passes but real API fails
Solution: Verify the contract schema matches the actual API response. Use a tool like Postman to capture a real response and compare it to your schema.
Problem: Too many false positives in warn mode
Solution: Refine your schemas to be less strict, or add exceptions for known outlier routes.
Problem: Cannot create route due to contract violation
Solution: Check the violation message to see which field is missing or incorrect. Update the route response or create a temporary exception if needed.
Related
- Git Sync - Sync contracts with mock definitions
- Compliance & Governance - Enforce contract usage via policies
- Routes & Responses - Learn about route structure