Resto · version 1.0
Restaurant point of sale & management
Everything you need to run a restaurant from one install: a touch till that works offline, a kitchen screen, recipe-level stock, a QR menu your customers order from, payroll, and books that balance. This guide covers installing it and running it.
In a hurry? Upload the files, open your domain, and follow the installer. Then read Your first hour — it is the shortest path from an empty install to ringing up a real sale.
Welcome
Resto is a single-restaurant system. One install runs one business, which can have several branches — each with its own stock, prices, staff, tables and reports.
What is in the box
Touch POS
Dine-in, takeaway, delivery and drive-thru. Splits, holds, voids, refunds, cash-up. Keeps taking orders when the internet drops.
Kitchen display
Tickets routed per station, timed against a target, with a bump screen and a recall.
Dining room
A floor plan you draw once, table sessions, transfers, merges and a waiter app for phones.
Inventory
Recipes down to the gram, moving-average costing, batches, wastage, stocktakes and transfers.
Purchasing
Suppliers, purchase orders, partial deliveries, landed cost and what you owe.
Online store
A QR menu search engines can read, guest checkout, order tracking, delivery zones and riders.
Customers
Loyalty points, gift cards, coupons with real rules, and moderated feedback.
Staff
PIN clock-in at the terminal, timesheets, leave, and payroll that reads the clock.
Accounting
Double-entry books that post themselves from sales, deliveries, expenses and payroll.
How to read this guide
Sections follow the order you will actually need them: set the place up, build the menu, open the till, then everything else. Every screen named here exists in the product — where something is planned but not built, it is listed under Not built yet rather than described as if it were.
Server requirements
Resto runs on ordinary shared hosting. There is nothing to compile, no Node on the server, no Redis, no websockets and no Supervisor.
| What | Needs | Notes |
|---|---|---|
| PHP | 8.3 or newer | 8.3 and 8.4 are both tested. |
| Database | MySQL 8.0+ or MariaDB 10.6+ | The installer creates the database for you if the user is allowed to. |
| Extensions | pdo_mysql, mbstring, openssl, tokenizer, xml, ctype, json, bcmath, fileinfo, curl, gd | All standard. The installer checks each one and tells you which is missing. |
| Optional | zip, intl | Nice to have; nothing fails without them. |
| Writable | .env, storage/, bootstrap/cache/, public/uploads/ | Usually 755 on folders, 644 on files. |
| Web root | Point the domain at public/ | See the warning below if your host will not let you. |
Point the domain at public/, not at the folder above it.
If the document root is the project folder, anyone can download your .env
— which contains the database password and the application key. On cPanel this is
Domains → Document Root. If your host truly will not allow it, move the
contents of public/ into the web root and edit the two require
paths at the top of index.php.
What you do not need
No cron job. No queue worker. No Node or npm on the server — the compiled CSS and
JavaScript ship inside the ZIP in public/build/. Nothing in Resto is queued
or scheduled: the kitchen and dispatch screens poll every few seconds rather than
holding a socket open, precisely so it runs on hosting that forbids long-running
processes.
Installing
Resto installs itself in a browser. You do not need shell access, phpMyAdmin or a command line.
-
Upload and unzip
Put the contents of the ZIP on your server and point the domain at the
public/folder. Everything is included — you do not need to runcomposer install. -
Open your domain
Any address on the site redirects to
/setupuntil the install is finished. You will land on the requirements check. -
Requirements
Every required row must be green. If one is not, enable the extension or fix the folder permission on the server and press Re-check. Nothing has been written yet.
-
Restaurant
The name, currency and timezone, plus the environment and URL. The currency decides how every price in the system is displayed, and the timezone decides which business day a 1 a.m. order lands on. Leave Debug mode off on a live server.
-
Database
Host, database name, username and password. Press Test connection before continuing. If the database does not exist yet, Resto creates it — as long as your database user is allowed to. Leave Drop existing tables off unless you are re-installing over a failed attempt.
-
Owner
Your name, email, password and a terminal PIN. The PIN is what the till asks for — clocking in, approving a void, applying a discount. Nobody types an email address on a busy Friday.
Leave Install sample data off for a real restaurant. It fills the system with a demo menu, floor plan, staff and a week of fake orders, which is a lot to delete afterwards.
-
Review and install
Check the summary, then press Install now. This writes
.env, creates the tables and your account. It usually takes under a minute; the log tells you exactly what happened, and exactly where it stopped if something went wrong.
The installer seals itself. Once it finishes, /setup
redirects to the site and cannot be re-run. The seal is a file:
storage/app/installed. Delete it to open the wizard again — and if
/setup is ever reachable when it should not be, that file is the first
thing to check.
If the install fails
The log on screen stops at the step that failed and shows the reason. Nothing after that point was changed. The usual causes:
| Message mentions | What to do |
|---|---|
| Access denied for user | Wrong database username or password. Go back a step and re-test. |
| Unknown database | Your database user may not create databases. Create an empty one in your hosting panel and use that name. |
| Permission denied / failed to open stream | .env or storage/ is not writable. Set folders to 755 and files to 644. |
| Maximum execution time | Rare, and only with sample data on slow hosting. Re-run with Drop existing tables on and sample data off. |
Your first hour
An empty Resto cannot ring up a sale, because nothing has a price yet. This is the shortest route from installed to trading.
-
Check your currency and timezone
Settings → General Settings. The installer set both from what you typed; this is where you correct them, add your logo and set your receipt header.
-
Set your taxes
Settings → Taxes & Charges. Create the rates you charge and put them in a tax group. Decide now whether your prices include tax — the switch is on General Settings → Money & tax. It changes what every number on the menu means, and changing it later does not restate the sales you have already taken.
-
Create a price book
Menu → Price Books. One book marked as the default is enough to start. Prices live in a book, not on the item, which is what lets a takeaway price differ from a dine-in one later.
-
Build the menu
Menu → Categories, then Menu Items. Each item needs at least one size (a variant) and a price in your default book. An item with no price in any book cannot be sold — the till and the online menu both hide it rather than sell it for nothing.
-
Add your staff
Staff. Give everyone a role and a terminal PIN. The role sets a sensible starting set of permissions; tick and untick from there.
-
Draw the floor, if you seat people
Tables & Floor. Add a floor, drop tables onto it and set the seats. Skip this entirely if you are takeaway only.
-
Open the till
POS Terminal. Pick a terminal, open a shift with the cash in the drawer, and take an order. That is the whole loop.
Everything else — stock, suppliers, the online shop, loyalty, payroll, the books — can wait until you are trading. None of it is required to take money.
Command-line install
If you have shell access and would rather not use the wizard:
composer install --no-dev --optimize-autoloader
cp .env.example .env
php artisan key:generate
# edit .env: APP_URL, APP_TIMEZONE and the DB_ settings
php artisan migrate --force
php artisan db:seed --force # branch, owner, payment methods, chart of accounts
npm install && npm run build # only if you changed the CSS or JS
# tell the installer it has nothing left to do
echo OK > storage/app/installed
The seed creates a placeholder owner, owner@resto.test, with the password
password.
Change or delete that account before you go live. It has a published email and a published password. The browser installer deletes it automatically once you create your own owner; a command-line install does not.
Sample data
Optional, and never part of a real install. Run them in this order:
php artisan db:seed --class=DemoRestaurantSeeder # staff with terminal PINs
php artisan db:seed --class=DemoMenuSeeder # a small bistro menu
php artisan db:seed --class=DemoFloorSeeder # a dining room and a terrace
php artisan db:seed --class=DemoInventorySeeder # ingredients, recipes, opening stock
php artisan db:seed --class=DemoChannelSeeder # customers, coupons, delivery zones
php artisan db:seed --class=DemoHrSeeder # timesheets and pay terms
php artisan db:seed --class=DemoSalesSeeder # a fortnight of trading
| Demo account | Role | PIN |
|---|---|---|
manager@resto.test | Manager | 1234 |
cashier@resto.test | Cashier | 4821 |
waiter@resto.test | Waiter | 5150 |
chef@resto.test | Chef | 7788 |
store@resto.test | Storekeeper | 3030 |
All demo accounts use the password password. Delete them before going
live.
Settings
Settings → General Settings. Resto stores its settings in the database,
not in .env, so nothing here needs a file editor. The installer writes the
important ones; the rest have sensible defaults and can be left alone.
Six tabs, each saving only its own keys — changing the receipt footer cannot reset your currency. The key names below are what the tables store, given here because they are also what the API and the seeders use.
| Tab | Covers |
|---|---|
| Restaurant | Name, timezone, logo and browser icon, footer text, languages. |
| Money & tax | Currency, symbol position, cash rounding, tax-inclusive pricing, service charge, tax number. |
| Orders & service | Order numbering, the trading-day start, kitchen target time, stock deduction, PIN approvals. |
| Receipts | Paper width, header and footer, auto-print — with a live preview of the paper. |
| Reservations | Turn time, slot spacing, auto-confirm. |
| API | Rate limit. |
Three things keep their own screens, because each is a set of records rather than a set of switches: tax rates under Settings → Taxes & Charges, the loyalty scheme under Loyalty, and opening hours and delivery under Delivery → Online Store — those differ per branch.
Money
| Key | Default | What it does |
|---|---|---|
currency_code | USD | Three-letter code. Used by the API and by every exported file. |
currency_symbol | $ | What is printed beside the number. |
currency_decimals | 2 | Set to 0 for currencies with no minor unit. |
currency_position | before | before or after the number. |
cash_rounding_increment | 0 | Rounds cash totals to the nearest increment — 0.05 where the smallest coin is five cents. The difference is recorded, not hidden. |
tax_inclusive | 0 | 1 if your menu prices already contain tax. |
service_charge_percent | 0 | Added to dine-in orders. |
service_charge_taxable | 1 | Whether tax applies to the service charge. |
Orders and receipts
| Key | Default | What it does |
|---|---|---|
order_number_prefix | ORD- | Prefix on every order number. |
order_number_daily_reset | 0 | 1 restarts the sequence each day. |
business_day_start_hour | 4 | The hour a trading day begins. A shift that finishes at 2 a.m. belongs to the night it started, not to the next morning. |
receipt_width | 80 | Paper width in millimetres — 58 or 80. |
receipt_header / receipt_footer | — | Free text above and below the receipt. |
auto_print_receipt | 0 | Prints the receipt as soon as an order is paid. |
print_method | browser | app prints through the Resto Print app instead of the browser. |
kot_enabled | 1 | Prints kitchen tickets at all. Off for a kitchen that works only from screens. |
kot_auto_print | 0 | Browser printing: kitchen screens print each new ticket as it arrives. |
tax_number | — | Your VAT / tax registration number, printed on receipts. |
kds_default_sla_minutes | 15 | Target time for a kitchen ticket. Colours the ticket amber, then red. |
inventory_deduct_on_sale | 1 | Takes ingredients out of stock when a sale closes. Turn off until your recipes are built. |
Branding
| Key | What it does |
|---|---|
app_name | Shown in the back office, on receipts and on the online menu. |
logo_path / favicon_path | Paths under public/uploads/. |
show_site_name | Whether the name appears next to the logo. |
dashboard_footer_text | Small print at the bottom of the back office. |
default_language | en. Resto ships English and Arabic, with a full right-to-left stylesheet. |
Branches
Settings → Branches. One Resto install runs one business. A business can have several branches, and almost everything is scoped to one: stock, tables, terminals, shifts, staff, orders and reports. The menu, ingredients and customers are shared.
A single-site restaurant can ignore this screen entirely — the installer creates one branch and names it after the restaurant.
Adding one
A new branch gets a main store automatically, because one with nowhere to hold stock cannot receive a delivery. After that it needs its own floor plan, opening hours and delivery zones — the branch form links to all three.
Two rules
- Exactly one default. Making a branch the default demotes whichever was. Staff with no branch of their own land there, and the online shop uses it when no branch is named.
- A branch is switched off, never deleted. Orders, stock movements and shifts all point at the row. Switching it off hides it from the till and the shop and leaves the history readable. The default branch, and the last one trading, cannot be switched off at all.
A staff member with no branch set can work at any of them. Set a branch on somebody who only ever works at one, and their screens default to it.
A staff member with no branch set can work at any of them. Set a branch on somebody who only ever works at one, and their screens default to it.
Staff, roles & permissions
Staff in the sidebar. Every person is one row, whether they log into the back office, clock in at the till, or both.
Roles
A role is a starting point, not a cage: it fills in a sensible set of permissions which you then tick and untick per person.
| Role | Starts with |
|---|---|
| Owner | Everything, always. The permission list does not apply. |
| Manager | POS, orders, discounts, voids & refunds, tables, kitchen, menu, inventory, purchasing, customers, reservations, delivery, staff, reports |
| Cashier | POS, orders, discounts, voids & refunds, tables, customers |
| Waiter | POS, orders, tables, reservations |
| Chef | Kitchen, orders, inventory |
| Storekeeper | Inventory, purchasing |
| Accountant | Accounting, reports, purchasing |
| Rider | Delivery |
Permissions
Sixteen sections: pos, orders, discounts,
refunds, tables, kitchen, menu,
inventory, purchasing, customers,
reservations, delivery, staff,
accounting, reports, settings.
Two of them govern money leaving the business rather than a screen:
discounts is Apply discounts, and refunds is
Voids & refunds. Both are separate from orders, so somebody can
be trusted to look at every sale without being able to give one away. See
Who may discount, void and refund.
A link somebody cannot use is dimmed in the sidebar, and the route behind it refuses them as well — pasting an admin URL into a cashier's browser gets a 403, not a page.
Passwords and PINs
Two separate credentials, deliberately. The password signs into the back office. The PIN is what the terminal asks for: clocking in, switching user mid-shift, approving a void, a refund or a discount. Four to eight digits.
A PIN only approves if the person it belongs to is a manager or an owner. A cashier's PIN clocks them in; it never signs off their own discount.
People who leave
Deleting a member of staff would orphan every order they rang up and every line they approved, so Resto marks them as left instead: the account is deactivated, dated, and hidden from the staff list unless you tick Include leavers. Their history stays intact.
Taxes & charges
Settings → Taxes & Charges. A tax is one rate. A tax group is the set of taxes that apply together — most restaurants need one group with one rate in it, but the structure handles a state tax plus a city tax without inventing a combined percentage.
Every menu item points at a tax group. Items with none use the default group.
Inclusive or exclusive
The single most important decision on this screen.
- Exclusive (
tax_inclusive = 0): the menu says 10.00, the customer pays 10.00 plus tax. - Inclusive (
tax_inclusive = 1): the menu says 10.00 and that is what the customer pays; Resto works backwards to find the tax inside it.
Set this before you take your first order. Changing it later does not restate sales already recorded — every order stores the totals it was rung up with, on purpose, so a settings change next month cannot rewrite what last month's revenue was.
Service charge
A percentage added to dine-in orders, set with service_charge_percent.
Whether it is itself taxable is a separate setting, because the answer differs by
country. It is never added to takeaway or delivery.
Categories
Menu → Categories. Categories group items on the till grid and on the online menu, and they can nest one level. Each one can carry a colour and a default kitchen station, which items inherit unless they override it.
Drag to reorder — the order here is the order on the till, so put what sells most first.
Items & variants
Menu → Menu Items. An item is a thing on the menu. A variant is a size or version of it — Regular and Large, or a single default variant for something that only comes one way.
Prices are not on the item. A price is the intersection of a variant and a price book. That is what lets delivery cost more than dine-in without duplicating the menu.
What an item carries
| Field | Why it matters |
|---|---|
| Category | Where it appears on the grid and the online menu. |
| Kitchen station | Which screen the ticket prints to. Falls back to the category's station. |
| Tax group | Overrides the default group for this item. |
| Channels | Where it may be sold: till, QR, online, delivery. An item absent from a channel is not merely hidden there — the order service refuses it. |
| Schedule | Available from / until, and on which days. Breakfast stops at 11. |
| Prep time | Feeds the kitchen timer and the online ETA. |
| Dietary tags & allergens | Printed on the online menu; several markets require it. |
| Image | Used on the till grid and the QR menu. |
Combos
An item of type combo carries choice groups instead of a plain price — a meal deal where the customer picks a main, a side and a drink. Combo groups are edited inside the combo item itself, on the item form.
Import and export
The item list exports to CSV and imports back. The export is the template: change it, re-upload it. Useful for a first bulk load and for a price review.
Modifiers
Menu → Modifiers. A modifier group is a question the till asks — "How would you like it cooked?", "Any extras?" — and the modifiers are the answers.
Attach a group to as many items as you like. Each item can override the group's rules, so Extras can allow three free choices on a burger and none on a salad.
| Rule | Effect |
|---|---|
| Required | The order cannot be sent until something is picked. |
| Min / max select | How many answers are allowed. |
| Free count | How many are included before charging. Spent in units, so "extra bacon ×2" uses two of three free picks. |
| Max quantity | How many times one modifier may be repeated. |
| Price & cost | What it adds to the bill, and what it takes out of stock. |
Combos
Menu → Combos. A combo is a meal deal: one price, and the customer picks a main, a side and a drink.
Making one
Create a menu item of type Combo
It gets a price like any other item — that is what the customer pays.
Add its choice groups
On the item's own page. "Choose a main", "Choose a drink". Each group says how many the customer picks.
Put options in each group
Any variant on the menu can be an option.
How it prices
The combo carries the price and the choices are free — unless an option sets an upgrade charge, the "large fries, +1.00" case. A negative charge is allowed, for a cheaper swap.
A combo with no choice groups cannot be ordered — the till has nothing to ask for. The Combos screen flags those at the top so they do not sit unsellable on the menu.
The Combos screen exists because the item list can tell you a combo is there but not what is in it, which is the only thing about a combo that matters. Groups are still edited inside the item, because a group has no meaning away from the combo it belongs to.
Price books
Menu → Price Books. A price book is a named set of prices. One book is the default and is used whenever nothing more specific applies.
A book can be limited by branch, channel, order type, day and time. Resto picks the first book whose conditions match the sale, and falls back to the default for any item that book does not price.
What that buys you
- A delivery book priced 15% above dine-in, to cover the aggregator's cut.
- A happy-hour book live from 4 to 6 on weekdays.
- A second branch in a more expensive part of town.
- A staff book at cost.
An item that no book prices cannot be sold. The till hides it and the online menu leaves it out, rather than offering it for nothing.
Availability (86)
Menu → Availability (86). "86" is kitchen shorthand for we have run out. This screen takes an item off the menu without deleting anything.
- Per branch — out at one site, still on at another.
- A whole item, or just one size.
- Until a time you choose, or until somebody puts it back.
86-ed items grey out on the till and drop off the online menu immediately.
The POS terminal
POS Terminal in the sidebar, or go straight to /pos. Built for a
finger on a tablet: large targets, no hover, no double-tap.
Terminals
A terminal is a named till — Front counter, Bar. Each has its own shift, its own drawer and its own receipt numbering. Pick one the first time you open the POS on a device; it is remembered.
Taking an order
Choose the order type
Dine-in, takeaway, delivery, drive-thru or room service. This decides the price book, whether a service charge applies and whether a table is needed.
Tap items
Tap a category, tap an item. If it has sizes or required choices, the till asks. The running total is on the right.
Adjust the line
Quantity up and down on the line itself, Discount for money off that one dish, and the bin to take it off the order.
Add the customer
Optional for a walk-in, and the point of the order for a delivery. See The customer on the order.
Send to the kitchen
Sends only the lines that have not been sent yet — adding a round sends the round, not the whole table again.
Take payment
One tender or several. See Payments.
Holds
Park an order with a label and recall it later. A held order has not been sent to the kitchen and owes nothing.
The customer on the order
Add a customer in the order panel searches by phone number or by name. Two characters are enough, and a partial number matches — people read their number out from the end as often as the start.
Choosing somebody puts their name on the order, their allergy note on every kitchen ticket for it, their customer-group discount on the total, and their saved addresses one tap away. New customer in the same panel adds one without leaving the order: name, phone, and an address if it is going out. A number already on file returns that person rather than an error — the intent was to put them on the order, and they already exist.
A delivery order at the till
Choose Delivery as the order type and the order panel asks for an address. A saved address is one tap. A new one is typed in and, for a customer who is on the order, kept for next time.
The zone fee and the promised time appear on the total as soon as there is a postcode to go on, and the order reaches the dispatch board with the address, the number to ring and the cash to collect. An address outside every zone is still accepted: the cashier has already said yes to the person on the phone, so the order lands on the board with no fee and no promised time rather than being refused. Paying at the till leaves the rider nothing to collect.
Customer lookup needs a connection. Offline the till still sells — see Working offline — but as a walk-in sale.
Discounts
Discount under the totals takes money off the whole order; the same button on a line takes it off that dish. Either way it is one pad: a percentage or a fixed amount, with quick keys for the shares a restaurant actually uses, and the amount it comes to shown before you apply it.
Every discount takes a reason and records who approved it. The till offers a short list — staff meal, manager comp, loyalty, complaint, promotion — because a free-text box gets "asdf" typed into it mid-rush while a short list gets used and turns into a report an owner can act on. Anything not on the list can still be typed.
An order-level discount is spread across the lines in proportion to what each contributes, before tax; taking it off the total afterwards would quietly reduce the tax owed on a sale that already happened.
A customer group's standing discount is not this. It applies on its own when that customer is on the order, because it is the owner's decision rather than the cashier's, and a discount keyed in by hand replaces it rather than stacking on top.
Who may discount, void and refund
Two permissions decide who: Apply discounts and Voids & refunds, set per person under Staff. Three settings under Settings → Orders decide when a manager has to lean over:
| Setting | What it does |
|---|---|
| A manager PIN is needed to apply a discount | On by default. Off, anyone holding the permission discounts on their own authority. |
| A manager PIN is needed to void or refund | On by default, and the same rule. |
| Discount ceiling without a PIN | A discount worth more than this share of the order asks for a PIN whatever the toggles say. Blank for no ceiling. |
Only a manager or an owner PIN approves. A cashier's own PIN proving their own discount would be no approval at all, so their PIN is never checked here. Whoever keys theirs in is written onto the order or the refund and into the activity log, whether or not a PIN was asked for.
The ceiling is measured on what the order actually lost, not on the number typed: a fixed amount off a small order can be a far bigger share than any percentage box would show.
Changing an order after it is placed
Orders on the till lists today's sales plus anything still open, searchable by order number, customer name or phone. Open one and the screen offers only what applies to it.
| The order is… | What to do |
|---|---|
| Still on screen, not sent | Change the quantity or take the line off. Nothing has happened yet. |
| Sent, nothing paid | Void the line, or the whole order, with a reason. |
| Paid | Refund the lines coming back. A paid order is never edited. |
| Paid, and the guest wants something different instead | Refund the original line, then ring the replacement as a new order. |
Voids
Voiding takes a reason and cancels an order that has not been paid. The order number stays on file marked cancelled rather than deleted — several tax regimes require the number to stay allocated — every line is voided, and stock already taken out goes back as its own movement, so the stock card still shows it leaving and returning.
Once money has changed hands, voiding is refused and the till says so: taking a line off a settled sale would leave the order paid for more than it says. That is a refund.
Shifts & cash-up
A shift is one session on one terminal: opened with the cash in the drawer, closed by counting it.
Open
Enter the opening float. Nothing can be rung up on a terminal with no open shift.
During service
Cash in and cash out — a supplier paid from the drawer, a float top-up — are recorded as they happen, each with a reason.
Close
Count the drawer and enter the figure. Resto shows what it expected, what you counted and the difference.
Expected cash is derived from the movements ledger, never from a running total anybody can edit. The Z-report is stored on the shift, so a cash-up can be re-read months later.
Staff → Shifts & Cash-up lists every shift with its variance. A small shortage that repeats is a different problem from one large one, and the list is sorted so you can see which you have.
Payments & refunds
Payment methods are set up in the foundation seed: cash, card, wallet, gift card and account. Each carries whether it counts in the drawer, whether it can give change and whether it needs a reference.
Splitting a bill
A bill split four ways is four payment rows, not one payment with a note — that is the only shape a payment-method report and a cash-up can be built from.
Change
Calculated on what was tendered, and only for methods that can give change. Handing cash back against a card tap is not a rounding error, it is a hole in the drawer.
Refunds
A closed order is never edited. A refund is a new record that quotes the original, picks the lines being returned, records who approved it and why, and puts the stock back if you say so. The original order still says what it said.
Find the order
Orders on the till, or Orders in the back office. Search by number, customer name or phone.
Say what is coming back
Set a quantity on each line — one of the two burgers, not the whole bill — or Everything on the order. Lines left at zero are not refunded.
Choose how, and why
The tender the money goes back on, and a reason from the list or typed in.
Restock, or not
Only tick it when the dish actually came back. A guest refunded because the dish was wrong is not returning it, and putting it back would inflate the stock on hand.
Approve
A manager PIN if the settings ask for one. See Who may discount, void and refund.
Each line tracks how much of it has already been given back, so a second refund cannot return the same food twice, and the total is capped at what was actually paid. Cash refunds come out of the drawer as their own movement, so the cash-up still balances. A refund on a card or another non-cash tender never touches the drawer.
Changing one item on a completed order is a refund of that line followed by a fresh sale, not an edit. It leaves two documents that add up, which is what a tax inspector and a cash-up both need — and what an edit would quietly destroy.
Printing
Settings → Printers & Receipts.
Resto prints in one of two ways. Choose under How Resto prints at the top of the screen. You can switch at any time. The receipt and the kitchen ticket look the same either way.
| Through the browser | Through the Resto Print app | |
|---|---|---|
| Install anything | Nothing | One small Windows app, on the computer the printers are plugged into |
| Printers per device | One: the device's default printer | As many as are plugged in |
| Kitchen tickets | Printed by a kitchen screen left open beside each kitchen printer | Sent straight to each station's printer |
| Tickets from QR orders and the waiter app | Print only while a kitchen screen is open | Always print |
| Print dialog | Yes, unless the browser is started for kiosk printing | Never |
| Cash drawer | No | Yes, opened after a receipt |
| Best for | A counter with one printer, or a kitchen that works from screens | A cashier printer and kitchen printers in the same restaurant |
The customer receipt
Paper width (58 or 80 mm), a header under the restaurant name, a footer at the bottom, and whether it prints itself the moment an order is paid. The screen shows a live preview of the paper, because "58 or 80" means nothing until you see how much of your address fits on it.
After every sale the till shows a Receipt button that prints that sale's receipt, even when printing on payment is switched off. Older receipts are printed from Orders → the order → Reprint, marked as a copy.
The kitchen ticket
For kitchens with a printer rather than a screen — a docket in a rail is still the fastest way to run a pass. Bigger type than a receipt, quantities and item names in capitals, modifiers indented, notes boxed and allergies boxed heavily: it is read at arm's length, in a hurry, through steam.
One order becomes one ticket per station: the grill gets the steaks and the bar gets the drinks. A kitchen can use screens, printers, or a screen on the grill and a printer at the pass.
Testing it
Both documents have a test print button that uses a real order or a real ticket — not a mock-up, so what you see is what a customer gets. Save the settings first; the test reads them as stored.
Printing through the browser
Each device prints to its own default printer. Set the printer as the default in Windows, and in the browser's print settings turn off headers and footers and set the margins to None.
Receipts at the till
Make the receipt printer the till computer's default printer. Switch on Print automatically when an order is paid if every sale should print.
Kitchen tickets
Switch on Print kitchen tickets and Print as soon as an order is sent. Put a tablet or small PC beside each kitchen printer, make that printer its default, and open the station's screen: the Screen button under Where tickets go, or Kitchen Display and choose the station.
Check the printer icon
The printer icon at the top of a kitchen screen turns printing on or off for that device. Turn it off on a screen that has no printer beside it. The Pass screen, which shows every station, prints only when its icon is switched on.
A ticket prints once, whichever screen prints it first: reloading the page, or a second tablet at the same station, does not print it again. Only new tickets print by themselves, so switching a screen on mid-service does not reprint the whole rail. The printer button at the bottom of each ticket prints it again by hand.
No print dialog. Start Chrome or Edge with
--kiosk-printing (add it to the end of the shortcut's Target) and
it prints straight to the default printer without asking.
A browser cannot choose a printer. One device means one printer, and a kitchen screen has to stay open for its tickets to print. When the receipt and the kitchen tickets must come out of different printers on the same computer, or tickets must print with no screen open, use the Resto Print app.
Resto Print app
Settings → Print App. A small Windows app that runs on the computer the printers are plugged into. One computer drives every printer: receipts to the cashier printer, each station's tickets to its kitchen printer, with no print dialog. Tickets from QR orders and the waiter app print even when no screen is open anywhere.
What you need
- A Windows 10 or 11 computer that stays switched on during service, usually the till.
- Each printer installed in Windows with its own driver, and printing a Windows test page. USB, network and Bluetooth printers all work, thermal at 58 or 80 mm or ordinary.
- The computer can open your Resto address in a browser.
Setting it up
Add your printers in Resto
Settings → Print App → New printer. One for each real printer. Give it a name, choose the paper width, and choose what it prints: Customer receipts and table bills for the cashier printer, and the stations whose tickets it prints for a kitchen printer. On the one kitchen printer of a small kitchen, also tick Every other kitchen ticket, so items with no station still print.
Download and install the app
On the computer the printers are plugged into, open Settings → Print App and press Download Resto Print for Windows. Run the installer.
Create a key
Under Print app connections, name the computer (Cashier PC), choose its branch and press Create key. The address and the key are shown once. Copy them now.
Connect the app
Open Resto Print, paste the address and the key, and press Connect. Your printers from step 1 appear in the app, and the computer shows as online in Resto.
Match the printers
For each Resto printer, choose the printer on this computer it should print to, then press Test print in the app. A test page shows the printer's name, its paper width and a line in several scripts.
Start with Windows
Tick Start with Windows in the app, so it is running in the tray whenever the computer is on.
Switch Resto over
Settings → Printers & Receipts → How Resto prints, choose Through the Resto Print app and save. Then press Test print beside a printer in Settings → Print App: the test page now comes out through the app, which proves the whole path.
"Windows protected your PC". If Windows shows this when the installer starts, press More info and then Run anyway. Windows shows it for installers it has not seen often. It does not mean anything is wrong with the file.
What prints where
| Document | Printer | When |
|---|---|---|
| Kitchen ticket | The station's printer, or the printer for every other kitchen ticket | As soon as the order is sent: from the till, the waiter app, a QR order or the API |
| Kitchen ticket again | The station's printer | The printer button on a ticket on the kitchen screen |
| Customer receipt | The printer for receipts and bills | On payment, if Print automatically when an order is paid is on; the Receipt button after a sale; Reprint under Orders |
| Table bill | The printer for receipts and bills | Print bill on a table |
| Test page | The printer you test | Test print under Settings → Print App |
A station's printer can also be chosen on the station itself, under Settings → Kitchen Stations.
The same ticket on two printers
In the app, choose a second printer under Also print on, for example a copy of every grill ticket for the pass. Each Resto printer can print on up to two printers on the computer.
The cash drawer
For a drawer plugged into the receipt printer, tick Open the cash drawer after a receipt on that printer in Resto. The app opens it after each receipt, but not after a reprint. The app's Open drawer button tests it.
More than one computer or branch
- Create one key for each computer that runs the app. Removing a connection in Resto stops that computer printing at once.
- A key belongs to one branch and only ever prints that branch's documents.
- Two computers in the same branch can both run the app. Each matches only the printers plugged into it. Every document is printed once, by whichever computer has its printer.
When something did not print
Look at Recent print jobs at the bottom of Settings → Print App first:
| Status | Meaning |
|---|---|
| Waiting | No app has collected it. Check the computer is on and the app is running: Print app connections shows it as online. |
| Printing | The app has it. If it stays there for more than two minutes, the app lost touch, and the job is handed out again. |
| Printed | The printer accepted it. If nothing came out, check the paper and the printer's own queue in Windows. |
| Failed | Tried three times. The reason is shown under the status, for example a printer that is not matched in the app, or out of paper. Fix it and press Retry. |
The app keeps its own log, shown in its window. Open log folder opens the files.
Keys and safety
- The key is shown once in Resto and kept only as a hash, like an API token. On the computer, the app stores it encrypted by Windows.
- A key can do nothing but print. It cannot read orders, reports or customers.
- The app fetches each document from a signed link that expires after fifteen minutes.
Shipping the installer
The Windows installer ships in public/downloads/resto-print/, and the
Download button offers the newest version found there. If that folder is
empty, for example on a host that will not serve .exe files, set
RESTO_PRINT_DOWNLOAD_URL in .env to where the installer can be
downloaded instead.
Working offline
The till keeps working when the internet drops. This is not a bonus feature — a restaurant that stops taking money because a router rebooted has a serious problem.
How it works
- A service worker keeps the terminal loadable with no connection.
- The menu is cached on the device, so items and prices are there.
- Orders taken offline queue in the browser and send themselves when the connection returns.
- Every order carries an identifier generated on the device, so a replay after a dropped connection is a quiet success rather than a duplicate sale.
What it will not do
| Offline | Behaviour |
|---|---|
| Cash sales | Work normally. |
| Card terminals | Depend on your card provider, not on Resto. |
| Kitchen tickets | Queue, and arrive when the connection returns. |
| Stock deduction | Happens on the server when the order syncs. |
| A brand-new item | Not on the device until it next syncs the menu. |
| Customer lookup | Needs a connection. The sale goes through as a walk-in. |
| Discounts needing approval | Refused while offline, and the till says so. A manager PIN is never written to the queue, so a discount that needed one would sync into a rejection — after the guest has left. |
| Voids and refunds | Need a connection: both act on an order the server already holds. |
Do not close the browser tab while orders are still queued. The badge on the POS shows how many are waiting to send.
Dining room
Tables & Floor to draw the room, Service → Floor to work it.
The plan
Add a floor — Dining room, Terrace — then drop tables onto a grid, set the seats and the shape, and drag them where they really are. The grid is in units rather than pixels, so the same layout renders on a phone and on a desktop.
During service
Each table shows its state at a glance: free, seated, ordered, food served, bill asked for, needs clearing. From a table you can seat a party, open its order, transfer it to another table, merge two tables for a large group, or clear it down.
A table that still owes money cannot be cleared. Settle or transfer the bill first.
QR codes
Delivery → Online Store → QR codes prints a sheet of table cards. Each carries a stable token, so reprinting the sheet does not invalidate the codes already stuck to the tables. Scanning one opens the menu and remembers which table it came from.
Kitchen display
Kitchen Display, or /kitchen. Designed for a screen on a wall,
seen from two metres away with steam in between.
Stations
Settings → Kitchen Stations. Grill, fryer, cold, bar. Items route to a station; the station's screen shows only its own tickets. A screen can also watch several stations at once for a small kitchen.
The board
- Tickets arrive as they are sent from the till and are ordered oldest first.
- Each carries a timer, amber at three quarters of the target and red past it.
- Tap a line to mark it ready; tap the ticket to bump it off the board.
- A bumped ticket can be recalled — the wrong bump is the most common mistake on a kitchen screen, and it should not cost anybody a plate.
The board refreshes itself every few seconds. It does not need a websocket, and it does not redraw unless something has actually changed.
Waiter app
Waiter App, or /waiter. A phone-sized view for the floor: your
tables, what is ready to run, and what is still coming.
It is the same login and the same permissions as everything else — no separate app to install and no separate account to manage.
Ingredients & units
Inventory → Ingredients. An ingredient is something you buy and hold: flour, chicken thigh, a bottle of tonic.
Units
Every ingredient has a base unit — the unit it is counted in. Purchase units convert to it, so you can buy a 25 kg sack and use 180 g without doing the arithmetic yourself.
Costing
Resto uses moving average cost. Each delivery blends its price into the existing stock, so the cost of a portion reflects what you actually paid rather than the last invoice. Ingredients marked track batches also carry batch codes and expiry dates, and are drawn oldest first.
Preps
An ingredient marked is prep is something you make: a sauce, a dough, a stock. It has a recipe of its own and can be held in stock like anything else.
Recipes
Inventory → Recipes. A recipe says what one portion of a menu item consumes. Build them and two things start working: food cost on every report, and stock that goes down when you sell.
Sub-recipes do the right thing. If a burger uses your own barbecue sauce and you hold that sauce in stock, selling a burger takes sauce out — not flour, sugar and tomato. If you do not hold it, Resto explodes the recipe down to raw ingredients instead. Costing always explodes to raw, so the number is honest either way.
Recipes attach to a variant, so a Large can use more than a Regular. Modifiers carry their own cost, so extra cheese takes cheese out of the walk-in.
Stock, wastage & stocktakes
Stores
A store is a place stock sits: the kitchen, the bar, the dry store. Every movement names one.
The ledger
Stock is an append-only ledger of movements, with the on-hand figure derived from it. Nothing writes a level directly. That means every number can be explained: tap a level to see exactly what made it.
Wastage
Inventory → Wastage. Record what was thrown away and why. It comes off stock and lands in the books as a cost, separate from a stocktake difference — one is a kitchen problem and the other is a counting problem, and you need to know which you have.
Stocktakes
Inventory → Stocktake. Open a count, enter what is physically there, and close it. Resto shows the variance per line — expected against counted, in units and in money — and posts the difference when you commit.
Transfers
Inventory → Transfers. Move stock between stores or between branches. One movement out, one movement in, both recorded.
Purchasing
Suppliers
Purchasing → Suppliers. Contact details, payment terms, lead time and a running balance of what you owe. Each supplier can carry its own price per ingredient.
Purchase orders
Purchasing → Purchase Orders. Draft, approve, send. The reorder suggestion reads what is below its reorder level and which supplier is cheapest per base unit, so a weekly order is mostly a matter of checking a list.
Goods receipts
Purchasing → Goods Receipts. Booking in a delivery is the only document that touches stock. It handles what actually happens at a back door:
- Partial deliveries. Order 20 kg, receive 12 today and 8 on Thursday. The order closes itself when nothing is outstanding.
- Landed cost. Freight and duty are spread across the lines by value, so an expensive line carries more of the delivery charge than a cheap one.
- Returns. Stock goes back out and the debt shrinks.
What you owe goes up with the delivery, not with the order — an order is a promise, a delivery is a debt.
Customers
Customers. One row per person, whether they were added at the counter or signed up on the website. Phone number is the practical identity: people give a number at a till and an email only when a form insists.
Each customer carries their order history, what they usually order, saved addresses, points, gift cards, and an allergy note that appears on every kitchen ticket for them.
Segments
Worked out from the order count and the last order date, not stored: New, Active, Slipping away, Lost. The filter on the list uses the same definition, so the regular who has not been in for four months is one click away.
Loyalty & gift cards
Customers → Loyalty.
Points ship switched off. A loyalty scheme is a real liability — every point is something a customer can walk in and spend — so Resto does not start accruing one until you decide to. Turn it on at the bottom of the Loyalty screen.
How it earns
| Setting | Meaning |
|---|---|
| Points per unit | How many points one unit of currency earns. |
| Point value | What one point is worth when spent. |
| Minimum to redeem | Stops a two-point redemption at the till. |
| Expiry | In months. Zero means never — check your local rules. |
Points are earned on the net of an order, not the gross. Paying points on tax is giving the taxman's money away twice. Earning is recorded once per order, so a replayed payment cannot pay out again.
Gift cards
Customers → Gift Cards. Issue a card for an amount; it gets a code and a balance. Spending one is a payment method at the till. A card cannot be overspent — it pays what it has and the rest is settled another way.
Both points and gift cards are ledgers with a derived balance. Nobody types a balance in, and the Loyalty screen shows the total liability so you always know what you owe.
Coupons
Customers → Coupons. Four kinds: a percentage off, a fixed amount off, a free item, or free delivery.
The rules are deliberately expressive, because "10% off" is the easy half. Every restaurant eventually wants free delivery over 25, Tuesdays only, first order, one per customer:
| Rule | What it does |
|---|---|
| Cap the discount | On a percentage. Without it, a percentage off a party of twenty costs whatever they ordered. |
| Minimum spend | Below it the code is refused — with a message that says how much more is needed, not just "invalid". |
| Channels & order types | Online only, delivery only, and so on. |
| Days & times | Tuesdays, or between 3 and 5. |
| Date window | From and until. |
| Total uses | How many times in all. |
| Uses per customer | The one that actually stops abuse. |
| First order only | For a welcome code. |
| Branch / customer group | Limit it to one site or one group. |
A code is only spent when an order exists, so an abandoned basket never burns a single-use code. A code that has been used cannot be deleted — it is switched off instead, because deleting it would orphan the discount on somebody's receipt.
Online store & QR menu
Delivery → Online Store configures it; the shop itself lives at
/shop.
The menu page
Server-rendered, not a JavaScript app. A QR menu a search engine cannot read is a marketing asset thrown away, and somebody standing outside your door on a weak signal should get text before they get a framework.
Ordering
Guest checkout by default. Forcing a stranger to register before they can buy a pizza is the most reliable way to lose the sale. An account is offered — it saves an address and counts points — never required.
Online orders are ordinary orders. They appear on the same list, print the same kitchen tickets and land in the same reports as anything rung up at the till. Prices come from the same price engine, so an integration cannot sell at a price you never set.
Order tracking
Every order gets a tracking page at /shop/order/{id}. The unguessable id
is the whole authorisation — a guest has no account to log into. The page polls for
progress and asks for a rating once the order is finished.
The controls that matter mid-service
| Control | When you reach for it |
|---|---|
| Busy mode | 8 p.m. on a Friday, kitchen drowning. Adds minutes to every quoted time without closing the shop. |
| Pause online orders | Stops new orders entirely. Existing ones carry on. |
| Opening hours | Per day, per branch. A closing time before the opening time means service runs past midnight. |
| Prep time | The normal quote when things are calm. |
Delivery
Zones
Delivery → Delivery Zones. A zone is either a list of postcodes or a radius from the branch. Each carries a fee, a minimum order, an optional free-over threshold and an ETA.
Zones are checked in order, so a specific postcode zone can sit in front of a catch-all
radius. Postcodes match on the outward part and ignore case and spacing — an entry of
SW1 covers everything in SW1.
Without at least one zone the shop refuses every delivery order. A radius zone also needs the branch latitude and longitude, set on the Online Store screen.
Where the orders come from
Two places, and they land on the same board: a customer ordering on the online store, and a cashier taking it at the counter or over the phone — choose Delivery as the order type at the till and the order panel asks for the address. See A delivery order at the till.
The difference is what each does with an address no zone covers. The shop refuses it, because nobody is there to make a judgement. The till takes it and puts it on the board with no fee and no promised time, because the cashier has already said yes to the person on the phone.
The dispatch board
Delivery → Dispatch Board. What is waiting, who is out, and how late it is. Assign a run to a rider or let Resto pick whoever has fewest in progress, mark it picked up, then delivered or failed.
Riders and cash
Cash collected on a doorstep moves onto the rider and stays there until they hand it in. The board shows what each is holding, and settling it is one button. Without that, the money is missing from the drawer and nobody can say where it went.
The fee is snapshotted onto the order when it is placed, so changing your delivery charge on Friday does not retroactively change what Thursday's customer was quoted.
Reservations
Front of House → Reservations. One day at a time, because that is how a host reads the book.
Availability is worked out from capacity and turn time rather than from a fixed grid of slots: six four-tops seat rather more than six parties across an evening, and a booking system that pretends otherwise turns away money.
- Bookings taken online wait for a human unless you switch auto-confirm on. Bookings taken by staff are confirmed on the spot.
- A host on the phone can overbook deliberately — there is a book it even if we look full switch, for when you know something the grid does not.
- Seating a booking opens a table session, so the party lands on the floor plan.
- No-shows are recorded, which is worth knowing about a number that does it repeatedly.
Waitlist
On the same screen. Add a walk-in with a party size, and Resto quotes a wait based on the queue in front of them rather than a flat guess. Call them when a table frees, then seat them straight onto it.
Feedback
Customers → Feedback. Customers are asked to rate an order on the tracking page once it is finished.
Nothing is published until you publish it — an unmoderated review widget on a restaurant website is a liability, not a feature. The point of this screen is not the five-star ones; it is finding Saturday's two-star before the customer gives up and puts it somewhere public. The Needs an answer filter shows exactly those.
Attendance & leave
The clock
Staff clock in at the terminal: /pos/clock, a keypad and a PIN. It is
built for a doorway, with wet hands and a coat still on.
Breaks are unpaid and are subtracted from the shift. A break left running is closed with the shift rather than quietly paid for. Nobody can be clocked in twice — two taps a second apart would otherwise pay one shift twice.
A shift that starts at 10 p.m. and ends at 2 a.m. belongs to the night it
started, controlled by business_day_start_hour.
Timesheets
Staff → Attendance. Who is in the building right now, hours per person for the period, and every entry with the ability to correct one. Corrections record who made them and when — an edited timesheet that does not say who edited it is worth nothing in a dispute.
Leave
Staff → Leave. Holiday, sick, unpaid or other. Days are counted as working days, so Monday to Friday is five and not seven. Approved paid leave appears on the payslip at the person's normal rate, and the panel on the right shows who is off in the next fortnight — which is what the rota actually needs.
Payroll
Staff → Payroll. A pay run reads the timesheets for a period and draws up a payslip for everyone.
Resto does not calculate payroll tax. It changes by country and by year, and getting it subtly wrong is worse than not offering it. Deductions are entered as a figure your accountant gives you.
What it works out
- Hours and overtime. Overtime is counted week by week, not across the whole period — fifty hours one week and thirty the next is ten hours of overtime, not zero.
- Salaries, pro-rata across the period.
- Tips, split by hours worked among those who share in the pool. The last share absorbs the rounding, so the shares add back to the pool exactly.
- Commission, on what each person personally sold.
- Paid leave, at the normal rate.
Draft, approve, pay
A draft rebuilds from the clock as often as you like — somebody always forgets to clock out and the timesheet gets fixed afterwards. Approving freezes the payslips and posts the cost to the books. After that a correction is a fresh run, not an edit: the point of a payroll record is that it says what was actually paid.
Rate and pay type are copied onto each payslip, so a rise next month does not rewrite last month's.
Accounting
Double-entry books that keep themselves. Everything the restaurant already records — a sale, a delivery, an expense, a pay run — posts itself as a balanced journal. Nothing is typed in twice.
Chart of accounts
Finance → Chart of Accounts. The installer creates a short default chart. It is deliberately small: a restaurant needs to know what it sold, what the food cost, what it spent and what it owes. Anything longer is a chart nobody maintains and every posting lands in "Miscellaneous".
Rename or renumber anything freely — the automatic postings look accounts up by a hidden key, not by name or code. Accounts marked system cannot be deleted for that reason.
What posts automatically
| When | The books record |
|---|---|
| A sale closes | Cash or card in, revenue out, tax owed, tips owed, discounts given — plus the food leaving stock at cost. |
| A delivery is booked in | Stock up, supplier owed. |
| A supplier is paid | Supplier owed down, bank or cash down. |
| An expense is recorded | The category's account up, bank or cash down. |
| Stock is wasted or counted | Wastage or variance, against stock. |
| A pay run is approved | Wages, tips discharged, net owed to staff. |
Tax and tips are never revenue. Tax collected is money held for the authority; tips belong to the staff. Both are debts, and booking either as income overstates the profit built on it.
Four rules
- Debits equal credits. An unbalanced journal cannot be saved.
- A journal is never edited. A mistake is corrected by a reversing journal that quotes it, so the books show both the error and the correction.
- One posting per source. A replayed sale is a no-op, not double books.
- Nothing lands in a closed period.
Statements
Trial Balance, Profit & Loss and Balance Sheet all read the same journal lines, so they agree with each other by construction. Each says plainly whether it balances rather than leaving you to add it up.
Period close
Finance → Period Close. Closing a month stops anything being posted or backdated into it, so the figures you gave your accountant in March cannot quietly change in June. A correction after a close is a journal dated today. Reopening a month is possible and is written to the activity log.
Expenses
Finance → Expenses. Rent, power, wages, card fees. Food is not entered here — a goods receipt already records what was spent on ingredients, and entering it twice is the fastest way to produce a profit figure that disagrees with the bank.
Reports
| Report | Answers |
|---|---|
| Sales | Revenue by day, by hour, by order type, by channel, by payment method and by staff member. Average check, covers, and the exceptions worth a second look — voids, discounts, refunds. |
| Food cost | Gross margin per item, and the menu-engineering quadrants: what sells and makes money, what sells and does not, and what does neither. |
| Inventory | Stock valuation, what is below its reorder level, wastage, and the variance a stocktake found. |
| Financial | Profit and loss from the operational data, expenses by group, and a tax summary for a return. |
Every report takes a period and a branch, compares against the previous period, exports to CSV, and prints. Printing uses the browser, which means a PDF on every platform without Resto shipping a PDF engine.
Charts are drawn in CSS rather than canvas: they print, they follow the theme, they need no JavaScript, and they survive being saved as a PDF.
Activity log
Staff → Activity Log. Every void, discount, price override, refund, timesheet correction, reversed journal and reopened period, with who did it, when, from which address.
This is the trail restaurant owners buy POS software for. Filter by person, by action type and by period.
REST API
For a delivery aggregator, a self-order kiosk, a dashboard of your own.
Tokens
Settings → API Tokens. Create a token, choose which member of staff it acts as, and optionally limit it to particular sections. The token is shown once — only a hash is stored, and a token list that can show you the secret is a token list that leaks every secret.
A token can never do more than its owner. Take a permission away from somebody and their integrations lose it too.
Calling it
curl https://yourdomain.com/api/v1/ping \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Every response has the same shape — data under data, pagination under
meta — so a client never has to guess where the payload is.
Endpoints
| Method | Path | Needs | What it does |
|---|---|---|---|
| GET | /api/v1/ping | any token | Confirms the token works and reports what it may reach. |
| GET | /api/v1/menu | menu | The menu priced for a channel and order type, with modifiers and availability. |
| GET | /api/v1/orders | orders | Orders, filterable by branch, status, channel and date. |
| POST | /api/v1/orders | orders | Creates an order. |
| GET | /api/v1/orders/{uuid} | orders | One order in full, with lines, payments and delivery. |
| PATCH | /api/v1/orders/{uuid}/status | orders | Moves an order along. |
| GET | /api/v1/stock | inventory | Levels and values, optionally only what is low. |
| GET | /api/v1/ingredients | inventory | The ingredient list. |
| GET | /api/v1/customers | customers | Customers, searchable by name or phone. |
| GET | /api/v1/reservations | reservations | Bookings for a date. |
| GET | /api/v1/summary | reports | The day's numbers for a dashboard. |
Creating an order
POST /api/v1/orders
{
"uuid": "8f14e45f-ceea-467a-9e4c-3b1d2a5f7b90",
"type": "delivery",
"customer": { "name": "Sam", "phone": "07700 900001" },
"lines": [
{ "variant_id": 12, "qty": 2, "modifiers": [{ "modifier_id": 5 }] }
]
}
Send a uuid and retries are free. Replaying the same one
returns the existing order instead of creating a second. Prices are always taken from
your database, never from the payload — a request claiming a steak costs a penny gets a
steak at the menu price.
Rate limits and errors
120 requests a minute per token by default (api_rate_limit), counted per
token rather than per address so several integrations behind one office connection do not
throttle each other.
| Status | Means |
|---|---|
401 | Missing, unknown, disabled or expired token. |
403 | The token may not reach that section. |
422 | The payload was rejected; errors says which field. |
429 | Rate limited. |
503 | This copy of Resto has not been installed yet. |
Payment gateways
Settings → Payment Gateways. Two halves: what the till accepts, and whether the website can take a card.
At the till
Cash, card, store credit, gift card and on-account are set up for you. You can add your own — a meal voucher, a local wallet — and the flags are behaviour, not decoration:
| Flag | What it changes |
|---|---|
| Counts in the cash drawer | Whether it reaches the cash-up. Tick it only for money that physically ends up in the till, or the drawer will never balance. |
| Can give change | Handing cash back against a card tap is a hole in the drawer, not a feature. |
| Pops the drawer | Opens the till on payment. |
| Asks for a reference | An auth code, a voucher number, a card serial. |
Methods are switched off, never deleted — every payment ever taken names one, and removing it would leave old orders unable to say how they were settled. Cash cannot be switched off at all.
Card payments online
Through Stripe Checkout. The customer is handed to Stripe's own payment page and comes back afterwards, so the card number never touches your server — which keeps your PCI obligation to the shortest questionnaire there is. Installing a till should not hand you a compliance project.
-
Create a Stripe account
Copy the two API keys from its dashboard. Start with the test keys — they begin
sk_testandpk_test. -
Paste them in and save
Then press Test the connection. It asks Stripe whether the keys work, so you find out now rather than when a customer does.
-
Add the webhook
The screen shows the address. In Stripe, add it as an endpoint and subscribe it to
checkout.session.completed. Stripe gives you a signing secret; paste that in too. -
Switch it on, and place a test order
Stripe's test card is
4242 4242 4242 4242with any future expiry. Check the order marks itself paid. -
Swap in the live keys
Only once a test order has gone all the way through.
Without the signing secret, no payment will ever be recorded. That is deliberate. The browser is never allowed to say a payment succeeded — anyone can open the page it comes back to. Only a webhook that Stripe signed marks an order paid, and an unsigned, forged or stale one is refused before a single row is read.
What the customer sees
With it switched on, online checkout offers Pay now by card alongside paying on collection or to the rider. The order is created before the payment page opens, so a customer who abandons it leaves you an order to chase rather than nothing at all — and the tracking page carries a Pay by card button so they can come back and finish.
The confirmation comes from Stripe, not from the customer's browser, so an order can read as unpaid for a second or two after they return. It settles itself.
Refunds
Refund a card payment in the Stripe dashboard, then record the refund in Resto as usual so the books and the stock agree. Resto does not push refunds to Stripe — a refund issued by accident from a POS screen is very hard to take back.
Languages
Settings → Languages. Resto ships English, and can be translated into any of the languages listed there — including Arabic, which loads a full right-to-left stylesheet automatically.
There is no template to fill in. Every string in Resto is its own
key — the English sentence itself — so the untranslated product reads as English by
construction, and a string you have not got to yet falls back to English rather than
going blank or showing you messages.save.
Translating
Open a language and you get every string the product uses, in pages of a hundred, with the English on the left and a box on the right. Filter to not translated yet to work through the gap, or search for a phrase you saw on screen.
Each page saves on its own and merges into what is already there, so translating page four does not wipe pages one to three.
Translating offline
Download gives you a JSON file with every string, translated or not — which is also the template to hand to a translator. Import takes it back. Anything in the file that this version does not use is ignored rather than stored, so an edited file cannot fill the table with junk.
Placeholders
Some strings contain a placeholder like :count or :name.
Keep them exactly as they are, in whatever position the sentence needs — the value is
substituted at the placeholder, so moving it is fine and renaming it is not.
Switching one on
A language has to be turned on before it appears in the language menu. The default language is always available whatever its switch says — otherwise the menu would offer a language the site will not serve. Change the default on General Settings.
Backups
Two things need backing up:
- The database. Everything is in it. Use whatever your host provides
— cPanel, a scheduled
mysqldump, your provider's snapshots. public/uploads/. Logos and menu images live here, not on a storage disk.
mysqldump -u USER -p DATABASE > resto-$(date +%F).sql
tar -czf resto-uploads-$(date +%F).tar.gz public/uploads
Keep a copy of .env somewhere safe too. It holds APP_KEY,
and restoring a database without the key it was encrypted alongside will sign everybody
out and invalidate saved sessions.
Updating
A release is a ZIP. There are two ways to install it: let Resto do it from
Settings → Backup & Update, or copy the files yourself and run the
database step afterwards. Both keep your data, and neither needs a shell. The version you
are on is in the footer of every back-office page, and in version.txt at the
root of the install.
Pick a quiet moment. While an update runs the site is offline for everyone else — tills, kitchen screens and the online shop included — usually for a minute or two.
Before you start
- Take a backup and download it. Settings → Backup &
Update → Take a backup now, plus a copy of
public/uploads/. The updater takes its own backup as well, but the one on your computer is the one you can restore from anywhere. - Check the version. Only a release newer than the one installed will go in. The same version is refused as already installed, and downgrades are refused outright.
- Leave room on the disk. The updater unpacks the release beside the live copy and keeps the old files as a backup, so it needs free space for roughly two more copies of the application. It checks before it starts and tells you if there is not enough.
From the browser
Open the updater
Settings → Backup & Update → Install an update. The page is
/system-update, and it needs the Settings permission.Upload the release ZIP
Drop it on the page. A marketplace download sometimes wraps the release in a second ZIP next to this documentation — upload that as it is, and Resto finds the release inside.
Read the checks
Before anything changes, the page confirms the package is complete and newer than what is installed, the server's PHP version and extensions are enough, the application folders are writable, there is disk space, the database answers, and no other run is in progress. A failed check blocks the update and says why.
Press Install
The run is a chain of short steps you can watch: a backup of the database and the files, the new release unpacked to one side, the site put into maintenance, the files swapped in one move, the migrations, your translation edits carried over, caches cleared, and a health check of the result. Keep the tab open.
Hard-refresh
Ctrl + Shift + R (Cmd on a Mac) once the page says it is done. If anything looks unstyled, the browser is still holding the old files.
If something fails after the files are swapped, the updater rolls itself back: the previous files and the database come back from the backup it just took, and the page says so. If the run stops part-way — a closed tab, a server timeout — nothing is lost. Return to the same page and press Continue where it stopped, or Roll back to the previous version. The page stays reachable while the rest of the site is in maintenance, so it doubles as the way out of an interrupted run.
Backups taken by the updater are listed at the bottom of the same page.
Each holds the database, the replaced files and .env, stored under
storage/app/updater/ where the web cannot reach them. The newest three are
kept by default; change the number there. Any of them can be restored from the page,
which puts both the files and the database back as they were before that update.
.env, storage/ and public/uploads/ are never
touched, in either direction. Translation edits made in Settings
→ Languages survive too: an edited string keeps your wording, an untouched one
takes the release's, and a language the release does not ship stays as it was.
By hand
The route to take when the browser updater cannot run — a 1.0 install, a package that fails its checks, a host you would rather do by FTP.
Back up first
Database and
public/uploads/. Every time.Copy the new release over the old one
Keep your own
.env,public/uploads/andstorage/. Everything else can be replaced.Update the database
Open
/updateand press Update database. It runs the outstanding migrations and clears the caches; a large database can take a few minutes, so keep the tab open.Hard-refresh
Ctrl + Shift + R, as above.
The install marker stays where it is, so the wizard does not reappear.
A hand copy replaces lang/, and with it any translation edits. Download
each language you have edited from Settings → Languages
first, and upload it again afterwards — or use the browser updater, which carries the
edits over by itself.
Coming from 1.0
1.0 has no updater page, so the first upgrade is by hand.
Copy the new files, then open /update — the page arrives with them. After
that:
- Activate your licence. The wizard asks for it on a fresh install; an upgraded one does not run the wizard, so go to Settings → Licence and enter the licence key or Envato purchase code. Until then staff who can open Settings see a reminder, and nothing is blocked.
- Supplier accounts fill themselves in. Existing deliveries and payments are carried into the new supplier ledger on the first migration, linked to the journals they already posted. No balance changes; where the stored balance and the history disagreed, the difference is carried as an opening entry dated before the first movement.
- Every later update comes through the browser.
Troubleshooting
| Symptom | Cause and cure |
|---|---|
Every page redirects to /setup | storage/app/installed is missing. Finish the wizard, or create the file if the install is genuinely complete. |
/setup loads on a live site | Same file, missing. Anyone reaching it could reinstall over you — create it immediately. |
| Blank white page | Almost always a permission problem. Make storage/ and bootstrap/cache/ writable, then check storage/logs/. |
| 500 after an update | Stale cache. Open /update and press Update database, or run php artisan optimize:clear. |
| The updater refuses the ZIP | Read the check that failed. Most often the package is the version already installed, or older — only a newer release goes in. |
| An update stopped part-way | Open /system-update and press Continue where it stopped, or roll back. The page works while the site is in maintenance. See Updating. |
| No styling anywhere | public/build/ is missing or the document root is wrong. Confirm the domain points at public/. |
| An item will not appear on the till | It has no price in any book, it is off for that channel, it is outside its schedule, or it is 86-ed. |
| The online shop says it is closed | Opening hours for today, accepts online orders switched off, or the branch is inactive. All three are on the Online Store screen. |
| The shop refuses every delivery | No delivery zone covers the address — or no zones exist at all. |
| Stock is not moving | The item has no recipe, or inventory_deduct_on_sale is off. |
| The cash-up is short | Check Staff → Shifts for cash movements out of the drawer, and the dispatch board for cash still on a rider. |
| An order has no journal | The chart of accounts was incomplete when it closed. Install the defaults on the Chart of Accounts screen; a posting failure is recorded in the activity log and never blocks a sale. |
| Kitchen screen not updating | It polls; check the device actually has a connection. Nothing here needs websockets. |
| Nothing prints after payment | Print automatically when an order is paid is off. Switch it on, or press Receipt on the till after the sale. |
| Kitchen tickets do not print (browser) | No station screen is open beside the printer, or its printer icon is off. See Printing through the browser. |
| Tickets stay Waiting (Resto Print app) | The app is not running, or the computer is off or asleep. Print app connections shows whether it is online. |
| Jobs Failed: "not matched to a printer" | That Resto printer has no printer chosen in the app on the computer. Choose one, then Retry. |
| The app says the key was refused | The connection was removed in Resto. Create a new key and connect again. |
| Receipts print a long blank tail | Set the paper size in the printer's Windows driver to the roll (58 or 80 mm), not A4 or Letter. |
Where the logs are
storage/logs/laravel.log. Turn APP_DEBUG on in
.env only long enough to read an error, then turn it back off — a debug page
on a live site leaks your configuration.
Deliberately not here
Every link in the sidebar opens a real screen. A few things a restaurant system could plausibly do are absent on purpose, and this guide would rather name them than let you find out:
- No printer drivers on the server. Printing goes through the browser or the Resto Print app, which both use the printer's own Windows driver. A driver on the server would mean a vendor library on a shared host and a support queue about USB.
- No card-machine integration. The Card tender at the till records that a card was used; the terminal is your bank's. Integrating one ties a restaurant to a single acquirer, and the ones worth integrating with differ in every country. Online card payments are a different matter — see Payment gateways.
- No unattended updates. Resto does not fetch releases or install them on a schedule. You upload the ZIP and watch it go in, with a backup before and a rollback if it fails.
- No restore button. Restoring overwrites everything, and a mis-click there costs a business its trading history. The command is on the screen instead.
- No payroll tax. It changes by country and by year, and getting it subtly wrong is worse than not offering it. See Payroll.
- No cron and no queue worker. Nothing is scheduled and nothing is queued, so Resto runs on hosting that forbids long-running processes.
Changelog
1.0
First release. POS with offline support, kitchen display and printed tickets, dining room and waiter app, recipe-level inventory, purchasing, QR menu and online ordering with card payments, delivery, reservations, customers with loyalty and coupons, staff with attendance and payroll, double-entry accounting, reports and a REST API — plus a browser installer, a translation manager and database backups.
Credits & support
Resto is built on Laravel 13 with Blade, Tabler UI and Alpine.js. QR codes are drawn by
bacon/bacon-qr-code. Everything else is written for this product.
If something here does not match what you see on screen, the product is right and this document is wrong — please report it, and it will be corrected.
Resto documentation · version 1.0
Thank you for buying it.