Twelve Features in Eleven Weeks, Built for the Restaurant Floor
A tour of twelve PayTable features shipped between June and September 2026, each one built to remove a specific friction we saw at the terminal, the pass, or close.
By Igor Riera
Between June 25 and September 11, 2026, we shipped twelve customer-facing features to PayTable, the QR ordering and payments platform we run for restaurants in Mexico — plus a new bank-transfer payment option that ships opt-in, which we’re covering in its own post. Every one of the twelve started from the same question: what’s slowing down a specific person at a specific point on the floor — the terminal, the pass, close. Some came directly from restaurants we work with; others came out of our own testing and product reviews. All twelve are documented in bilingual Spanish and English release notes on our site.
We group them here by where they land: selling and menus, paying and closing, and running the shift.
Selling and menus
Packages & scheduled orders (June 25)
Floor problem: combo pricing and pre-orders needed real rules, not workarounds — flat or base-plus-upcharge pricing, selection groups with min/max picks, and a schedule that respects when the kitchen can actually cook.
What we built: components keep their own modifiers, a modifier price can be overridden inside a single package, and time windows can run overnight. On the ordering side, a guest picks “as soon as possible” or a slot inside open hours for pickup or delivery, and the kitchen gets tickets released just-in-time based on prep time, or immediately, printed “PROGRAMADO HH:mm.” Prep time, booking horizon and slot interval are all configurable, per restaurant or per section. The packages half came directly from a customer need.
Engineering detail: instead of adding a new scheduler for just-in-time release, we reused the existing course-timer sweep that already runs across the system — and this release is also where order-time enforcement of restaurant open hours began.
Dynamic package pricing & happy hour (July 22)
Floor problem: running a real promotion — say, 50% off wine during happy hour — shouldn’t require anyone to do the price math by hand.
What we built: “sum of selected” pricing with an optional base, per-item pricing inside a package as flat or a percentage of catalog (percentage tracks catalog changes automatically), modifier and option price adjustments, a live preview that matches the actual charge, and schedules by day of week in the restaurant’s own timezone, including overnight windows.
Engineering detail: a Friday 22:00–02:00 window is gated by its start day, so it correctly stays live until 2 a.m. Saturday rather than cutting off at midnight. A misconfigured schedule fails closed — the package stays hidden — rather than staying visible at the wrong price.
Section types (July 22)
Floor problem: “Table 4” doesn’t mean anything at a hotel counter or a delivery-only kitchen.
What we built: every section is now typed as Tables, Room, Pickup, Delivery, or Counter, and the guest app’s header label follows the type — “Room” at a hotel instead of “Table” — translated into 30+ languages. Existing sections default to Tables, so nothing needed activating.
A new menu manager (August 26)
Floor problem: building and checking a menu with photos, modifiers and per-menu pricing was harder than it needed to be for the person doing it.
What we built: a table view with a column picker, a per-menu price panel that shows the resulting price directly, stable item order across screens, portrait photo collection, 44px minimum touch targets, and an always-visible edit button; the waiter app also gained a menu switcher.
Engineering detail: item order is now deterministic, driven by an explicit placement sort order, instead of depending on whatever order the database happened to return rows in.
Packages became menus (August 26)
Floor problem: running two separate systems — a Packages tab and a Menu tab — for what were, functionally, both “things a guest orders” made the menu manager above only half the fix.
What we built: the separate Packages tab is gone. Packages that had their own price became combo items on the menu; packages whose dishes carried the price became per-dish menu prices; a 2-for-1 still counts as two units in kitchen, inventory and reporting. Restaurants didn’t have to migrate anything themselves.
Engineering detail: the conversion rule was precise — any package with its own price, or with a component quantity other than one, became a bundle item; everything else became menu placements. That quantity clause exists specifically so a 2-for-1 keeps selling two drinks, not one. “Sum of selected” components with no override converted at 100% of catalog, so they kept tracking catalog price changes afterward. We rehearsed the conversion three times in staging before running it in production.
Several menus at once, with per-menu pricing (August 26)
Floor problem: a restaurant with a lunch menu, a dinner menu and a delivery menu needed all three live at once, at different prices, without staff guessing which one applies.
What we built: multiple menus active simultaneously, in an order the operator chooses; “Active” (orderable) and “Visible” (browsable) are now separate switches, with a “View only” badge for menus guests can see but not order from; the same dish can carry a different price on each menu — flat or a percentage of catalog, including its modifiers and options — with the catalog price shown struck through when a menu undercuts it. Staff pick the menu when creating an order, in the waiter app too.
Engineering detail: every order line records which menu it was ordered from, so the price charged is the price quoted even if a happy-hour menu ends before the tab closes. A unique constraint on dish and menu guarantees exactly one price per dish per menu. Before any of this went live, every consumer of “the active menu” in the codebase was first made safe for more than one active menu; only then did we flip the switch, the same day.
The new guest experience (August 27)
Floor problem: the guest-facing menu needed to feel like browsing a menu, not paging through a form.
What we built: a full-screen photo cover, a menu sheet that rises under the guest’s thumb as the restaurant name travels into the top bar, one continuous scroll across categories, in-place search, a menu switcher, packages shown honestly as “Desde $X” or “×2” instead of a single misleading price, dark mode, and Call Waiter moved to the front of the navigation bar.
Engineering detail: only the current cover photo and its immediate neighbors are mounted at any time, so the phone never has to decode tens of megabytes of images at once, and jumping between distant categories is instant rather than a smooth scroll a resting thumb could accidentally interrupt. The performance work behind this screen is its own story — we’re covering it separately.
Paying and closing
Own terminal (June 28)
Floor problem: some restaurants take card payments on their own bank terminal, outside PayTable entirely, and that money still needs to show up correctly in the shift report and the invoice.
What we built: staff can record a charge made on the restaurant’s own terminal as its own tender — PayTable never touches that money. A guest can optionally tap “pay with the restaurant’s terminal,” which notifies the waiter. The shift report splits Cash, Own terminal, and Card-Wallet, and the CFDI invoice automatically picks the correct SAT payment form. It ships opt-in, off by default, and can be limited to specific sections. It shipped the same day as its release note.
Engineering detail: the invoice payment form is derived from the actual tender used — terminal maps to form 04, cash to form 01 — and the claim-and-confirm flow was built tender-agnostic from the start, so a future payment method can reuse it rather than needing its own path. Two fail-closed guards keep every other tender out of this record-only settlement flow.
Tab discount (July 25)
Floor problem: comping or discounting a whole tab — a manager’s call, on the spot — needed to work everywhere a tab already works: split tabs, receipts, reports.
What we built: a fixed or percentage discount on a whole tab, applied from admin with an admin PIN, available only before any payment starts. It works with split tabs, shows on guest checkout, bill and receipt, and the Z-report reports “Discounts Applied” alongside net total sales; processing fees are still calculated on the undiscounted amount. This one came directly from a customer request.
Engineering detail: the discount is stored as negative offset rows on each line, so it flows through every existing total, split and receipt calculation without needing special-case logic anywhere; cents are allocated by largest remainder, and the whole operation runs under the tab’s advisory lock.
Move items between tabs (August 1)
Floor problem: a group splits, someone changes tables, or an order got rung to the wrong tab — and fixing it shouldn’t mean voiding and re-entering everything.
What we built: staff can move whole lines, or part of a line — two of five beers — to another tab. The source tab stays open, and closes automatically only if it ends up empty. A manager PIN is required, and paid or comped items can’t be moved.
Engineering detail: moving a whole order re-points it so it keeps its identity and kitchen state intact; moving part of an order clones it at the same full per-unit price. Every check runs inside the tab’s lock, so an item can never be validated as unpaid and then get paid partway through the move. It shipped with 54 unit tests and 3 Postgres integration tests.
Cash drawer (September 6)
Floor problem: cash still moves through a restaurant — floats, paid-outs, corrections — and needed a system, not a notebook by the register.
What we built: staff declare the float at shift open, prefilled from the last shift; cash in and out gets recorded with a category and reason — supplier, petty cash, change, correction, other; the drawer can’t go negative; every device updates in real time; at close, a manager chooses to keep the float or take everything; a separate printable and PDF cash drawer report keeps voids visible, struck through rather than hidden. Cash movements in either direction require a manager PIN. It ships opt-in, off by default, and it came directly out of a training session with a restaurant.
Engineering detail: the balance is read and written inside a single Postgres advisory transaction lock, so two managers working the same drawer can never overdraw it. The feature flag is read once, at shift open, so a past shift’s report never changes retroactively if the flag changes later. Real-time events carry no balance figure at all — every receiver re-fetches the authoritative number rather than trusting a figure that traveled over the wire. A “no drawer” shift (a null float) is kept distinct from a shift that opened with a genuine $0 float.
Running the shift
Guardar para después — hold a table’s name for later (September 11)
Floor problem: during a rush, retyping a guest’s name for every refill produces tabs named things like “the corner table.”
What we built: waiters can save a guest name on their phone for one-tap use on the next order at that table — several names per table at once. It clears when the order is sent, when dismissed, after one hour, or on logout. A name is no longer required to open a tab at all; it shows as “Cliente” until someone provides one.
Engineering detail: the name never leaves the phone. It’s stored only in local storage with a 60-minute lifetime, cleared on logout, with no API call, no database row, and nothing to sync. It was scoped and shipped in a single day.
What moved fast, and what didn’t need to
The June and July features mostly went from first commit to release note in zero to three days — several the same day. The larger August wave — the menu manager, the packages conversion, multiple active menus, and the new guest experience — took closer to seven to nine days from first commit, which tracks: they were connected changes, built and released together. And features that add new ways for a restaurant’s money to move — own terminal, the cash drawer — ship opt-in and off by default regardless of how fast they were built, because speed of delivery and confidence in a money-handling feature are two different questions.
Full release notes for all twelve, in Spanish and English, are on our site: https://paytable.mx/novedades