When APIs Change Under You: The SLE Migration Story
A real API deprecation, a real deadline, and the verification methodology that made migrating MistPulse's SLE metrics endpoint boring instead of risky.
Part 9 of 10 in Building MistPulse: A Network Architect's Field Notes

Every project that depends on a third-party API eventually gets this notice, in one form or another: an endpoint you rely on is being deprecated. For MistPulse, that moment arrived for one of the more important pieces of functionality in the app: the Service Level Expectation (SLE) metrics that summarize how well a site's Wi-Fi is actually performing for real clients. The specific endpoint pattern the app used to fetch that summary was being phased out in favor of a newer one, and unlike a UI tweak, an API migration has real teeth: get it wrong, and a core feature silently breaks for every user, on both the main app and the Siri integration, at the same time.
Catching it before it broke anything
The first piece of good fortune here wasn't luck; it was the habit, described earlier in this series, of tracking a living feature-ideas and technical-debt document rather than only thinking about features as they're being actively built. That document is where a deprecation notice like this gets flagged the moment it's noticed, framed honestly as "not a feature idea, an action item," rather than left to be discovered later as a support ticket when the old endpoint actually goes away. Proactive migration, on a schedule I control, is a fundamentally different and safer position than reactive migration, on a schedule an outage forces on me.
Proactive migration, on a schedule I control, is a fundamentally different position than reactive migration, on a schedule an outage forces on me.
Verifying before touching a single line of code
This is where the "curl first, build second" discipline from Part 3 mattered most in the entire project's history. Before writing any migration code, I ran live curl calls against the new endpoint pattern, using the same home-lab Mist deployment described earlier, and compared the response shape directly against what the old endpoint returned. That comparison covered all of the individual SLE metrics the app surfaces, plus the edge case that matters most for a metrics endpoint: what happens when you request a time window with no data in it, such as one that extends into the future. The new endpoint, reassuringly, returned nulls for that case rather than an error, the same behavior as the old one, which meant the existing error-handling logic in the app didn't need to change, only the endpoint path and any field-level differences did.

Migrating both sides at once, without breaking either
Because the Siri module maintains its own independent Swift implementation of the Mist API client, a direct consequence of the native integration described in Part 5, this migration had to happen in two places at once, kept consistent with each other. The main app's data-fetching function was updated to point at the new endpoint pattern, and the Siri module's equivalent function was updated the same way, verified against the same curl-tested response shape rather than assumed to behave identically just because it used to.
The proxy's path allowlist also needed a change, but the specific way it was changed mattered: rather than replacing the old pattern outright, the new pattern was added alongside it. That additive approach meant there was no window where a client using the old endpoint would suddenly be locked out before every caller had actually switched over: a small operational safeguard that cost almost nothing to include and removed an entire class of "did I deploy these changes in the right order" risk.
- Flag deprecation notices proactively, in a living document, before they become urgent
- Verify the new endpoint's response shape with real curl calls before writing any migration code
- Deliberately test the edge cases (like empty time windows) that matter most for the type of endpoint being migrated
- Migrate every independent client (main app and Siri module) together, verified against the same tested shape
- Add new allowlist patterns additively rather than replacing old ones, to avoid a lockout window during rollout
Closing the loop with a real review and a real deployment
After the code changes were made on both sides, the same bug-and-security review habit from Part 4 was applied specifically to this change: checking the updated allowlist regex for correctness, confirming no token or sensitive data handling had shifted as a side effect, and confirming the generalized parts of the codebase touched by this change (any shared utility functions) still behaved correctly for every caller, not just the one being actively migrated.
The backend half of the fix was deployed directly to the production Supabase project and verified by reading the live deployed function back to confirm it matched what was intended, closing the loop the same way every deployment in this project does, by checking the actual deployed state rather than trusting that a deploy command succeeding means the intended change is what's actually live.
No new mobile build was required for this particular migration, since the change lived entirely in code paths the existing build already called generically. That's a direct payoff of the proxy architecture from Part 2: a real infrastructure-facing change shipped without needing a new App Store submission or a new TestFlight build at all.
This migration is a good closing case study for the series, because it's the one moment where every methodology covered so far, proactive tracking, live API verification, dual-client discipline, security review, and a real deployment check, had to work together under real time pressure, not just in isolation during calm feature development. The final post steps back from any single feature to ask the bigger question: what did building this, end to end, actually teach me, and where does it go from here?
Coming up next: Lessons Learned & What's Next: the retrospective, and the roadmap for MistPulse going forward
Building MistPulse: A Network Architect's Field Notes
- 1.The Idea: Why I Built MistPulse
- 2.Laying the Foundation: Architecture and the Security-First Proxy
- 3.Curl First, Build Second: The API Validation Methodology
- 4.Real Bugs, Real Fixes: Debugging in the Open
- 5.Teaching Siri to Speak Mist
- 6.The Entity Resolution Saga
- 7.Generalizing Features: The Bulk Rename Story
- 8.Security by Design
- 9.When APIs Change Under You: The SLE Migration Story (you are here)
- 10.Lessons Learned & What's Next
Related posts

Generalizing Features: The Bulk Rename Story
What it took to turn a single-purpose bulk-rename tool into something reusable across device types, without overbuilding it, and the trade-off that came with generalizing.

Lessons Learned & What's Next
A retrospective on building MistPulse solo: five lessons worth carrying into any infrastructure-facing project, and where the app goes from here.

Security by Design
Encryption, redaction, and least privilege as first-class features in MistPulse, not afterthoughts, and why recurring security review matters more than a one-time audit.
Comments
No comments yet. Be the first.