Fooodo / Docs

R-Keeper integration

How Fooodo round-trips with R-Keeper in production, in operational detail.

R-Keeper is the only POS connector running in production today. This page documents how the integration actually works — what data crosses the boundary, in which direction, and what you should expect when something goes wrong.

What Fooodo asks R-Keeper for

RequestPurpose
GetRestaurantMenuFetch the menu (products, categories, prices)
GetRestaurantModifiersGroupsFetch modifier groups and ingredients
GetRestaurantStatusCheck whether the restaurant is online
GetTableStatusGet table-level order state
GetTableOrderStatusGet full order details

These are read-only calls. Fooodo does not modify R-Keeper menus, prices, modifiers, or any reference data. R-Keeper is the source of truth.

What Fooodo writes to R-Keeper

RequestPurpose
PostOrderCreate or update an order; lock orders
PostPayOrderMark an order as paid
PostSendMessageSend a kitchen message
PostApplyPersonalCardApply loyalty cards

Order creation and payment confirmation are the two writes that matter most for service. Both are queued, retried with exponential backoff, and logged.

Per-restaurant configuration

R-Keeper credentials live in the restaurant config. Each restaurant in Fooodo carries:

  • API endpoint URL
  • Restaurant ID inside R-Keeper
  • Optional loyalty pricing endpoint
  • Optional loyalty card program code
  • Optional menu item code for tip routing

Different restaurants in the same Fooodo company can point at different R-Keeper instances. This is how multi-location chains operate today.

Failure handling

The integration is designed to tolerate R-Keeper being briefly unavailable. Three failure modes you will see in practice:

Locked orders

R-Keeper returns error codes 2219 or 13 when a waiter has the order open in the back-office terminal. Fooodo's response:

  • Mark the order Locked
  • Retry export with exponential backoff: 5 s, 10 s, 20 s, 40 s, 80 s
  • If all retries fail, escalate to Error

In normal operation, locks last seconds. A persistent lock usually means a waiter walked away with the order open and the only fix is to close the order in R-Keeper.

Mark-paid retries

When R-Keeper rejects the PostPayOrder call (often because the order is locked), Fooodo retries on a longer schedule: 60 s, 120 s, 180 s, 240 s, 300 s. Five attempts, total ~17 minutes. The slower cadence reflects that paid orders are not blocking service — they are reconciling.

If all retries exhaust, the order is in Error. The Fooodo payment is still recorded; the R-Keeper side needs a manual reconciliation by the waiter.

Restaurant unreachable

If R-Keeper itself is down or the restaurant is offline, Fooodo flips the restaurant to read-only:

  • The customer-facing menu still loads (cached)
  • New orders are blocked
  • Existing orders queue updates

Once R-Keeper comes back, the queued operations drain and the restaurant returns to normal.

Logging

When an integration issue arises, four log channels are relevant:

  • rkeeper-requests — every API call with payload and response
  • rkeeper-errors — only the failures
  • rkeeper-orders — order-specific operations
  • order-flow — state transitions on the Fooodo side

For partner support cases, the request log is usually the first place to look. The most common cause of "the order didn't reach the kitchen" is a momentary R-Keeper outage that the retry budget didn't cover.

Mock mode for development

Development environments can run with RKEEPER_MOCK=true. In this mode, all R-Keeper traffic is faked — useful for partner integrators who want to test against the Fooodo menu app without a live R-Keeper instance.

Production never runs in mock mode. Staging mirrors production by hitting the R-Keeper test environment.

What the kitchen sees

The contract is: an order created through Fooodo arrives in R-Keeper indistinguishably from an order created at a terminal. Same printer routing, same KDS behavior, same reports. Kitchen staff do not need to know Fooodo exists, and waiters keep using R-Keeper exactly as they did before.

This is intentional. The integration is invisible by design; the operating system extends R-Keeper, it does not replace it.

On this page