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.

status laden… versie — — operaties openapi.json

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.

ScopeMag
readAlles lezen: omzet, loonkosten, P&L, personeel, marketing, reviews, reserveringen, forecasts.
writeDaarbovenop: 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"]}
]
Fail-closed. Staat 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)."}}
StatusBetekenis
400Ontbrekende of ongeldige parameter
401Geen of ongeldig token
403Token mist de benodigde scope
404Onbekend pad, of de rij bestaat niet
405Methode niet toegestaan op dit pad
502/504Een 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.

Stel je vraag gewoon in het Nederlands. Bijvoorbeeld: "Wat was de loonkost van Locals Brunch vorige week en welke uren draaiden verlies?" Hermes combineert dan zelf locals_labour_daily en locals_labour_hourly.

Conventies

OnderwerpAfspraak
Datumsstart en end als YYYY-MM-DD, beide inclusief. Maandtabellen accepteren ook YYYY-MM.
Locatieslocals-coffee, locals-brunch, flow-brunch, locals-to-go, locals-city — of all.
BedragenEuro, exclusief btw tenzij anders vermeld.
Paginerenlimit (standaard 1000, max 5000) en offset. Bij afkappen staat meta.truncated: true in het antwoord.
Sorterenorder 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.

Endpoints laden uit /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.

Gebruik liever een specifiek endpoint. Die bevatten de logica — /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.

BronVultVerverst
Lightspeed (kassa)omzet, producten, uren, tafelselke 5 min voor vandaag, 's nachts volledig
Eitje (rooster)geklokte en ingeroosterde loonkostenlive bij elk verzoek
Exact Onlineinkoop, vaste kosten, afschrijving, belasting, bank, cashdagelijks
Nmbrs (loon)personeel, contracten, werkgeverslastdagelijks
Zenchefreserveringendagelijks
Apify → Googlereviews en plaatsstatistiekenperiodiek, tweefasig
Google Adscampagnes, advertentiegroepen, zoekwoordenpush vanuit Google Ads Script
Meta Adsspend, bereik, clicksdagelijks
Open-Meteoweer als forecast-driver's nachts
SOP-workbookEOD- en weekrapporten van managersdagelijks

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.