Recipes / Daily close (Z-report) dashboard

Finance

Daily close (Z-report) dashboard

Reconcile one day of trading: the Z-report and the payment breakdown come from the same pipeline, so they always match to the cent.

GET/api/reports/daily-close GET/api/reports/payments GET/api/payment-methods

The same numbers our back office shows store managers.

Pull the daily close for one day

One call per day is the whole Z-report: turnover (incl/excl/VAT), non-revenue money (gift cards, tips), the payment breakdown, and the order count. It reuses the exact pipeline behind /api/financial-report, so the numbers reconcile 1:1 to the cent. Dates are Europe/Amsterdam.

# the Z-report for Monday July 14th
curl -s "https://api.storekeeper.me/api/reports/daily-close?date=2026-07-14" \
  -H "Authorization: Bearer $TOKEN"
{
  "date": "2026-07-14",
  "location_id": null,
  "currency": "EUR",
  "turnover": { "incl_vat": 3412.85, "excl_vat": 3131.06, "vat": 281.79 },
  "non_revenue": {
    "gift_card_sales": 75.00,
    "tips": 12.50,
    "payments_on_invoice": null,
    "prepayments": null,
    "total": 87.50
  },
  "payments": [
    { "provider_method_type_id": 3, "type_alias": "TerminalDevice", "name": "Card terminal", "value": 2410.30 },
    { "provider_method_type_id": 5, "type_alias": "Cash", "name": "Cash", "value": 914.05 },
    { "provider_method_type_id": 8, "type_alias": "GiftCard", "name": "Gift card", "value": 88.50 }
  ],
  "payments_total": 3412.85,
  "balance_check": { "payments_match_incl_vat": true, "difference": 0 },
  "order_count": 186
}
Gotcha: pass location_id if you close per branch. Without it you get the whole account rolled into one Z-report, which will not match a single till.

Pull the payment breakdown for the same day

The standalone payments report is the same computation exposed for reconciliation. For one day, set from and to to the same date; the response also carries the paid turnover and a built-in balance check.

curl -s "https://api.storekeeper.me/api/reports/payments?from=2026-07-14&to=2026-07-14" \
  -H "Authorization: Bearer $TOKEN"
{
  "from": "2026-07-14",
  "to": "2026-07-14",
  "location_id": null,
  "currency": "EUR",
  "payments": [
    { "provider_method_type_id": 3, "type_alias": "TerminalDevice", "name": "Card terminal", "value": 2410.30 },
    { "provider_method_type_id": 5, "type_alias": "Cash", "name": "Cash", "value": 914.05 },
    { "provider_method_type_id": 8, "type_alias": "GiftCard", "name": "Gift card", "value": 88.50 }
  ],
  "payments_total": 3412.85,
  "paid_turnover_incl_vat": 3412.85,
  "balance_check": { "payments_match_incl_vat": true, "difference": 0 }
}

Resolve payment method labels via type_alias

Fetch the account's payment method catalog once and cache it. Key your dashboard labels (and any ledger mapping) on type_alias, never on the numeric id.

curl -s https://api.storekeeper.me/api/payment-methods -H "Authorization: Bearer $TOKEN"
{
  "count": 3,
  "data": [
    { "provider_method_type_id": 3, "type_alias": "TerminalDevice", "name": "Card terminal" },
    { "provider_method_type_id": 5, "type_alias": "Cash", "name": "Cash" },
    { "provider_method_type_id": 8, "type_alias": "GiftCard", "name": "Gift card" }
  ]
}
Gotcha: provider_method_type_id is registered per account: id 5 is not Cash everywhere. Cash lives on an internal provider registered for the account, so the id differs between accounts while type_alias stays "Cash". Always match on the alias.

Verify the totals match and display

Because daily-close and payments come from one pipeline, the sums must agree to the cent. Assert the invariants below before rendering; a mismatch means your date or location filter differs between calls, not rounding.

# invariants for the Z-report screen
sum(payments[].value)             == payments_total
balance_check.payments_match_incl_vat == true
daily-close.payments_total        == payments.payments_total   # same date, same location_id
Gotcha: non_revenue money (gift card sales, tips) is deliberately outside turnover. A gift card sale shows up in the payments the day it is sold and in turnover the day it is redeemed. Show it as its own line on the Z-report, do not add it to turnover.