the baja app

How We Replaced Paper Vouchers With a QR Code a Partner Can Actually Verify

The Baja App's Bilingual Tourism Membership Platform

The Objective

Visitors to Baja arrive without a trustworthy bilingual guide to the businesses around them. The businesses have the opposite problem: a restaurant, an excursion operator or a fishing charter can offer a visitor a discount, but a paper voucher cannot be checked, cannot be limited to one use, and cannot tell the owner who redeemed it. We built three connected products on one backend, a Tourist app, a Partner app and an admin web panel, with a freemium membership unlocked by in-app purchase and a one-time QR code that the partner scans and the server validates.

Service Tags

Cross-Platform App Development Web Application Development Backend Development Product Design

Industry Tags

Tourism Hospitality Membership Platform

Tech Stack

React Native Vercel Web SPA REST middleware REST middleware SQL Firebase Apple and Google in-app purchase Node 20

The Impact

1
Redemption per QR code, validated server-side
The code is generated once, scanned by the partner, and checked by the server rather than by eye.
3
Connected products on a shared backend
Tourist app, Partner app and admin web panel read and write the same records.
8
Partner categories onboarded through one flow
Restaurants, excursions, hotels, rentals, fishing, services, retail and sports.
2
Languages carried through every surface
English and Spanish across both apps, the admin panel and the landing page.
The Client

A Region Full of Businesses With Nothing to Put a Visitor In Front Of

John Charos and Adam J. Moss came to us with a discovery and membership platform for the Baja region, built for two audiences at once. Visitors who need to know which businesses are worth their time and money, and local partners across eight categories who want a way to reach those visitors with an offer they still control.

The brief was bilingual from the start. In Baja that is not a localisation phase bolted on at the end. A platform that works in English and fails in Spanish only serves half the transaction.

The Problem

An Offer You Cannot Verify Is an Offer You Cannot Control

A visitor to Baja has no single trustworthy source for where to eat, what to book and who to hire. Recommendations come from whoever is nearby, in whichever language they happen to speak, with no way to tell a curated business from an advertised one.

The partner side is harder. A local business that wants to offer a member discount has historically had one instrument: a printed voucher. A voucher cannot be checked against a real membership, cannot be limited to a single use, and leaves no record of who redeemed it or when. The business absorbs every discount it cannot verify, which is why most of them stop offering one.

And connectivity across the region is uneven. An app that assumes a signal at the moment of redemption will fail at the exact point where the partner is standing in front of the customer.

baja-app
Our Approach

We Designed the Redemption Before the Discovery

The obvious build order is the tourist experience first. We went the other way, because the redemption is the moment the platform either earns a partner or loses one, and every other decision, membership tiers, offer configuration, partner onboarding, has to serve it.

One-Time QR With Server-Side Validation

The tourist displays a code, the partner scans it, and the server decides whether it is valid. Validation never happens on the device, because a redemption a partner can approve locally is a redemption a screenshot can defeat. The code is single-use, so the same offer cannot be redeemed twice from one membership.

A Scanning App for People Standing at a Counter

Partners are standing at a counter or on a boat, so the scanning experience had to be a phone app rather than a web login. The same app carries listing management, offer configuration and scan history, which means the person redeeming the offer is the person who can see how many have been redeemed.

Offline Caching on Both Clients

Local caching and sync were built into the Tourist and Partner apps rather than added later. A visitor browsing guides on a beach with no signal still sees the guides, and a partner who scans during an outage still has the scan reconciled when the connection returns.

Bilingual Through the Data Model

English and Spanish run through the apps, the admin panel and the landing page. Curated guides and partner listings carry both languages at the record level, so a partner onboarded in Spanish is discoverable by a visitor browsing in English without a translation step in between.

Freemium With the Membership as the Gate

Discovery is open and redemption is the paid boundary. Single- and duo-user premium plans run through Apple and Google in-app purchase, which keeps the platform inside store billing rules and gives the partner confidence that a scanned code belongs to a paying member.

What We Built

16 Modules Across Three Products

Each module maps to a product and a role. All three read from the same backend.

Tourist app (iOS + Android)
Partner app (iOS + Android)
Admin web panel
How It Was Built

One Backend, Three Clients, and a Validation Path Proven First

React Native carried both mobile clients so the Tourist and Partner apps could ship to two stores from one team, with the admin panel as a web SPA against the same REST middleware. That middleware holds the business logic, authentication, session management and caching, which keeps the three clients thin and keeps redemption rules in one place rather than three.

The SQL schema was scoped before the clients were built. Users, listings, offers, subscriptions and audit logs all had to relate cleanly, because a redemption touches every one of them at once and a disputed scan is answered from the audit log rather than from memory.

Firebase handles push, in-app notification and transactional email. In-app purchase runs through Apple and Google billing, validated server-side, so membership state is a property of the backend rather than a claim the device makes about itself.

Outcome

A Discount the Partner Controls and the Server Proves

A member finds a partner through a curated bilingual guide, opens an offer, and shows a code generated for that offer and that membership. The partner scans it in their own app and the server confirms or rejects it. The redemption is recorded against the member, the offer and the partner, and the code cannot be used again.

Partners configure their own listings and offers and see their own scan history, so the discount they extend is one they can measure. Administrators curate guides, onboard partners across all eight categories, configure offers and ads, and read platform analytics from one panel.

The platform is at MVP. These describe the system as built rather than results in market, and this section needs rewriting with real figures once it has launched.

Testimonials

“Our partners had all stopped offering discounts, and every one of them gave the same reason. They could not tell a real member from a photocopy. The scan is the product. Everything else is how people find it.”

Founder

The Baja App

Running a membership or loyalty offer that partners cannot verify at the point of redemption?

We have built the validation path before, and we know it belongs at the start of the build.

Start the conversation