<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Angad</title>
    <description>The latest articles on DEV Community by Angad (@xenrai).</description>
    <link>https://dev.to/xenrai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4055400%2F874c511b-9398-4754-bb01-c914dba92a36.png</url>
      <title>DEV Community: Angad</title>
      <link>https://dev.to/xenrai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xenrai"/>
    <language>en</language>
    <item>
      <title>We diffed two real Stripe API specs. 679 changes, 16 breaking. Here's what breaks your code.</title>
      <dc:creator>Angad</dc:creator>
      <pubDate>Thu, 30 Jul 2026 16:29:42 +0000</pubDate>
      <link>https://dev.to/xenrai/we-diffed-two-real-stripe-api-specs-679-changes-16-breaking-heres-what-breaks-your-code-3m8k</link>
      <guid>https://dev.to/xenrai/we-diffed-two-real-stripe-api-specs-679-changes-16-breaking-heres-what-breaks-your-code-3m8k</guid>
      <description>&lt;p&gt;Stripe is the gold standard for API stability. Date-pinned versions, compatibility layers, migration guides — the works. And yet: since 2024 they ship breaking changes twice a year, on purpose, via named releases (acacia, basil, clover, dahlia).&lt;/p&gt;

&lt;p&gt;If the best API in the world breaks you twice a year, what are the other 20 APIs you depend on doing?&lt;/p&gt;

&lt;p&gt;I built a tool to answer that concretely. It diffs OpenAPI specs, classifies every change as breaking or additive, scans your codebase for the exact call sites affected, and generates a patch — gated on your own test suite passing. Then I ran it on Stripe's real published specs. Here's what happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The diff (real data)
&lt;/h2&gt;

&lt;p&gt;Source: Stripe's actual &lt;code&gt;spec3.json&lt;/code&gt; from their public openapi repo, at two release tags (v2250 → v2349), about 8MB each.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total changes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;679&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Breaking&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;16&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Additive&lt;/td&gt;
&lt;td&gt;663&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documented paths compared&lt;/td&gt;
&lt;td&gt;200+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The breaking set includes a genuinely interesting one:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;card.iin&lt;/code&gt; was removed — with no replacement.&lt;/strong&gt; The issuer identification number field that BIN-routing logic depends on (&lt;code&gt;token.card.iin.slice(0, 6)&lt;/code&gt; → "route Visa to the primary processor") simply stops existing. No &lt;code&gt;card.iin2&lt;/code&gt;. Your code compiles fine. It dies at runtime, on live traffic.&lt;/p&gt;

&lt;p&gt;(Also in the set: the entire response shape of Terminal's &lt;code&gt;cancel_action&lt;/code&gt; endpoint changed — 13 fields gone at once.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection is the easy part
&lt;/h2&gt;

&lt;p&gt;There are good tools that watch API surfaces and alert you. Alerting is necessary and completely insufficient: an alert that says "something broke" still leaves an engineer reading a changelog, grepping a repo, rewriting call sites, and hoping.&lt;/p&gt;

&lt;p&gt;So the tool does the whole loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Watch&lt;/strong&gt; — diff the specs (deterministic, no LLM needed for classification)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scan&lt;/strong&gt; — map each breaking change to your actual call sites (file:line)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remediate&lt;/strong&gt; — codemod the affected lines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify&lt;/strong&gt; — run YOUR test suite against a simulated post-change server. The patch only ships if your tests pass.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The proof
&lt;/h2&gt;

&lt;p&gt;I wrote a consumer integration the way real code gets written — &lt;code&gt;token.card.iin&lt;/code&gt; for BIN routing — and pointed it at a mock server shaped like the NEW spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tests BEFORE patch: 1 passed, 2 failed   ← TypeError on live patterns
Tests AFTER patch:  3 passed, 0 failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The patch it generated replaced direct &lt;code&gt;.iin&lt;/code&gt; access with a null-guard shim and — this is the honest part — &lt;strong&gt;flagged it for human review&lt;/strong&gt;, because Stripe removed the field with no replacement and choosing a new data source is a business decision, not a code decision. The tool prevents the crash; it doesn't pretend to make your product decisions.&lt;/p&gt;

&lt;p&gt;Fun detail: on the first run, the test gate caught a bug in &lt;em&gt;my own codemod&lt;/em&gt; (an over-broad regex mangled the file). The gate refused to pass it. That's the entire trust model in one anecdote: nothing merges without your CI saying yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's open source
&lt;/h2&gt;

&lt;p&gt;The spec differ and scanner are MIT-licensed: &lt;a href="https://github.com/Xenrai/patchline" rel="noopener noreferrer"&gt;https://github.com/Xenrai/patchline&lt;/a&gt; — point it at any two OpenAPI specs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;patchline diff old_spec.json new_spec.json
patchline scan &lt;span class="nt"&gt;--repo&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--report&lt;/span&gt; diff.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remediation engine (codemods + the migration corpus + CI gating) is the commercial layer, and there's a free watcher that alerts you when APIs you use ship breaking changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The long tail of API change is additive (663 of 679) — signal-to-noise is the real problem, which is why per-codebase impact analysis matters more than changelogs&lt;/li&gt;
&lt;li&gt;Field removals with no replacement are the nastiest class: silent, runtime-only, and unfixable by automation alone&lt;/li&gt;
&lt;li&gt;"We read the changelogs" is this generation's "we have backups" — the diff found things the changelog never mentioned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you maintain more than a handful of integrations, run the differ on your stack and tell me what it finds. Issues and PRs welcome.&lt;/p&gt;

</description>
      <category>api</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
      <category>tools</category>
    </item>
  </channel>
</rss>
