April 27, 2016

Pixels and Tactics: Building a 2D RPG in the browser

Continuing with my tradition of belatedly writing blog posts after talks, I'm super excited to be reviving my blog with a post about a game I'm working on.

As most of my friends already know, I love games (of both the board and video variety). I've wanted to write a game for a really long time and have actually started a few text-based RPGs over the years, but I've never gone deep into any particular one. Around a year ago, me and my friend James decided we wanted to try again, and thus our game and this talk were born!

I gave this talk last year at a meetup called WaffleJS where you listen to JS talks and eat waffles (highly recommend; it's pretty great). Enjoy!

I really like (J-) RPGs.

My favorite games are old-school Japanese RPGs on GBA / SNES like Golden Sun, Tales of Phantasia, Chrono Cross/Trigger, Fire Emblem, etc. Anyone else?

We spent hours doing, uh, "competitive research", which distracted us at times but gave us tons of ideas for battle mechanics, crafting and refining systems, and menu aesthetics that we knew we'd want in our game. Whatever you end up doing, you should have a pretty clear idea of what you want to build. Play games or look at screenshots / videos for inspiration!

Our game


We knew our game was going to end up being fairly complex: we got overly excited and chose to go with a full tactics RPG for our first game ever (talk about scope creep). Given the number of features we needed to build, we thought it'd be nice to build and test our logic before getting drawn into the time-sucking world of pixel art, so we started building a text-based game first.

In hindsight, this was a great strategy: we were able to decouple the aesthetics, for now, and focus on the actual gameplay and battle mechanics we needed. It's the equivalent of building an MVP and testing out a product hypothesis — assets end up being a huge time sink, however fun and exciting they may be to look at initially.

Code-wise this meant separating our views from the logic as much as possible. This is a pretty standard practice nowadays in most frameworks, but I didn't fully appreciate it until it came time to swap out the text frontend (console.logs) for an actual graphics engine. (We still have our "CLI" files in our repo, for when we want to test something out quickly without the graphical interface!)

If you're into text-based games you can stop here, and there are a lot of small polishes you can do to make your game delightful. Here are a few of our early screenshots! (Yes, those are command line progress bars repurposed as HP bars. I also went a little crazy with custom terminal colors.)

2D onward!

I looked around at several different browser game engines and settled on CraftyJS (more on this in the next section). Coupled with a graphics pack, we were able to start building out our game look and feel:

This is the current stage we're at and there's lots to do in terms of defining the storyline, mechanics, building out the menu and battle interfaces, and so on. It's really fun. (:

We're working toward the first "release" of our game, so if you're interested in following along with the progress, you can sign up to be notified. (I'll also post any updates, along with any new posts here and on Twitter.)

What even goes into a game?

This was my first time building anything like this! We had to learn all of the fundamental bits ("how are tilesets formed") and dug up a ton of resources that we found really useful and would love to share.

At the highest level: what goes into a game, or at least a game like ours? The main areas are the framework, assets, and your actual game mechanics.


First, you need something to actually write your game in. Think of this as the skeleton that supports your assets and game logic. It also provides handy standard functions for you (e.g. rendering graphics, collision detection, event handling).

If you care most about the end result, you might want to consider using a fully featured game engine like Unity or Unreal Engine (these support cross-platform compilation and have more of a WYSIWIG / GUI interface for game development; they're used for many professional games), or even something like RPGMaker which is software specifically for creating RPGs.

I was personally most interested in the game development (hopefully you are too if you are reading this post!), and wanted more of the ability to learn how to architect a game and string all of the pieces together myself first. We were also looking for a JS/HTML5 framework because we wanted to build in the browser given the ease of distribution and ability to show our friends.

I personally liked Crafty both because of the framework itself but also because it's being actively developed on, including third-party extensions. It felt like there was a good balance between existing standard functions and customizability: we ended up writing all of the interaction logic, menu displays, and so on, but it was easy to take advantage of the primitives that already existed.

With Crafty, the way you write your game might look something like this:

// I've included a working demo / code at the end of this post! (:

// Load assets
Crafty.sprite(32, 32, "assets/player.png", {
  player: [0, 0] // specify size & index of image sprite

// Write some custom components
Crafty.c("PlayerControl", {
  PlayerControl: function() {
    this.bind("KeyDown", function(e) {

      if (e.keyCode === Keys.RIGHT) this.moveRight();
      if (e.keyCode === Keys.LEFT) this.moveLeft();
      if (e.keyCode === Keys.UP) this.moveUp();
      if (e.keyCode === Keys.DOWN) this.moveDown();

      // Player-specific commands
      if (e.keyCode === Keys.SELECT) {

// Set and load the first scene
Crafty.scene("start", function() {
  // Set map tiles, populate enemies, etc
  // ...

  // Create player entity and properties
  var player = Crafty.e("2D, DOM, PlayerControl, player")
    .attr({currentMap: "start"})
    .PlayerControl() // custom component to handle keyboard control commands
    .Collision(Crafty.polygon(points)) // automatically handle collisions
    .reel("walk_left", 600, 0, 1, 4) // set animation speed & sprite frame indexes
    .reel("walk_right", 600, 0, 2, 4)
    .reel("walk_up", 600, 0, 3, 4)
    .reel("walk_down", 600, 0, 0, 4)

We use the component system (e.g. PlayerControl) extensively as a design pattern. Components are extremely composable so we use them to represent logic for everything from menu UI to how sprites walk around. This topic by itself is enough to fill several blog posts — stay tuned!


Assets are the other large and obvious (because they're what you see) part of game development.

The first thing I learned was that assets are hard, particularly if you're not an artist or composer yourself. They're really important because they represent the look and feel of your game and very often are what players will initially judge your game by, but you can end up spending a lot of time and money here.

This is admittedly another infinite bucket (welcome to gamedev!). I can really only speak to 2D graphics here, but the main things I've worked with so far are sprites and tilesets.

Sprites and tilesets are probably best explained with a game we're all familiar with. Take Zelda, for example:

Tilesets are repeatable assets which compose what you typically think of as the "background": grass, trees, flowers, houses, and so on. You often use special software (like Tiled, a map editor for Mac) to "draw" the map with tilesets or else it's impossible to manage.

Sprites are more of "foreground" objects: players themselves, monsters, items, etc. They're also very often animated, which adds additional complexity: you want your character to look like it's walking, talking, attacking, casting spells, leveling up, whatever.

If you're not an amazing pixel / 3D artist yourself (I am not!), there are a ton of really great resources out there — from open source to marketplaces and commissions.

Here are a few of my favorites:

  • Open Game Art: Totally free and open tilesets, sprite, music, you name it. The descriptions will usually tell you if they can be used for commercial purposes or not; most can be.
  • Kenney: A gaming studio that made a ton of their high-quality assets free for use by the public. Our tileset actually came from here — see if you can spot it!
  • Game Dev Market: Lots of nice, high-quality asset packs available for purchase. They're not too expensive, though it is pretty tempting to purchase many of them!
  • RMN Music Pack: Large, free selection of great background / battle music (mostly RPG-sounding).
  • as3sfxr: Make your own sound effects (particularly good for things like beeps, lasers, etc) and export them.

You can also find a fair number of independent artists by Googling or looking at DeviantArt. Here's one I drooled over for quite some time and hope to be able to use sometime in the future.

Happy hunting!

Game logic and data

Finally, there's the actual lifeblood of your game: the style of game you're building, and the resulting logic, mechanics, and data.

This section is pretty much as complex as you want it to be. Something like Pong is relatively simple, whereas a full-fledged tactics RPG (sigh) is going to require significantly more work both in terms of brainstorming and implementation.

Our game started off very Pokemon-esque (you can tell what generation we grew up in...) and it evolved more into a classic J-RPG. As we worked, we ended up pulling bits from other games we've played such as crafting, taming companions, weapon mastery, and so on.

For most games, there are a few main areas you'll need to consider:


Every game has some sense of the "player" and the more complex you get the more state this player will need to contain. In our game we had a notion of a level, HP / MP, intrinsic stats and stat growths, skill trees, and inventory.


What does the map or setting for your game look like? If you have monsters that spawn, do they spawn randomly and how do they walk around? Many RPGs follow the pattern of having the map you're currently on (whether it be a town, cave, or forest) and the "world map" where you can travel between maps.

Depending on your game you may have in-game characters or objects you can interact with or stores that your character can buy equipment from.


Are you building a platformer? Puzzle game? Shooter? How do battles work, how do interact with other characters, and how do you use consumable items? Is there a skill / spell system? How do you win the game? Is it real-time?

Another thing think to keep in mind is if your game feel balanced: is it too hard or easy, does the progression feel right? You'll likely need some set of data files to contain all of this information. We have spreadsheets for each type of item, monster, and spell complete with their properties, and our set of algorithms for things like calculating how much damage is dealt or how to randomly roll the loot you collect.

This part is a lot of fun and where some of the best games are most creative. You can also do hybrids of different mechanics you see! For example, I once played a game that was half RTS (real-time strategy, like Starcraft or Warcraft) and half FPS (first person shooter, like Halo).

When you're building a game, it's important to keep playing it yourself! Trust your instincts; when something doesn't feel fun, you should tweak it. We're building an "endless dungeon"-style of game first (no plotline, just battling monsters), which will give us a test arena for development going forward and can also act as our first release. There won't be a story, but we'll get to test out how the game progression feels: are the skills we pick exciting, does the leveling curve flatten out at some point, are the bosses impossibly hard?

Try it yourself

I found it hard to find any actual up-to-date Crafty tutorials / examples when I was starting out, so I made one that you can fork and start playing around with that covers some basic mechanics hooked up with some of our assets. Let me know if it's useful or if you run into any issues!

Try it out below (click, then arrow keys to move and pick up mushrooms):

Game development is infinite

There are many areas I can sense on the horizon, but don't know much about yet: from AI to networking in a multi-player game.

This is something I find fascinating about game development — you can go as infinitely deep as you want. You can code a text-based game, then expand into the world of 2D graphics, then explore 3D. As if that wasn't enough, there's optimizations (on the graphics layer but also in the game itself), AI (for anything more complicated than A* / simple heuristic rules), realistic map generation, and networking. In the not-so-distant future, we'll also have virtual reality and augmented reality.

There's so much surface area I'm excited to learn about and I'll continue to write about my adventures here. (If you are too, holler! I'd love to chat and trade notes.)

October 10, 2014

Move fast, don't break your API

As a sequel to my talk last year on building Stripe's API, I thought it'd be useful to go over how we scaled some of our internal abstractions to continue building and iterating quickly. I gave this talk at APIStrat Chicago a couple of weeks ago and several events at HeavyBit last week, who generously recorded and transcribed the whole thing for anyone who'd like to watch a video. (Thanks, HeavyBit!)

I'm the kind of person who will impatiently watch videos of talks or lectures on 2x speed and greatly prefer reading a blog post that can be skimmed easily, so I decided to write an accompanying post to go with the slides.

Enjoy! (:

Let's build an API!

Stripe has a lot of APIs, and as a result we had to quickly figure out how to scale our abstractions and code. Since code is worth a thousand words (that's a saying, right?), I'll run through an example of building an API.

Here's a super simple example of an API endpoint in Sinatra that creates credit card charges:

post '/charges' do
  # Authentication
  api_key = get_api_key
  user = User.find_by_key(api_key)

  unless user
    return {error: "Invalid API key."}

  # Collect user parameters
  card_number = params[:card_number]
  amount = params[:amount].to_i

  # Validations
  unless card_number.length == 16
    return {error: "Invalid card number."}

  unless amount > 0 and amount <= CHARGE_MAX
    return {error: "Invalid amount."}

  # Actually create the charge
  charge = create_charge(card_number, amount)

  # Return an API response
  json {
    id: charge.id,
    amount: charge.amount
    card_number: charge.redacted_card_number,
    success: charge.success

It's starting to get a little crowded in here, but it's more or less a working API. That was easy!™

What next?

As you start adding new endpoints, functionality, and changes you run into more problems.

How do you (scalably) do things like authentication, validation, actual API logic, error handling, authentication, and at the same time support every combination of behaviors that has ever existed in the past? We can't ever break integrations—particularly as a payments processor, broken integrations means our users are literally losing money every minute. We need to be able to build and change things rapidly without compromising any API stability or backwards compatibility.

Once your API has reached a certain size, something that also starts to creep up on you is dependencies. Documentation is a good example of this. Say you build an API and write up docs in the form of static HTML or markdown. It launches and everyone is happy.

A week later you decide to add something to the API. You diligently add it to your API code and maybe even remember to make the change in the docs as well.

With more additions or updates though, sooner or later this is going to happen:

Crap, I forgot to update the docs! — Everyone, ever

Sound familiar? (This has definitely happened to me more than once.) How did we start making these problems less painful?

Separate the layers of responsibility

In the example above, many things are going on at once: authentication, validation, endpoint-specific logic, error handling, and constructing the response.

Separation of responsibilities is CS 101, so we started moving things out and building abstractions around them.

For authentication and error handling, we use Rack middleware and it works pretty well. You shouldn't have to worry about authenticating users in the middle of your API logic (most frameworks have a concept of before filters for this as well). You also shouldn't have to hardcode error response formats. Wouldn't it be nice if you could just throw an error and know that someone else will catch it to format it into the proper response later?

use ErrorHandler
use Authenticator

get '/charges/:id' do
  user = env.user
  id = params[:id]

  if charge = user.get_charge(id)
    json {
      id: charge.id
  else user.get_charge(id)
    raise UserError.new("No charge #{id}!")

We represent endpoint validations, logic, and response generation internally in our code as APIMethods and APIResources. If you're familiar with MVC, they're very similar to controllers and views for your API.

class ChargeCreateMethod < AbstractAPIMethod
  required :amount, :integer
  required :card_number, :string

  resource ChargeAPIResource

  def execute
    create_charge(amount, card_number)

class ChargeAPIResource < AbstractAPIResource
  required :id, :string
  required :amount, :integer
  required :card_number, :string
  required :success, :boolean

  def describe_card_number

Make it really hard to mess up

A good UX design principle is that you should make it really hard for your users to mess up or do the wrong thing. Why not apply this toward building the API as well?

One thing that we did that I thought was really cool was a system for documenting our API. To try to address "I forgot to update the docs!" syndrome, we made it really hard to forget by putting the documentation right under the code that adds a new property.

class ChargeCreateMethod < AbstractAPIMethod
  required :amount, :integer
  required :card_number, :string

  document :amount, "Amount, in cents."
  document :card_number, "The card number."


Our documentation then auto-generates itself from these specs—for changing most things, there's no need to go dig up static HTML files.

Similarly for our API libraries (or at least those that can support it), we don't hardcode properties for each object but instead dynamically generate them based on the properties present in the response that is received. This way we don't have to worry about adding new fields to object definitions in each library.

Hide your backwards compatibility

We're often asked how we implement our API backwards compatibility. This probably merits an entire talk and post by itself, but I'll go over it at a high level.

When a user starts implementing Stripe for the first time they don't need to worry about API versions. Instead it's invisible—they'll innocently make their first API request, we'll record what internal version they're on, and from then on our code takes care of making sure we never break their integration.

If a user wants to worry about versions they can: we allow overrides to be sent in via request headers and users can upgrade their version via the dashboard. However most people won't care, so they shouldn't have to know about it. All most Stripe users see is that their integration, even if they first wrote it years ago, never breaks.

All of our versions live in the same code base and are deployed to the same service. We don't do separate services or deploys for different versions. The downside of doing is that it's easy for things to get hairy after a while.

First pass

Imagine sometime down the road Stripe decides to deprecate the amount parameter and all charges are now $1. (Disclaimer: I'm pretty sure we will never actually do this.)

What's the naive way to implement that change in behavior? Maybe something like this:

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


  if !user.old_version?

There are a couple of problems with this. First, who knows what old_version? is supposed to mean? You can infer it from the code, but it's really not intuitive and is just waiting for accidental regressions. Second, the regular API logic and legacy logic are being mixed together. If someone wanted to add or update the something in the current API (somewhere in that ...), they would have to wade through those extra conditionals.


We've modeled our versioning system around a series of gates. A "gate" is a database flag (similar to feature flags) that our code can use to determine what functionality to allow. For example, if a user is on an old version and is therefore allowed to send the amount parameter, they're on the allows_amount gate.

We declare all of the versions along with the corresponding functionality gates in a single YAML file:

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

and are able to decouple versions from the actual behavior they represent in our code:

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


  if !user.gating(:allows_amount)

To go one step further and actually get that logic out of the endpoint execution code, separate compatibility layers were added to our code flow. Because who doesn't need more layers of indirection?

Now when a request comes in it first filters through the request compatibility. That layer may or may not reject it based on the parameters (like if someone passes in amount who isn't allowed to) or munge the parameters to something that the later logic expects.

After the response is created, it passes through another layer of response compatibility which transforms the response into whatever the user's version dictates. The great thing about this is that the API logic and response construction steps can represent the current version of the API without any legacy edge case clutter.

It's worth noting that these layers aren't free: there's a certain amount of complexity added when fiddling with requests and responses that are passed through, but we made the tradeoff to be able to keep our general API code (what engineers spend 80-90% of their time working on) clean and easier to reason about.

In the real world

What does this look like in practice? Stripe has (at the time of writing) 106 endpoints, 65 versions, and 6 API client libraries. You can do the combination math yourself.

We would be far behind where we are today if we couldn't find, read, and change code quickly without being afraid of breaking our users.


So design for yourself. Spend some effort not just thinking about how you can optimize your users' experiences, but how you can optimize your own as well.

Stripe's far from perfect; we're learning more and more every day and (like any other startup) there are still very many things in our code that annoy and embarass us. I hope this gives others a sense of things we've learned over the years and helps other developer companies who are tackling the same problems.

If you're ever interested in chatting about any of these topics, I'd love to chat—drop me an email or poke me on Twitter.

I ended up writing far more than I had intended so if you made it down this far, congratulations and thanks for reading!

Credit to Sheena Pakanati, Saikat Chakrabarti, Ross Boucher, Greg Brockman, and many others at Stripe for contemplating, building, and iterating on everything covered in this post.

May 8, 2014

Opening files in Github from Vim

I spend a lot of time nowadays doing code reviews and helping spin people up on Stripe (or more generally, distributing knowledge about our code base). One thing I found myself needing over and over again was the ability to show someone a file or some code over IM or Slack. Since we use Github to host our repositories, this is as easy as linking to the online file.

However, it's pretty annoying to have to use Github's UI to navigate through folders, and I almost always mess up trying to type the full path in the URL (blob? tree?). I also use Command-T with Vim, which means I never remember file paths or exact file names. (If you don't use Command-T or something similar, you should—it's the single biggest improvement to my code reading/writing productivity over the last couple of years.)

"Wouldn't it be awesome if I could just open a file in Github directly from Vim with some keyboard shortcut?", I thought to myself.

I did a bunch of research to try to figure out how hard it would be to build myself (I've never written a Vim plugin before), and stumbled upon git web--browse. From the man page:

   git-web--browse - git helper script to launch a web browser


   opened web browser.

Sounds like exactly what I want!

Amazingly, fugitive, a Git wrapper for Vim, actually has this functionality built in. If you have fugitive installed already, try it right now: go to a file that's hosted on Github, then type in the command :Gbrowse. It'll automagically open the corresponding link (keeping in mind what branch you're on, and everything) in your browser. You can even highlight a couple lines in visual-mode to have those be highlighted on Github.

I ended up remapping :Gbrowse in my .vimrc to something easier to type, you should too:

noremap <leader>w :Gbrowse<cr>

I use this at least a few times every single day. Hope you find it useful too!

September 20, 2013

Painting Adventures

A couple of friends and I decided around a month ago that we wanted to get better at drawing, so we decided to embark on one of those "draw one thing every day for 365 days" projects. Well, if we're being realistic, for approximately 365 days—we even named ourselves "Approximately 1095" (1095 = 365 x 3).

It's been really fun so far:

(I'll write up a separate post later about how/where I'm posting these!)

One day I woke up to discover that my friend Jack had, that morning (on mostly a whim), gone out and purchased a set of painting supplies and was happily painting away on an easel in front of the bay windows in his room.

I thought that was pretty amazing and was inspired to do the same. As much as I like drawing and sketching, the lack of color is sometimes a bit depressing. I've always wanted to experiment with painting (having done digital/Photoshop painting but never physical painting), and decided to try it out1!

Color mixing

The day my acrylic paints arrived (2-day Amazon Prime, ftw), I sat down and practiced mixing a bunch of colors to get a feel for the ratios and color combinations. And it's a good thing I did, because I instantly made the newbie mistake of squeezing out entirely too much dark paint (a dark pigment like red will overwhelm a lighter one like yellow; 90% yellow + 10% red is basically already dark orange).

I ended up with a bunch of index cards with color gradients, much like a Pantone catalog. Pretty fun. I actually like using physical paints a lot more than using a digital color picker, since the colors blend together pretty interestingly when painted, and aren't just one flat color.

First painting!

The prompt of the day for our drawing project was "mermaid" and I knew I wanted to paint a landscape (so hard to mess up!), so I decided to paint the underwater castle from the Little Mermaid.

The hardest part was probably being too scared to paint over things that I had already painted in the background (no undo or layers?!). It was really fun though.

Highly, highly recommend picking up painting as a hobby. It's relatively cheap (I got everything for around $50-60 on Amazon), and it's super fun and relaxing/therapeutic to be swirling paint around for a couple of hours. Not to mention you get an awesome physical piece of art that you can then decorate with, gift, or hide in your closet.

I decided to start off with acrylic because watercolor is really hard to control or recover from mistakes with, and oil has a messier cleanup, but it's really up to your own preference. Enjoy!

I hope to be posting more about the rest of my painting adventures soon! (:

1: I'm still continuing the drawing project, I'll just substitute paintings in every once in a while.

February 23, 2013

Building Stripe's API

I just got back from New York, where I gave my first conference talk ever at the API Strategy and Practice conference. Pretty exciting!

I thought it would be interesting to talk about Stripe's API, particularly lessons learned and what kind things we did to try to make using the API as easy as possible. I've included the slides below, but most of the content isn't on the slides so I'll try to cover some of the highlights below.

As a disclaimer, we definitely don't know everything. A lot of what you see on Stripe today is the product of thought and discussion, as well as a lot of trial and error. I hope you find something in here applicable toward your own API! (:


Make it easy to get started

This sounds like a no-brainer, but the best way to get people to try out your API is to make it really easy to get started.

We do things like including passable code snippets throughout our site and documentation. For example, one of the first things you'll see on our front page is a curl snippet you can paste into a terminal to simulate charging a credit card. Regardless of whether you have a Stripe account or not (if logged in, we embed your test API key, else, it's a sample account's API key), you can see the Stripe API in action.

All of our documentation code snippets are similarly easy to copy and paste—we try to embed as much information as possible (API keys, actual object IDs from your account) so you don't have to.

Language-specific libraries and documentation

Since Stripe is an HTTP API, you could easily integrate it into your application with any HTTP client library. However, this still requires constructing requests and parsing responses on your own.

To make this easier, we support official open-source libraries in the most web today (turns out people are pretty attached to their favorite languages). There was a lot of internal discussion about whether we actually wanted to support our own API or allow the community to organically start and maintain the projects themselves.

Ultimately, I think there's a certain degree of trust that users put in official libraries, which makes it easy for them to get started (as opposed to trying to audit different third-party libraries). It also makes it really easy for us to have language-specific documentation this way.

Have a focused API, but allow flexibility

One thing that we found critically important was to keep the API focused. It's tempting to add new features that are nice, but not necessary.

For example, our users frequently want us to add better analytics, tax calculations, or to send user receipts. While these things are nice, they're not our core competency and may very well clutter our API with too many options1.

Instead, you should give your users the tools to be able to write their own extensions. We allow our users (and third party applications) to hook into Stripe in a couple of ways.


Webhooks are a way of Stripe letting you (our user) know when some interesting event has happened on the Stripe server. Examples include charge.succeeded, charge.refunded, invoice.paid, and so on.

With webhooks, it's easy to build something on top of Stripe events, like sending a customer receipts. This has the added benefit of allowing our users to control the entire user experience.

Stripe Connect

Stripe Connect, an API we released just last year, is another way of building on top of the Stripe platform. Connect is an OAuth2 API that allows a Stripe user to authorize access to their Stripe account to a third-party application. This application might be a marketplace, whose users want to accept payments, or an analytics dashboard, who wants to be able to have full access to Stripe data.

Provide a testing environment

One of the most important things you need with an API is a test environment. This is particularly important for a payments API— obviously your users won't want to make live charges when they're trying to test their application.

In our testing environment, we allow you to send test web hooks of any type and provide handy test card numbers that trigger certain errors (like declines). Doing this allows our users to easily test the behavior of their own application in the face of different scenarios instead of having to manually trigger things that are nondeterministic, like declines, or time-dependent, like expiring subscriptions.

If there's certain behavior that your user's application potentially depends on, make sure they can test it easily.

Help your users debug

We're developers too. We know that a large percentage of our users' time is probably spent debugging. We also (unfortunately) know that sometimes you spend a lot of time debugging something that eventually turns out to be really obvious or stupid.

For common or easy errors, you (the API) likely know exactly what's wrong. So why not try to help?

>> Stripe::Customer.create
Stripe::AuthenticationError: No API key provided.  (HINT: set your API key
support@stripe.com if you have any questions.)


>> Stripe.api_key = TEST_KEY
=> ...
>> Stripe::Charge.retrieve("ch_17SOe5QQ2exd2S")
this request.

If you help your users debug, they'll love you.

Dealing with Change

Lastly, dealing with change is never fun. As much as you hope you'll never have to change the API, sometimes you need to make changes, and sometimes those changes are backwards-incompatible.

There's no easy answer to versioning APIs. We keep a version per-user, which reflects the state of the API the first time they made an API request. This version isn't taken into account when we add a new feature or non-breaking change (i.e. you'll always be able to use new features, regardless of what version you're on).

Whenever we make a backwards-incompatible change2, however, we bump the current version of the API (so that any new users will see the "new" changes) and take the legacy user's version into account in the relevant API code paths.

Users can choose to upgrade their versions in the dashboard (after reviewing the details changelogs, of course), or can send a version override header in any API request to test the behavior of a specific version.


If you have any questions, feel free to email or tweet at me. Thanks for reading!


  1. I'm not saying that Stripe is not going to do these particular things in the future, but it's not feasible in general to try to accommodate everyone's use case.
  2. We are usually hesitant to do this.

Credit for various parts of the presentation content go to Greg Brockman, Sidd Chandrasekaran, Evan Broder, and Ross Boucher. And of course, credit to everyone at Stripe for actually doing the things I outlined in the talk.