Fooodo / Docs

Order flows

Pay-First versus Pay-Later — when to use each, and how each behaves end-to-end.

Fooodo supports two distinct order flows. They differ in when the kitchen sees the order and when payment happens. The choice depends on the service style, not the restaurant — a single restaurant can run different flows on different tables.

Pay-First (the older flow)

Best for: takeaway, quick service, food courts, anywhere the guest pays before eating.

1. Guest scans QR, builds cart
2. Guest pays
3. (only after successful payment) Order exported to R-Keeper
4. Kitchen prepares
5. Order delivered or collected

In this flow, the kitchen never sees an unpaid order. R-Keeper sees a single order export per cart. If payment fails or is abandoned, nothing reaches the kitchen.

Pay-Later (the newer flow)

Best for: dine-in, table service, multi-round service where guests order over time.

1. Guest scans QR, builds cart
2. Items sent to R-Keeper kitchen immediately
3. Guest can add more rounds (each round sent incrementally)
4. When ready, guest pays
5. Order locked during payment, marked paid in R-Keeper after success

Each new round is added to the same R-Keeper order — synced_to_rkeeper_at on each order item tracks which rounds have already been exported. The order stays open in R-Keeper from the first round until payment.

Why the flows differ

The mechanical difference is straightforward — Pay-First has one R-Keeper export; Pay-Later has many. The operational difference matters more:

  • In Pay-First, the kitchen does no extra work if a guest abandons the cart. But the guest experience is wrong for dine-in: people don't pay before they eat, and asking them to do so feels like a takeaway counter.
  • In Pay-Later, the guest experience matches a normal restaurant. But the operator has to accept that some orders may not get paid (a guest walks out, a card fails). The same risk exists with paper bills, so operators rarely flag this as new.

Configuring the flow

Flow is set per-table or as a restaurant default in the admin panel. A restaurant can mix flows — for example, dine-in tables on Pay-Later, takeaway counter on Pay-First, both running through the same Fooodo install.

States, in practice

Orders move through a state machine. Most operators only see four of these:

StateWhat it means
CreatedCart exists, no items submitted yet
InProgressItems submitted to R-Keeper, awaiting more or payment
ReadyToBePaidGuest finished ordering, payment pending
PaidPayment succeeded, R-Keeper marked paid
FinishedOrder closed, terminal success state

There are three failure-adjacent states worth knowing:

StateWhat it means
LockedR-Keeper has the order open (waiter editing). Auto-retries with backoff.
ErrorExport to R-Keeper failed after all retries. Needs manual intervention.
CancelledOrder was cancelled or timed out unpaid

Most Locked states resolve in seconds. Persistent Locked usually means a waiter has the order open in R-Keeper and forgot to close it.

Error is the only state that needs human intervention. The rkeeper-errors log channel records what failed; the waiter typically resolves it by recreating the order in R-Keeper directly.

What runs in the background

A few scheduled jobs keep the order layer in sync. Operators do not need to know these by name, but integrators do:

CadenceJob
Every minuteCheck restaurant availability in R-Keeper
Every minuteCancel orders that timed out without payment
Every 2 minPull order updates from R-Keeper
Every 4 minPull table status from R-Keeper
Every 5 minSync item availability
Daily 09:00Full menu sync

If R-Keeper is unreachable, jobs retry with exponential backoff; orders queue in their current state and reconcile when R-Keeper returns.

On this page