Locals BI — Agent API
Alle data en berekeningen van het dashboard, achter één geauthenticeerde API. Bedoeld voor agents: dezelfde endpoints zijn ook als MCP-tools beschikbaar.
Quickstart
Zet je token hieronder — alle voorbeelden op deze pagina vullen 'm dan automatisch in. Het token blijft in je browser en wordt nergens heen gestuurd.
# Draait de API en is je token geldig?
curl -s https://locals-dashboard-omega.vercel.app/api/v1/health
# Omzet per dag, afgelopen week
curl -s -H "Authorization: Bearer $LOCALS_TOKEN" \
"https://locals-dashboard-omega.vercel.app/api/v1/revenue/daily?start=2026-07-01&end=2026-07-07"
# Winst per locatie over juni — dé endpoint voor winstvragen
curl -s -H "Authorization: Bearer $LOCALS_TOKEN" \
"https://locals-dashboard-omega.vercel.app/api/v1/financials/pnl?start=2026-06-01&end=2026-06-30"
Authenticatie & scopes
Elk endpoint verwacht Authorization: Bearer <token>.
Alleen /health en /openapi.json zijn publiek — die geven
geen bedrijfsdata prijs.
| Scope | Mag |
|---|---|
read | Alles lezen: omzet, loonkosten, P&L, personeel, marketing, reviews, reserveringen, forecasts. |
write | Daarbovenop: targets zetten, alerts afhandelen, ontvangers beheren en sync-jobs starten. |
Tokens beheren
Tokens staan in de Vercel-omgevingsvariabele AGENT_API_TOKENS, als
JSON-array. Een token intrekken = die regel weghalen en opnieuw deployen.
[
{"token": "lba_…", "name": "hermes", "scopes": ["read", "write"]},
{"token": "lba_…", "name": "viewer", "scopes": ["read"]}
]
AGENT_API_TOKENS niet gezet, dan
weigert de API élk verzoek met een 503. Dat is bewust anders dan de oudere
cron-endpoints, die publiek worden als hun secret wegvalt.
Foutformaat
{"error": {"code": "forbidden",
"message": "Dit token heeft de scope 'write' niet (heeft: read)."}}
| Status | Betekenis |
|---|---|
| 400 | Ontbrekende of ongeldige parameter |
| 401 | Geen of ongeldig token |
| 403 | Token mist de benodigde scope |
| 404 | Onbekend pad, of de rij bestaat niet |
| 405 | Methode niet toegestaan op dit pad |
| 502/504 | Een bron erachter (Supabase, Eitje, een job) gaf een fout |
Hermes koppelen
De API praat ook MCP, dus Hermes ontdekt alle endpoints als tools — één commando, geen losse skill nodig.
hermes mcp add locals \
--url https://locals-dashboard-omega.vercel.app/api/v1/mcp \
--auth header
# Vul bij de prompt in: Authorization: Bearer <jouw token>
hermes mcp test locals # moet alle tools ontdekken
hermes tools list | grep locals # locals_kpis, locals_financials_pnl, …
De tools heten locals_<operatie> — dezelfde namen als de
operationId's hieronder. Een token zonder write-scope
krijgt de schrijftools niet eens te zien.
locals_labour_daily en
locals_labour_hourly.
Conventies
| Onderwerp | Afspraak |
|---|---|
| Datums | start en end als YYYY-MM-DD, beide inclusief. Maandtabellen accepteren ook YYYY-MM. |
| Locaties | locals-coffee, locals-brunch, flow-brunch, locals-to-go, locals-city — of all. |
| Bedragen | Euro, exclusief btw tenzij anders vermeld. |
| Pagineren | limit (standaard 1000, max 5000) en offset. Bij afkappen staat meta.truncated: true in het antwoord. |
| Sorteren | order in PostgREST-vorm, bv. date.desc of net_revenue.desc. |
| Antwoordvorm | {"data": …, "meta": {…}}. Berekende endpoints zetten hun uitleg in meta. |
Alle endpoints
Gegenereerd uit de live OpenAPI-spec, dus altijd gelijk aan wat de API werkelijk doet.
/api/v1/openapi.json…Vrije query
Voor alles waar geen eigen endpoint voor is. Alleen lezen, alleen tabellen uit de allowlist, maximaal 5000 rijen.
curl -s -X POST -H "Authorization: Bearer $LOCALS_TOKEN" \
-H "Content-Type: application/json" \
https://locals-dashboard-omega.vercel.app/api/v1/query \
-d '{
"table": "lightspeed_products_daily",
"select": "date,product_name,qty,net_revenue",
"filters": {"date": {"gte": "2026-07-01"},
"location_id": {"eq": "locals-coffee"}},
"order": "net_revenue.desc",
"limit": 25
}'
Toegestane operatoren: eq, neq, gt,
gte, lt, lte, like,
ilike, in, is, cs,
cd. De volledige tabel-allowlist staat in de OpenAPI-spec bij
query.
/financials/pnl reconcilieert Exact met de kassa,
/labour/hourly verdeelt loonkosten over de uren. Zelf tabellen
optellen levert andere cijfers dan het dashboard.
MCP-protocol
Voor wie zelf een client bouwt: POST /api/v1/mcp spreekt
JSON-RPC 2.0 over HTTP, protocolversie 2025-06-18.
curl -s -X POST -H "Authorization: Bearer $LOCALS_TOKEN" \
-H "Content-Type: application/json" \
https://locals-dashboard-omega.vercel.app/api/v1/mcp \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Ondersteund: initialize, tools/list,
tools/call, ping. Argumenten van tools/call
zijn één plat object — query-, pad- en bodyvelden door elkaar; de server sorteert
dat zelf uit.
Databronnen & versheid
Handig om te weten hoe actueel een antwoord kan zijn.
GET /api/v1/data-quality geeft de werkelijke versheid per bron.
| Bron | Vult | Ververst |
|---|---|---|
| Lightspeed (kassa) | omzet, producten, uren, tafels | elke 5 min voor vandaag, 's nachts volledig |
| Eitje (rooster) | geklokte en ingeroosterde loonkosten | live bij elk verzoek |
| Exact Online | inkoop, vaste kosten, afschrijving, belasting, bank, cash | dagelijks |
| Nmbrs (loon) | personeel, contracten, werkgeverslast | dagelijks |
| Zenchef | reserveringen | dagelijks |
| Apify → Google | reviews en plaatsstatistieken | periodiek, tweefasig |
| Google Ads | campagnes, advertentiegroepen, zoekwoorden | push vanuit Google Ads Script |
| Meta Ads | spend, bereik, clicks | dagelijks |
| Open-Meteo | weer als forecast-driver | 's nachts |
| SOP-workbook | EOD- en weekrapporten van managers | dagelijks |
Valkuilen
Vier dingen waar een agent anders de mist in gaat.
Winst komt uit /financials/pnl, niet uit optellen
De P&L reconcilieert per kalendermaand:
afgesloten maanden gebruiken Exact-omzet en Exact-loon, inclusief het terugverdelen van
doorbelast loon naar de BV die het boekte; de lopende maand gebruikt live kassaomzet en
Eitje-geklokt loon. Zelf exact_cost_daily optellen geeft daarom andere
cijfers dan het dashboard.
Marketinguitgave niet dubbeltellen
De echte uitgave staat in
/marketing/costs (netto, uit de boekhouding). Bureaus zijn ongeveer
tweederde van het budget en komen niet voor in de ad-API's. Tel
/marketing/google-ads en /marketing/meta-ads dus nooit
bij /marketing/costs op.
Oude kassaomzet heeft gaten
Lightspeed mist Locals Coffee voor
mei en juni 2025. Voor periodes ouder dan de lopende maanden is
/financials/pnl of /revenue/monthly betrouwbaarder dan
/revenue/daily.
Let op degraded en warnings
Is Eitje onbereikbaar, dan mist de
lopende maand zijn loonkost en valt de winst veel te hoog uit. De P&L zegt dat
dan expliciet via degraded: true en een warnings-lijst —
negeer die niet.