How Stripe does versioning

Much of this post comes from Amber Feng's article Move Fast, Don't Break Your API.

If you use Stripe, you probably haven't thought about the fact that your API has never broken. The company is many years old, and ships changes to their API daily, yet somehow that code you wrote a few years ago still works!

Stripe remembers what version you were on the first time you make a call to a specific endpoint, and locks you in. The URL, parameters, and everything else will be frozen, even if they make changes in the future. This way, the code you've written to interact with the Stripe API never goes out of style.

If the user wants, they can override the version using a header, like this:

curl https://api.stripe.com/v1/charges -u "sk_test_Akslaj2bI2HlWgHofQ2:" \
    -H "Stripe-Version: 2018-05-21"

Stripe does this using gates. Basically, similar to how feature flags work… lots of if statements! All the versions and what they have access to are saved in a YAML file, like this:

-
  :version: 2014-09-24
  :new_gates:
    -
      :gate: allows_amount
      :description: >-
        Sending amount is now deprecated.

And then, in the code, it's checked like this:

def execute
  if !user.gating(:allows_amount) && params[:amount]
    raise UserError.new("Invalid param.")
  end

  ...

  if !user.gating(:allows_amount)
    response.delete(:amount)
  end
end

If you want to read more, check out the full blog post!