← Writing

Building a booking system where Stripe doesn't exist

I own hotels in northern Pakistan, and I'm building their booking platform myself. No Stripe, flaky mountain internet, WhatsApp as the real communication channel — payment infrastructure looks very different from outside the countries it was built for.

On this page

Most of what’s written about payments engineering starts from an assumption so deep it’s invisible: that Stripe is available. Add the SDK, handle the webhook, done — payments are a solved problem.

I run engineering for clients across the US, Europe, and the Gulf, where that assumption holds. But I also own hotels in northern Pakistan, and I’m building their booking platform myself — a booking website and back office, TypeScript end to end, Next.js and Postgres. In Pakistan, Stripe does not operate. The most-documented payment path in software simply isn’t on the menu.

Building for my own business, in my own market, has taught me more about payments than any integration guide — because it forced me to see how much of “payments best practice” is actually “US/EU market assumptions.”

The payment stack when there’s no default

With no Stripe, the payment section of the architecture stops being one integration and becomes a portfolio:

  • Local gateways — Safepay, PayFast, JazzCash — cover online payment. Each has its own integration quirks, its own settlement behavior, its own reliability profile.
  • Direct bank transfer — a first-class option, not a fallback. A large share of guests are most comfortable transferring to an account and sending the receipt.
  • Pay at the hotel — still, honestly, the channel a big portion of guests prefer, and pretending otherwise in the product would just mean abandoned bookings.

The design consequence: the booking flow can’t be built around “payment succeeded → booking confirmed” as a single synchronous moment. A booking might be confirmed pending a transfer, confirmed with payment on arrival, or paid online. Payment state and booking state are related but separate machines, and the back office has to let staff resolve the in-between states a card-only system never has.

And one feature I’m genuinely fond of, because only an owner would prioritize it: an admin toggle to hide the online-gateway checkout entirely. When a gateway is having a bad week — and they have bad weeks — I don’t want guests hitting a broken checkout and bouncing. Flip the toggle; the flow gracefully narrows to transfer and pay-at-hotel until the gateway earns its place back. Availability of a payment method is a runtime operational decision, not an architectural constant. Stripe-land never taught me that.

WhatsApp is the real front end

The booking website takes the booking. But the relationship happens on WhatsApp, because in Pakistan WhatsApp is the communication layer — confirmations, “what time is check-in”, “send me the location”, “we’re running late.”

So the system is WhatsApp-first by design: it’s the primary channel for guest communication around a booking, not a nice-to-have notification target after email. Email exists; it’s the formality channel. Designing this honestly means accepting that some of the conversation will always be human and unstructured, and making sure the system supports the staff having it — rather than trying to force every interaction through forms.

The register is the law

Pakistani hotels keep a guest register with identity documents — CNIC for domestic guests, passport details for foreigners. That’s not a product decision; it’s a requirement, and any hotel software built for this market that treats identity capture as an optional field misunderstands the job.

So check-in in the back office captures documents as a first-class step. It’s a good example of a category I’d flag for anyone building for an unfamiliar market: every market has these load-bearing local requirements that no global SaaS template includes, and they’re exactly the features that make locally-built software worth building.

Designing for mountain internet

The hotels are in the mountains. Connectivity is real but moody — and the people using the back office are staff mid-shift, not engineers with fiber.

That shapes the engineering in unglamorous ways: assume requests will fail and make retrying safe; keep the critical staff workflows light; never let a lost connection eat data someone typed. None of this is exotic engineering — it’s ordinary robustness work, promoted from “nice to have” to “core requirement” by the environment. Flaky-network resilience is a feature you can’t retrofit convincingly; it has to be a design assumption from the start.

The dual-hat advantage

Here’s what building for my own business has actually given me, beyond a booking system: I am the client, the operator, and the engineer at once — and the feedback loop between those roles is brutal and immediate. When a design decision creates work for front-desk staff, I hear about it at family dinner, not in a quarterly review.

That loop is where things like the gateway toggle come from. No requirements document would ever contain it. It exists because I’ve been there when the gateway was down and watched what it did to bookings.

It’s also sharpened how I work for clients: I now actively hunt for the constraints that are obvious to operators and invisible in specs — the local law, the unreliable dependency, the channel users actually live on. Every market has its version of “Stripe doesn’t exist here.” The interesting engineering starts right after that sentence.

← All writing Book a call →
Book a call → WhatsApp