Designing APIs with Chris Bell from Knock.app
Chris Bell's rule for API design at Knock: write the documentation before writing a line of code. APIs are effectively immutable once shipped, and Stripe's date-based versioning — which he calls the best in the industry — is still a huge amount of effort most companies can't replicate.
Chris Bell is the founder of Knock, notification infrastructure that powers cross-channel notifications — email, push, SMS, Slack, and real-time in-app feeds — for products like Vercel's deployment alerts. Knock started by writing documentation before any product existed at all.
We get into his documentation-first API design process, why he thinks about interfaces in TypeScript even for a company whose backend runs on Elixir, and the very different sales motion required when your buyer is a central platform team who then has to convince other product teams to actually adopt what they've bought.
The Q&A below is experimental — extracted from the episode transcript with AI. If you spot a mistake, let us know at jack@scalingdevtools.com.
What does Knock actually do, and why call it infrastructure rather than just an API?
Knock is notifications infrastructure — we see the value extending well past a plain API surface. A good example is powering in-app notification feeds, like the one in Vercel: when your deployment fails, you see that notification pop into your feed in real time, and all of that real-time behavior is handled behind the scenes by Knock. Beyond in-app, we also handle email, push, SMS, and chat apps like Slack, plus a lot of complex behavior like batching — if three guests join your Riverside call at once, you want one notification about three guests, not three separate ones, and that logic lives in Knock rather than something every team has to build themselves.
How do you actually approach designing a new API primitive?
We start by writing the documentation before writing a single line of code, then design the API around that documentation, and put it in front of customers or prospects to get input before building anything. A lot of this is borrowed from Stripe, who we constantly cite as doing this exceptionally well. For our schedules API — essentially a managed cron job for triggering notifications on a recurring basis, executed in each user's own time zone — we wrote guides showing how someone would actually use the feature in anger, iterating on the API design until it felt genuinely ergonomic. The reason this matters so much is that APIs are extremely hard to version well once shipped. Stripe's date-based versioning is probably the best in the industry, but building something like that yourself is still a tremendous amount of effort — so we'd rather be methodical about getting the design right the first time, matching it stylistically to our existing APIs, than lean on versioning to bail us out later.
What's the actual first step, concretely, when you're about to design something new?
Everything starts with a positioning statement in our product brief — what are we shipping to market today — followed by a problem statement framed as a user story: as a user, I don't want to write cron jobs, because they're problematic, they fail often, and it's a part of my stack I don't want to manage myself, so it should be offloaded to Knock. From there we write the external-facing guide as if the feature already existed, walking through exactly how someone would set it up and use it for their use case. Sometimes we write customer-specific versions of that guide for a prospect with a concrete need, which lets us sketch the API, see what it would feel like to actually use, and check whether it genuinely solves their problem before any code exists. Sometimes that draft guide becomes the real documentation we ship.
You mentioned designing in TypeScript even though Knock's backend runs on Elixir. Why?
Not every customer uses TypeScript, but it's a genuinely lovely place to start designing an interface — you can think concretely about the type signature, what properties it takes, whether filtering options make sense. It's usually pretty easy to work backward from that to the REST API sitting behind the SDK method, rather than starting with the REST design directly. The reality is you can hide fairly bad RESTful design behind a nice SDK anyway, and the SDK — the code sample with a language selected on a docs page — is the actual surface area most customers interact with and think about. I'm not looking at how the nouns and verbs of a REST endpoint are constructed when I'm on an API reference page; I'm thinking about what a block of SDK code feels like sitting in my own codebase.
How do you actually gather feedback on an API design before shipping it?
Usually a Notion doc — we clone it per customer we want feedback from, send a customer-specific version, and let people comment directly, then collate that into the next iteration. We started Knock by literally writing documentation and sharing it before there was any real product, and that's remained a long-standing principle for how we build collaboratively. It's not rigorously data-driven — it's not 'we got seven comments so this must be great' — it's closer to vibes, but it reliably helps refine the messaging. If someone doesn't get a feature from reading the doc, the doc is wrong, or the value proposition itself is wrong. For a devtool, you're constantly trying to explain concepts to developers precisely enough that they can act on them, so that clarity work matters as much as the API shape itself.
Knock is a flexible set of primitives rather than one narrow tool. What's the specific challenge that creates for documentation?
The hardest part of a flexible product is helping someone map their specific problem onto your domain — how does what I'm trying to do translate into Knock's workflow engine, its logic, its templates, its channels? You have to root the person doing the implementation in your nomenclature so they know where to start and how to reason about the system. The feedback loop for us is relentless: as soon as a customer stumbles in a support channel — 'I'm trying to do this, but I don't get how it works' — that has to turn into a documentation PR the same day. Often the fix isn't the API itself, it's that the language explaining a concept assumed prior knowledge, like assuming someone already knows what a cron job is.
How do you avoid overwhelming a new user with the full surface area of a flexible product?
You have to layer complexity in gradually — a 'ladder of success' where someone can get started simply, but knows where to reach when they hit a more advanced need. WorkOS does this really well: their docs are organized around a specific use case, like implementing directory sync as an IT admin's list of users, and layer in complexity progressively rather than dumping the entire topic on you at once, like a choose-your-own-adventure. We have a preferences model — the settings someone can turn on and off for their notifications — that's genuinely flexible but hard to grasp in one page; really it should be several pages that each guide you toward a specific, more contained job to be done, with the advanced fine-grained control available once you need it. Vercel uses that advanced layer to let you say 'notify me at 125% of my usage budget' — a fairly sophisticated use of our preferences model under a very simple-feeling feature.
Selling to a central platform team is different from selling to one product team. What makes it harder?
You're one step removed from the team actually doing the implementation. Instead of directly onboarding the team building with Knock, you're setting up a platform team to then enable and educate several other product teams — helping them migrate their emails to Knock, set up reporting, and so on. It becomes almost educational: what materials does that platform team need to succeed with their own internal customers, who are other product teams, who in turn serve the actual end users. The real risk is spending a lot of effort getting the platform team set up, having them pay for the service, but the actual product teams never migrate off their old setup — two years later someone asks why the company is still paying for this. Success for the platform team usually looks like a concrete adoption target, like 70% of notifications running through the new service after a year, and it works much better when we're actively present with them in Slack, helping drive that adoption rather than assuming it happens on its own once the contract is signed.
Is it better to have pull from an individual product team, rather than just top-down platform-team buy-in?
Yes — the driver for wanting to replace a service matters a lot. Engineers are going to engineer: platform teams sometimes want to replace something just because there's a new, more interesting way to build it, and that's a much weaker foundation than a product team that's driven by wanting a new capability they genuinely couldn't offer before, like an in-app notification system or better in-product messaging. When the demand for adoption comes from a product team's real need, it spreads outward on its own. The other failure mode is a platform team coupling adoption to some other internal infrastructure project — 'we want a Kafka event stream before anyone can use this' — which just leaves you stuck in an indefinite waiting period.
How do you position Knock against marketing-oriented tools like OneSignal or Braze, which are usually bought by marketers?
Most of those tools are owned by marketers and built for broad customer engagement and messaging. We sit specifically in transactional notifications for products — think a dating app sending a push notification and email the moment someone gets a match — which means our sale is driven primarily by product and engineering, not marketing. There's a messy middle ground, lifecycle marketing, that's contested between product and marketing ownership, and that's where we see real expansion opportunity — more customer-centric messaging that's native to the product and built on the same developer experience: React components you can drop in, strong documentation, logging and observability that feel like you built it in-house. The uncomfortable truth about most marketing tools is they're bought by marketers but implemented by engineers, and engineers want the right tool — that's exactly the developer-champion dynamic that makes a product genuinely sticky over time.
How do engineering teams actually justify the cost of buying a service like Knock, versus building it themselves?
Selling pure engineering-hours-saved is thin — you need to sell the full package: infrastructure cost saved, the ongoing keep-the-lights-on maintenance burden avoided, and critically, the new capabilities unlocked. Anyone could technically build a Slack integration, but with Knock's React components you can have one running in an hour, and that's really just one piece of a much bigger multichannel notification story you now get access to. I like to frame it as 'we're shipping your notification roadmap' — the things a product team's roadmap kept getting deprioritized in favor of whatever big customer request came in that quarter. It's ultimately about the capabilities you're enabling, not just the hours you're saving, especially now that budgets for cloud tools are getting scrutinized much more closely than they used to be.
What's your one takeaway for people building APIs?
APIs are effectively immutable — treat them that way, do real design work up front, and it's genuinely okay to stay in the design phase for a while before writing code.