iVendNextDevelopers Request a sandbox

Feed a data warehouse from the shop — the incremental BI-feed recipe

This recipe copies the shop's sales, lines, payments and returns into a data warehouse. It copies only what is new, never misses a record the shop wrote while the feed was down, and agrees with the shop's own day-end report. It is for a retailer's analytics team. Reference implementation: samples/s9_bi_feed/bi_feed.py (Python, standard library only; SQLite and CSV as the warehouse — the same logic loads any database). It is built on the event-feed client (tools/feed_client/, recipes/event_feed.md).

When to use it. When reports or dashboards outside the shop need the shop's sales, kept up to date without a full copy every night.

What it keeps

The feed's key is read-only on the business: the log (to mark events done), and read on POS Invoice and POS Closing Entry.

Steps

  1. Give the feed its key, read-only on the business as above, and set it as BI_KEY and BI_SECRET.
  2. Run run as often as you like. It picks up what is new from the event feed (below).
  3. Check each day against the shop with control (below).
  4. If the feed was off, or the file lost its tail, run backfill. To start a fresh file, run rebuild.
  5. Hand the warehouse on with export (CSV).

Four ways in, one result

Command How it picks up
run the event feed: a sale booked, a return booked or a sale cancelled names an invoice; the invoice is read over the API (header, lines, payments) and replaces its rows. The seen-set and the warehouse are in the same SQLite file and written in one transaction, so a kill at any moment leaves each invoice extracted once or not at all, and the feed hands back what was not marked done
backfill independent of the feed: per record type, the invoices modified at or after its watermark. For when the feed was off, or to heal a gap at the end of the file. An upsert is harmless twice, so equal times are read again
rebuild a full refresh into a fresh file: every invoice created since a date
export the warehouse as CSV (sales, lines, payments, control) — the same bytes for the same data

The control total — the day agrees with the shop's own report

BI_KEY=… BI_SECRET=… python3 samples/s9_bi_feed/bi_feed.py control --base … --warehouse state/bi.sqlite --since "2026-10-04 00:00:00"

The shop's own report for a day is the POS Closing Entry: the till's own end-of-day figure.

When the feed is down, and when the till is offline

Limits to know before you build

Technical notes

Proven on our test bench. The bench holds POS Closing Entries, and also back-office Sales Invoices merged from them; the closing is the till's own end-of-day figure.

What the kit has proven (23 checks)

Bounds, stated

This page in the kit