Skip to content
Build in Public

OTP without accounts: the booking flow nobody talks about

Every booking tool I've ever used asks me to make an account before I can do the one thing I came to do. I have always hated this. You want to book a 20-minute…

SD
Shubham Datarkar
· 3 min read
Updated

Every booking tool I've ever used asks me to make an account before I can do the one thing I came to do. I have always hated this. You want to book a 20-minute call and suddenly you're choosing a password, verifying an email, agreeing to terms, and by the time you're done you've forgotten why you came. The signup wall is a tollbooth on a road that should be free.

Book A Sloth's entire promise dies at that wall. So today I built the thing that lets me tear it down: OTP booking. A guest proves they're real with a one-time code, books, pays, and leaves — and never makes an account. This is the flow nobody writes blog posts about, and it's secretly one of the most important things in the whole product.

The flow on paper is simple. Guest picks a slot. Enters their name and email. We email them a six-digit code. They type it back. The code checks out, the booking gets created, the payment goes through. Four steps, no password, no account, no toll.

Simple to describe. A minefield to build correctly. Let me walk through the mines.

Mine one: where do you store the code? My first version — and I'll be honest because that's the deal with this series — stored the OTPs in memory. Just a little in-app list: email code. It was fast to write and it worked instantly on my machine. I felt great. (Spoiler for a future post: this decision detonates in production and costs me a day. I'll tell that story when it happens. For now, just know past-me was smug.)

Mine two: the code itself is sensitive. A one-time code is a key to someone's booking. So I'm not storing it as plain text. I'm hashing it — running it through bcrypt — so that even if someone somehow saw my database, they'd see scrambled nonsense, not usable codes. If you store secrets, you store them hashed. There's no excuse not to, and "it's just an OTP" is exactly the attitude that leads to incidents.

Mine three: abuse. An OTP system is a gift to bad actors if you don't guard it. What stops someone from requesting a thousand codes and spamming people's inboxes? What stops someone from guessing codes a million times until one hits? So from the start I designed in the boring-but-essential guardrails: a limit on how many codes you can request, a limit on how many times you can guess, and a lockout window if you fail too many times. You build the locks at the same time as the door, not after someone walks in.

And underneath all of it, today I finally laid down the bones of the bookings table itself — the place a confirmed booking actually lives. Who booked, what service, what time, what status. It's the center of gravity for the whole product, and until today it didn't really exist. Now it does, even if nothing's writing to it properly yet.

Here's the thing I keep thinking about. This entire feature exists to remove a step. All this work — the codes, the hashing, the rate limits, the table — so that a guest sees fewer screens, not more. The best engineering is often invisible. Nobody booking through Book A Sloth will ever think "wow, what a nice OTP system." They'll just notice they booked something in thirty seconds without making an account, and they'll feel lightly, pleasantly surprised. That surprise is the product. The work is the iceberg under it.

The flow runs now, end to end, on my machine. Pick a slot, get a code, verify, booking created. It feels like magic.

It feels like magic specifically because I haven't deployed it yet. Production is where magic goes to find out it's made of in-memory lists.

That's a story for a few days from now.

by Shubham DatarkarBuild in Public

Reactions

How was this article?

Newsletter

Never miss the next one

Get the latest playbooks, build logs, and the occasional unpublished idea straight to your inbox. One signal a week — no noise.