The warehouse updates its server while staff keep using the previous scanner application. Testing the new app goes well: a delivery opens, cartons are checked and the result is saved. An older scanner cannot interpret the new status and offers to receive goods that have already been processed. The server is healthy, but the warehouse workflow is not.
Backward compatibility means the new side still honours its previous contract with supported consumers. Keeping the API address and field names is insufficient. The agreement includes meaning, permitted actions, failures and what lets the consumer conclude that its work is complete.
Name the versions covered by the promise
“We support old clients” is too vague. Which scanner versions remain in use? Does a partner export deliveries only once a month? Can a device reconnect after an extended offline period? These consumers cannot all be upgraded through one server deployment.
Identify supported combinations of client, server, stored records and message formats. A new application reading an old database does not prove that an old worker can read a newly written record. Upgrade, mixed-version operation and rollback require different compatibility checks.
Google AIP-180 distinguishes source, wire and semantic compatibility. The distinction makes the promise more precise: an application can successfully parse a response and still take an action nobody intended under the previous contract.
An extra field can still change the outcome
A new optional field is often safer than renaming an existing one. But the consumer must actually tolerate unknown fields. Strict response validation, older generated libraries or custom string parsing can invalidate that assumption.
Defaults deserve particular attention. Suppose the server starts paginating a long delivery list while the old scanner sends no pagination parameter. Returning only the first page may silently turn a partial list into what the device believes is the complete result. A successful response will not expose the missing records. Introduce the limit through an agreed transition rather than calling it an invisible optimisation.
A new status value also requires knowing the consumer. One application may display “unknown”; another may fail; a third may take an unsafe default branch. Zalando’s API guidelines discuss extensible values and compatible changes. Declaring a field as string does not document every assumption made about it.
Sometimes the old contract cannot represent the new reality. If deliveries used to be received as a whole and now individual cartons can be accepted separately, neither “received” nor “not received” describes every new state accurately. A separate flow, a restriction on older clients or a changed contract may be necessary. Inventing an approximate answer can be worse than a clear refusal.
Prepare readers before producing the new format
During a rolling deployment, different server versions coexist. Even without external clients, a new writer may encounter an old reader. A useful sequence is often to deploy code that understands both representations while continuing to write the old one, then enable the new writes after the relevant consumers are ready.
Amazon Builders’ Library describes this two-phase technique. Once new-format data exists, the rollback target must still understand it. Keeping yesterday’s installer is not sufficient protection.
Queues and offline commands extend the compatibility window. A scanner may submit yesterday’s action after today’s server update. The worker must interpret that older message and distinguish a retry from a new intention. Message retention, offline duration and client support windows need to agree.
Test consumers that exist, not just the latest build
Testing a new client against a new server answers only one question. The warehouse also needs an old scanner against the new server, supported mixtures of server versions, and rollback after new records have been created. Include unfinished receipts, reconnection and unusual states, not just a clean new delivery.
Pact connects contract verification with specific participant versions. This helps avoid applying evidence from one tested pair to another. But verified exchanges do not replace the employee’s workflow: every required carton must remain visible, and resubmitting an operation must not receive it twice.
Production observations complement these tests. Support needs client version, operation and failure reason without unnecessary document contents. Watch for silent outcome changes too, such as an unexpected reduction in exported records. Not every compatibility failure raises a technical exception.
The old contract need not last forever
Supporting several behaviours costs maintenance, testing and product constraints. Agree on the transition period, an upgrade route and what happens to consumers that miss it. A quiet week does not prove that a monthly integration has disappeared.
Compatibility is not a justification for retaining unsafe access or an acknowledged defect without assessing its risk. An accelerated shutdown may be necessary. Treat that as an explicit decision with an owner, communication and a way to continue essential work—not an incidental consequence of a routine release.
For warehouse receiving, completion means that supported scanners handle deliveries correctly, older queued commands have been accounted for and retired versions are genuinely out of use. Transitional code can then be removed. Until that point, sharing an API version label does not make every combination of applications compatible.