Skip to content

Introduction

The ScanFood API lets your own systems read the data a ScanFood point of sale already records — shops, closed transactions and loyalty members. It is read-only, authenticated with a single API key, and designed to be polled on a schedule rather than to drive the till.

Every request goes to one base URL:

https://api.scanfood.co/ext

The version is part of each endpoint path, so a full URL reads https://api.scanfood.co/ext/v1/shops.

  • Accounting and tax exports — pull yesterday’s closed bills, with receipt and tax invoice numbers, VAT and payment breakdowns, into your bookkeeping system.
  • Reporting and BI — load transactions into a warehouse and slice by shop, device, sales channel or product.
  • Franchise consolidation — one franchise-scoped key reads every branch, so head office can total the group without asking each shop for a file.
  • Loyalty and CRM — read members, their points, store credit, rank and coupons, and match them to the bills they appear on.
Resource Endpoint What it returns
Shops GET /v1/shops Every branch this key may read, with its time zone and member provider
Transactions GET /v1/transactions · GET /v1/transactions/{id} Closed bills for one shop: line items, amounts, payments, status
Members GET /v1/members · GET /v1/members/{memberToken} · GET /v1/members/lookup Loyalty members of one brand: points, credit, rank, coupons, visits — and the member token behind a LINE user id you already hold
Specification GET /v1/openapi.json The machine-readable contract — the only endpoint that needs no key

Two properties hold everywhere:

  • Read-only for your data. Every endpoint is a GET. No request creates, changes or deletes anything a shop owns, so a call can always be repeated safely. We do record the calls themselves: the key’s last-used time, a daily counter for your quota, and a request log — key id, path, query string, status, row count and timing — kept for 90 days for support and abuse handling. The secret half of your key is never stored.
  • Pull, not push. You decide when to ask. A common cadence is every 15 minutes for transactions and once a day for members.

Being explicit about the edges saves you a support round-trip:

  • No writes. You cannot create, void or amend a bill, or change a member.
  • No webhooks or push notifications. Nothing calls your servers; you poll.
  • No calls from a browser. Cross-origin requests are refused on purpose, because a key that reaches a browser is a key that has leaked.
  • No product catalogue, stock or SKU endpoints. Line items carry a product id you can join against your own catalogue, but there is no SKU or barcode.
  • No cost or recipe data. Unit costs and ingredient formulas never leave ScanFood, by policy.
  • No separate refund object. A refund at the counter is a voided bill — the transaction comes back with status: "void".
  • No pre-computed loyalty segments. You get visit counts, last visit and the underlying bills; the segmentation is yours to define.
  • No separate test environment. Keys are live keys and read your own real data — see Test data for how to try things out safely.
  • Incremental sync for members is not open yet. Transactions support updatedSince; members must be re-read in full. See Pagination & sync.

The version lives in the path: every endpoint today is under /v1/. Within a version we may add fields to a response or accept new optional parameters; neither breaks a client that ignores what it does not recognise.

To stay compatible with additive changes:

  • Read fields by name; never rely on the order or the number of keys.
  • Branch on the error code, never on the human-readable message — message text can change at any time.
  • Treat enumerations like channel.code as open strings; shops add their own sales channels whenever they like.

A breaking change would ship as a new path prefix, not as a silent edit of /v1/. The current contract is always downloadable from GET /v1/openapi.json, which needs no API key.