Contract testing
Validate producer/consumer compatibility before deployment.
A functional and technical investigation of a distributed order-processing failure across REST APIs, microservices and asynchronous messaging.
System
Incident
PAY-99821ORD-78451Customer has been charged.
“Your payment was successful. We are processing your order.”
Hypotheses
API validation
{
"customerId": "CUS-1842",
"items": [
{
"productId": "PROD-901",
"quantity": 2,
"unitPrice": 24.9
}
],
"currency": "EUR"
}201 CreatedOrder = PENDING_PAYMENT{
"orderId": "ORD-78451",
"amount": 49.8,
"currency": "EUR",
"paymentMethod": "CARD"
}200 OKPayment = APPROVEDA successful API response does not guarantee a successful business transaction.
Event contract
{
"eventType": "payment.completed",
"eventVersion": "2.0",
"eventId": "evt-78310",
"timestamp": "2026-09-10T09:42:18Z",
"data": {
"orderId": "ORD-78451",
"paymentId": "PAY-99821",
"amount": 49.8,
"currency": "EUR",
"status": "APPROVED"
}
}Unsupported eventVersion: 2.0
Log analysis
Payment approved PAY-99821Publishing payment.completed eventPublish successful messageId=MSG-7719Message delivered to order-processing-queueReceived message MSG-7719Parsing event payment.completedERROR Unsupported eventVersion: 2.0; expected 1.0Message moved to DLQRoot cause
The producer publishes eventVersion 2.0, while the Order Processor supports only 1.0. The rejected message moves to the DLQ, leaving the customer charged and the order pending.
Defect
| ID | ORD-2173 |
|---|---|
| Title | Order remains PENDING_PAYMENT after successful payment due to unsupported event contract version |
| Severity | Critical |
| Affected | Payment Service · Order Processor |
| Expected | APPROVED payment → order CONFIRMED → confirmation notification |
| Actual | Payment APPROVED; event rejected; order remains PENDING_PAYMENT |
| Business impact | Customer charged without confirmed order; possible support contacts, reconciliation work, duplicates and loss of trust. |
Regression & contract tests
Validate producer/consumer compatibility before deployment.
Verify event publication, delivery and consumption.
Checkout → payment → order confirmation → notification.
Alert when messages enter the Dead Letter Queue.
POST /orders · 201 CreatedPOST /payments · 200 OKGET /orders/ORD-78451 · expected CONFIRMEDIdempotency
evt-78310 × 2If event evt-78310 is delivered twice, the order should transition to CONFIRMED only once.
Investigation outcome
The investigation narrowed the issue from the complete order flow to the interaction between the payment event and its consumer.
The producer published payment.completed using event contract v2.0, while the Order Processor only supported v1.0.
API responses, event payloads, service logs and DLQ behaviour were connected to validate the hypothesis.
A technically successful payment could leave the customer with a charged payment but an order still in PENDING_PAYMENT.
Producer and consumer contract compatibility was identified as a critical integration risk.
Contract testing, integration testing, E2E validation, idempotency and DLQ monitoring were identified as complementary controls.
Takeaway
Quality is not only validating individual services. It is understanding whether the entire system delivers the expected business outcome.