831 Project 831

Side project · Co-founder & design engineer · Jamshedpur, India · 2026

A venue that books itself inside WhatsApp.

Project 831 is a two-court pickleball venue I co-founded and run. I designed and built the system it runs on, from booking inside WhatsApp to a desk dashboard and a kids' programme that renews itself. I also wear the other hats: the money, partnerships, brand, marketing and the edits.

₹5.6Ltaken through the system since May
15→74%court bookings made without the desk, May → Sep
69%of people sent the booking flow went on to book
1,509commits in 200 days, most of them mine

Every hat · co-founder

The software is one job of many.

I run the money, negotiate the partnerships, build the brand, market it and cut the videos. Each one shaped what the product needed to do.

Money & deals

Every rupee and every negotiation

Pricing, settlements and the deals behind them, from the coach's revenue split to brand partnerships.

Partnerships

Four brands for one tournament

I pitched and closed the 831 City Open's partners, with a deck built for each brand.

Brand

831 reads as "I love you"

The pincode is the name. A heart hidden in the 3, a terracotta palette and Dalmo, our mascot, for partner creatives.

Growth

Found on Google, run from code

SEO with structured data on project831.in, a Google review funnel, and Meta and Google ads I run myself through the API.

Social

Instagram, edited by me

Close to 450 followers, and I edit every reel.

Build

The engine underneath

The booking system, the website and the dashboards: the rest of this page.

Poster for the 831 City Open, the Jamshedpur Pickleball Championship, 4 and 5 July 2026 in Sonari, with a ₹30,000+ prize pool.

831 City Open · 4–5 July 2026

A city championship, run on our own system.

78entries across 5 categories
₹30K+prize pool

Registration, payments, draws and the schedule ran on the same engine as court bookings.

AiravatBall
Fast&UpHydration
SkinInspiredSunscreen
KheloMorePartner
An iMovie timeline for the Off-Screen Club self-defence reel: titles, cuts, a music bed and voice, 1 minute 38 seconds.
The edit. An Off-Screen Club self-defence reel in iMovie: titles, cuts, two music beds, 1:38.
Co-branded creative: Dalmo the elephant mascot holding a Fast&Up bottle courtside, Official Hydration Partner of the 831 City Open.
The brand at work. Dalmo for Fast&Up, our hydration partner at the City Open.

Booking · real screenshots, 15 October

Six taps from “831” to a confirmed court.

No app, no website, no login. A customer types the venue's name into WhatsApp and books a court without leaving the chat.

WhatsApp chat: the customer types 831; Project 831 replies with prices, location and three buttons: See slots and book, Call us, FAQs.
01 · HelloPrices, location and three choices, before anyone asks.
The bot replies with Check available slots and a Pick a slot button that opens a WhatsApp Flow.
02 · Open the flowOne button opens a native form inside WhatsApp.
Flow screen Plan your booking: date preselected as today, time of day Morning or Evening, and duration 1 hour, 1 hour 30 minutes or 2 hours.
03 · WhenToday and the next open session are already ticked.
Flow screen Pick a start time: a list of one-hour windows from 4 PM, most marked Only 1 court left for this hour.
04 · Which hourOnly times that are actually free, live from the engine.
Flow screen Booking summary: Thursday 15 October, 6 to 7 PM, 1 hour, 700 rupees total, and a Confirm booking button.
05 · CheckThe price shown is the price charged; one engine quotes both.
Confirmation message: you're booked at 831, with date, time, kit, pay 700 rupees at the venue, address, a maps link and a no-show rule.
06 · BookedConfirmed in the same chat, with the map and the house rules.
People sent the booking flow, 13 June – 14 October 2026, and how far they got.

Each version of the flow asks for less.

v4 let you pick several slots. v5 added a kit screen. v6 asks one “When?” question, moves duration to the slot screen and shows no price copy until the summary.

Meta integration · WhatsApp Cloud API + Flows

WhatsApp is the front door, so I built it like one.

The bot, the booking Flow, the confirmations and the marketing all run on Meta's WhatsApp Cloud API, wired straight to the booking engine.

Meta

Cloud API

Signed webhooks in; templates and messages out.

831 engine

Webhook + Flow endpoint

Encrypted data exchange returns live slots and prices per screen.

Data

Postgres

Bookings, money, flow events. Row-level security on every table.

Flows

An encrypted form inside chat

RSA-OAEP + AES-GCM on every screen. The first screen ships with its data, so it opens with no server round trip.

Flow studio

A Flow builder in the dashboard

Draft, preview, publish and promote Flows through the Graph API without opening Meta's tools.

24-hour rule

Confirmations that always land

Approved templates by default, a 30-minute safety margin on the window, and a retry when Meta refuses.

Two numbers

Marketing can't break login

Promotions go out on a second number, so a block or report never touches the number that sends login codes.

Funnel

Every abandoned booking is visible

Seven stages are logged per person; the desk can nudge a drop-off with one tap, inside the window only.

Consent

Utility and marketing kept apart

Opt-ins stored with evidence, a Stop promotions button on every campaign, and sends paused when Meta rate-limits.

Broadcasts screen: choose an approved Meta template by category, add context, select eligible recipients, live preview on the right.
Mock dataBroadcasts. Campaigns go out only through approved templates, and only to people whose consent covers that category.

Payments · Razorpay, inside WhatsApp and on the web

The data said: take the money first.

Booking was free, so skipping it was free too. Bookings with nothing paid kept getting cancelled, and some people just didn't turn up. So the engine learned to ask for money before it holds a court.

6×more cancellations when nothing is paid up front
0no-shows on a prepaid booking
₹23,250lost to customer cancellations and no-shows on unpaid bookings
≈₹21,600of that recoverable at the prepaid cancellation rate

What each finding turned into

12 MayRazorpay pay links inside the booking Flow
7 JunCustomers who ghost get flagged “pay first”: no money, no booking
14 JunRazorpay checkout for tournaments, then the website, events and the kids' club
9 AugWeekend slots need a 50% part payment
29 AugPay without leaving WhatsApp: a native checkout card in the chat
Hold

Court held 15 min

A pending row blocks the slot in Postgres; nobody else can take it.

In-chat pay

Review and pay card

Meta's checkout, Razorpay underneath. UPI or card without leaving the chat.

Confirm

Checked twice

Meta's payment status, re-checked with Razorpay: captured, INR, same amount. Then the booking confirms.

Everywhere

One payment layer, every product

Courts, tournaments, events, Off-Screen Club memberships and enquiries all pay through the same Razorpay orders and links.

Part pay

The venue sets the rules

Deposit percentage, which days need prepayment, and per-customer flags: pay first, or trusted to pay at the venue.

No double charge

Reference before request

The order reference is stamped on the booking before the card is sent. If a send fails silently, the hold stays and no second link goes out.

Webhooks

Signed, then believed

HMAC-SHA256 on the raw body with each venue's own secret. Replays are ignored; late money is flagged to the desk, never lost.

Secrets

Keys the dashboard can't read

Each venue's Razorpay keys are encrypted with AES-256-GCM and a rotating keyring. The dashboard can write them, never show them.

Second gateway

HDFC behind a switch

Web checkout can route to HDFC SmartGateway per venue. Built and tested with a ₹1 harness; waiting for launch.

Prepaid bookings have never been a no-show.

The desk · bookings dashboard

The desk stopped being the way in.

Self-serve bookings went from 15% to 74% of the month in four months. The desk now reads the day instead of typing it.

Entered at the deskBooked by the customer (WhatsApp, website)
Bookings day view: courts as columns and hours as rows, with paid, due, coaching blocks and empty slots priced by the hour, plus the day's expected revenue.
Mock dataOne day, one screen. Paid, due, blocked or empty with its price, and what the day is worth at the top.

Off-Screen Club Juniors · kids' fitness, run with a coach

A weekly programme that runs, renews and splits itself.

Saturday and Sunday batches for children, run with an outside coach. Parents sign up on the website or at the desk; the system handles the month after that.

Juniors money collected per month. October is the first half only.
₹1.21Lcollected since July
48children from 36 families
40paid membership months
117attendance marks, taken by the coach's team

Who keeps what

Split after shared costs. Both sides open the same accounts page, every line needs the other side's tick, and a settled week is frozen by the database.

Three plans, one register

₹2,999 for every session in the month, ₹1,999 for any four, ₹599 for one. Memberships stay on the register until someone stops them, and attendance is the record of what was used.

The register: 11 children to chase, cash not collected, a warning that no attendance was taken since 8 August, and rows with Take cash or Renew as the next step.
Mock dataThe register. It opens on who to chase and names the next step for each child: take cash, renew, or nothing.

Renewals chase themselves

3 days before“Month ends Friday” with Renew and Call me buttons
The day it endsReminder; the child stays on the register as unpaid
3 days afterSecond nudge
10 days afterLast nudge, then a person calls

Planned every morning at 7, sent between 9 AM and 8 PM, at most two a week per family, cancelled the moment the family pays. Each sequence can run off, for review, or automatically.

Event accounts: money in, costs, still to collect and left to share, with each partner's collected, holding, share and entitlement, and who owes whom.
Mock data, 60/40 exampleSettling up. Who holds the cash, who is owed, and one button to close the week.
Collaborators

One grant opens the programme

The coach gets a collaborator role that starts with zero access. A grant on the programme opens every plan and batch inside it.

Money rights

Given per person, per programme

The coach's team takes cash at the venue and records it. Prices, refunds and deletes stay with the venue.

No login

Attendance from a link and a PIN

A signed WhatsApp link opens one programme's register for 60 days, never shows parents' numbers, and dies when the key rotates.

From WhatsApp

The coach works in chat

Enrolments and payments come in through a desk Flow and pass the same rules as the dashboard.

APIs · 12 serverless functions, 6 outside services

One engine, many doors.

WhatsApp, the website, the dashboard and the voice agent all call the same booking API. No business rule exists twice.

EndpointServesDetail that matters
/api/webhookEvery WhatsApp message, status and paymentSignature checked on the raw body; duplicates claimed once
/api/flowThe booking Flow's screensEnd-to-end encrypted; slots and prices from the live engine
/api/bookingsDashboard and website bookingsPublic reads and creates rate-limited per visitor
/api/eventsProgrammes, registrations, attendance, collaboratorsThe coach's WhatsApp entries call it in-process with his identity
/api/razorpayPayment webhooks for Razorpay and HDFCNever trusts a callback; re-reads the payment first
/api/admin-dataThe dashboard: money, staff, messages, settlementsAbout 36 resources behind role and grant checks
/api/cronReminders, follow-ups, briefings, renewalsSix schedules across every venue on the platform
/api/v1The voice agentPer-venue keys, rate limits, idempotent bookings
Meta Graph

Messages, templates, Flows, payments

API version pinned in code, with an alarm 90 days before Meta retires it.

Razorpay · HDFC

Three payment rails, one settlement

Checkout, payment links and in-chat WhatsApp Pay all finish in the same code.

Multi-venue

Built to host more than one venue

Each venue's keys are encrypted at rest with a rotating keyring; webhooks resolve the venue from the URL and the number.

Also: Postgres with deny-all row-level security, web push for the desk, Vercel cron. Tests run behind a network guard, so no test can reach a real service.

Security · built in, not added later

Locked down like it holds real money. It does.

Every request proves who it is and which venue it belongs to before it gets near the data. The browser never talks to the database at all.

1 · Browser

Holds a key it can't read

The session sits in a cookie scripts can't touch. Requests from other sites are refused.

2 · Signed session

Checked on every request

Signed, compared in constant time, and re-checked on the server each time, so sign-out everywhere is instant.

3 · Venue check

One session, one venue

Built for many venues. A session is bound to one, and editing the URL can't cross into another.

4 · Database

Server only

No table access from the browser, row-level security on, backed up every day.

The path every dashboard request takes. Each check fails closed: if it can't be sure, it says no.

End-to-end encrypted booking

The booking form inside WhatsApp is encrypted end to end: RSA-OAEP key exchange, then AES-GCM on every screen.

Signed webhooks

WhatsApp and payment callbacks must carry a valid signature. A payment that doesn't match its order changes nothing.

Secrets encrypted at rest

Each venue's WhatsApp, payment and voice keys are sealed with AES-256-GCM under versioned keys that can be rotated.

Limits that fail closed

Sign-in, WhatsApp codes and resets are rate-limited across every server. If the limiter is down, it refuses. It stores hashes, never a phone or IP.

Links instead of accounts

Coaches mark attendance from a signed link plus a PIN. Rotating one secret revokes every link at once.

3,100+ tests on every change

They run with the network blocked, so no test can touch production. CI also stops real phone numbers or a venue-boundary slip from merging.

Also: a public security contact for responsible disclosure, customer images served through the server so no token reaches a page, and an offline cache that never stores private responses.

Voice agents · two attempts, both parked

We tried to answer the phone with an agent. Twice.

Plenty of customers still prefer to call, so we built a voice agent that could book. It worked; it wasn't worth keeping. What lasted is the API it forced us to build.

Attempt 1 · 26 May – 5 June

Our own agent on WhatsApp calling

  • Meta WhatsApp calling → a Node server in Mumbai
  • Sarvam AI for speech, model and voice; English, Hindi and Hinglish
  • Could check slots, book, cancel and reschedule
  • Interruptions handled; worst-case reply cut from 10 s to 3 s

28 calls and 12 test bookings in 72 hours. Then a review found it fragile: booking logic copied outside the app, calls held in memory, a reschedule that could lose a booking.

Attempt 2 · 28 July – early September

A voice platform, our API in charge

  • Dograh as the voice layer; the app keeps every booking rule
  • Narrow tool API: venue info, dates, slots, the caller's bookings, book, cancel
  • Idempotency keys, confirmation sent once, caller sees only their own bookings
  • 152 example conversations prepared for tuning tone

Booked end to end in testing, never with a real customer. The WhatsApp-to-phone route was never proven; voice was switched off in October.

The lesson: buy the voice, own the booking rules.

Rebuilt on coss ui · open source, runs in the browser

The same product, on Cal.com's own components.

The booking page, part payments, the 15-minute hold and the desk, rebuilt end to end with all 55 coss ui components, installed with the shadcn CLI and unmodified. Demo data only.

Live

rkj-builds.github.io/slot-picker

Book a court, then watch it land on the desk as held.

Code

github.com/rkj-builds/slot-picker

React 19, TypeScript, Base UI, Tailwind v4. Headless primitives of my own for slots, recurrence and time zones. 433 tests with accessibility checks.

Try

The Demo menu

Jump to any of 74 states: part payments, a declined card, a slot taken mid-checkout, empty and error states. Then the Primitives page and ⌘K on the desk.

How it was built · 28 March – 14 October 2026

Designed and built by me, with Claude Code.

68% of commits co-authored with Claude Code. I specify and review; the machine types.

Commits per week, 28 March – 14 October 2026.
Stack

React 19, Vite PWA, Postgres

12 serverless functions on Vercel, a separate Next.js marketing site, no component library.

Safety

Production data is never test data

3,100+ tests run offline; a mock mode answers every API call in the browser; a PII scanner blocks real phone numbers in the repo.