Recipes / Accounting export & reconciliation

Finance

Accounting export & reconciliation

Pull a complete, VAT-correct financial period into your bookkeeping: revenue, VAT breakdown, payments, and turnover per group, per location.

GET/api/financial-report GET/api/turnover-groups GET/api/tax-rates GET/api/payment-methods GET/api/locations

Powers our AFAS journal export in production.

Pull the financial report for the period

One call returns the whole bookkeeping picture: revenue, the VAT breakdown, the payment breakdown, and turnover per product group. Dates are inclusive, Europe/Amsterdam.

# the whole month of June
curl -s "https://api.storekeeper.me/api/financial-report?from=2026-06-01&to=2026-06-30" \
  -H "Authorization: Bearer $TOKEN"
{
  "currency": "EUR",
  "revenue": {
    "total_turnover": { "incl_vat": 48210.55, "excl_vat": 42393.40, "vat": 5817.15 },
    "total_cost_of_goods_sold": 19882.10,
    "margin": 0.53
  },
  "direct_paid": {
    "vat_breakdown": [
      { "tax_rate_id": 55, "rate": 0.21, "rate_percent": 21, "excl_vat": 30110.20, "vat": 6323.14, "incl_vat": 36433.34 },
      { "tax_rate_id": 52, "rate": 0.09, "rate_percent": 9,  "excl_vat": 9120.44,  "vat": 820.84,  "incl_vat": 9941.28 }
    ],
    "payments": [
      { "provider_method_type_id": 3, "type_alias": "TerminalDevice", "name": "Card terminal", "value": 31220.10 },
      { "provider_method_type_id": 5, "type_alias": "Cash", "name": "Cash", "value": 8120.55 }
    ],
    "payments_total": 48210.55,
    "balance_check": { "..." : "..." }
  },
  "turnover_by_group": {
    "rows": [
      { "product_group_id": 3, "product_group_code": "BROOD", "name": "Brood", "total_incl_vat": 22110.40,
        "tax_rate_id": 52, "tax_rate_percent": 9, "excl_vat": 20284.77, "vat": 1825.63, "cost_of_goods_sold": 9120.10 }
    ]
  }
}

Resolve the ids to your ledger names

The report speaks in Storekeeper ids. Three small reference calls translate them once per sync; cache the result.

# product_group_id + code (map to your revenue ledgers)
curl -s https://api.storekeeper.me/api/turnover-groups -H "Authorization: Bearer $TOKEN"

# tax_rate_id -> percentage (filter, or you get the whole EU registry)
curl -s "https://api.storekeeper.me/api/tax-rates?country_iso2=NL" -H "Authorization: Bearer $TOKEN"

# provider_method_type_id -> type_alias (map to your payment ledgers)
curl -s https://api.storekeeper.me/api/payment-methods -H "Authorization: Bearer $TOKEN"
Gotcha: provider_method_type_id is registered per account. Id 10 can be "On invoice" on one account and something else on another. Always key your mapping on the stable type_alias (Cash, TerminalDevice, OnInvoice, ...), never on the numeric id.
Gotcha: /api/tax-rates without country_iso2 returns every EU rate, Austria first. Filter it.

Split per location if you book per branch

Pass location_id to scope the whole report to one physical site. List locations once to find the ids. A location (physical site) and a shop (sales channel) live in different id spaces; the report's per_shop rows carry shop ids, the filter takes a location id.

curl -s https://api.storekeeper.me/api/locations -H "Authorization: Bearer $TOKEN"
curl -s "https://api.storekeeper.me/api/financial-report?from=2026-06-01&to=2026-06-30&location_id=14" \
  -H "Authorization: Bearer $TOKEN"

Book the journal and verify it closes

Book one revenue line per (product group × VAT rate) from turnover_by_group.rows, the VAT payable from vat_breakdown, and one debit line per payment method. Before posting, assert that the sums reconcile; they come from one pipeline, so a mismatch means your period or location filter differs between calls, not rounding.

# invariants to assert before posting
sum(turnover_by_group.rows[].total_incl_vat) == revenue.total_turnover.incl_vat
sum(vat_breakdown[].incl_vat)               == direct_paid.total
sum(payments[].value)                       == direct_paid.payments_total
Gotcha: a row with product_group_id: 0 means "products without a turnover group". It has no entry in /api/turnover-groups and product_group_code is null. Decide explicitly which ledger it books to; don't let it fall through silently.