When the Contract Lies: Detecting API Drift in Production
Years ago I was integrating against a carrier's SOAP web service, and I did the most routine thing in the world: I pointed wsimport at their WSDL and let it generate a Java client.
wsimport -keep -s src/generated https://partner.example.com/service?wsdl
Clean build. Every type resolved. The generated proxy looked exactly like what the contract described — because it was exactly what the contract described.
Then the first real call failed. Not a compile error, not a serialization warning. A flat rejection from the server at runtime. One of the generated methods was missing a parameter that the server actually required. The client I'd built faithfully matched the published contract, and the published contract was wrong.
The contract lied, not the tooling
This is the part that stuck with me. wsimport didn't malfunction. My code didn't have a bug in any normal sense. The WSDL — the third party's own machine-readable description of their service — was incomplete. It advertised a method signature the running service didn't accept. Every tool in the chain did its job perfectly, and I still shipped a broken integration, because every tool trusted the contract, and the contract lied.
Here's the uncomfortable general lesson: a machine-readable API contract is only as trustworthy as its agreement with the running service. And almost nothing in your toolchain checks that agreement. Your compiler validates your code against the contract. Your codegen validates the client against the contract. Your tests, if you're disciplined, validate your assumptions against the contract. Every layer validates against the contract — and no layer validates the contract against reality.
What is API contract drift?
API contract drift is when a live API's responses stop matching the contract that describes them — a field changes type, a documented field disappears, a new status code appears — while the endpoint keeps returning a perfectly valid response. It isn't an outage. Nothing errors. The endpoint answers with a clean 200. It just no longer returns the shape your code was written to expect.
Common forms of drift:
- A field changes type — a numeric ID starts arriving as a string
- A field that was always present becomes optional, or vanishes under some conditions
- An undocumented status code or enum value appears
- A date or currency format changes — ISO to epoch, dollars to cents
- Pagination or envelope structure shifts underneath you
None of these trip a status code. All of them can silently corrupt the data flowing into your systems — into billing, reporting, or anything downstream — long before anyone notices.
How API drift shows up in REST and OpenAPI
That original incident was SOAP, and mine was a request-side bug — I was failing to send something the server wanted. It's not the exact failure I'd build a product around. But the shape of it is everywhere, and it didn't stay in the SOAP era.
Swap WSDL for OpenAPI and the story repeats itself constantly. A provider's spec says a field is a string; the live endpoint started returning null last Tuesday. The spec documents six status codes; production quietly added a seventh. An endpoint the spec still lists was deprecated and now returns a 404. Your generated client, your typed models, your contract tests — all green, all validated against a spec that no longer describes what the service actually does.
How to detect API drift in production
The only reliable way to catch this is to continuously detect API drift in production: check the live endpoint against its spec, on a schedule, and get told the moment they diverge. Not at your next release. Not when a customer opens a ticket. The moment it happens.
That gap is what I built DriftSignal to close — for the REST and OpenAPI side of it, where most of us now live.
DriftSignal polls your live GET endpoints on a schedule, validates each response against your OpenAPI spec, and alerts you when the response drifts from the contract: a changed field type, a field that vanished, an undocumented status code, an endpoint that no longer answers the way the spec promises. It watches what the service returns and holds it against what the contract claims — the same silent divergence that burned me back then, caught before it reaches a customer.
The day you find out
The lesson from that carrier integration never changed. Contracts drift from reality, they do it quietly, and your build is the last place that will ever tell you.
If you depend on third-party APIs — or you publish your own — the question isn't whether the spec is accurate today. It's whether you'll find out the day it stops being accurate, or the day your customer does.
Frequently asked questions
What is API contract drift?
API contract drift is when an API keeps responding successfully but the shape of its responses changes from what consuming code expects — a field is renamed or retyped, a previously guaranteed field becomes optional, a new status code or enum value appears, or pagination changes. Unlike an outage, drift is quiet: the endpoint returns a valid 200 response, no alerts fire, and malformed or incomplete data flows silently into downstream systems.
How do you detect API drift in production?
You validate live responses against the API's spec on a schedule, rather than only at build time. A monitoring tool records what each endpoint should return according to its OpenAPI spec, polls the live endpoint continuously, and alerts you the moment a real response diverges from the contract — a changed type, a missing field, an undocumented status code — so you catch drift in production before it reaches your users.
Why doesn't uptime monitoring catch API drift?
Uptime monitoring only answers whether an endpoint responded. A drifted response and a correct response both return 200, so they look identical to a tool that only checks status codes. That is why integrations can quietly corrupt data for weeks while every dashboard stays green — the API is "up" and the integration is broken at the same time.
Is API contract drift only a third-party problem?
No. It happens just as often between internal services. If one team ships a backend change without coordinating with another service that consumes it, the consuming service hits the same silent mismatch. The failure mode — and the fix, validating responses against the contract — is the same whether the API is yours or someone else's.