API

Bistro Content API

Läs restaurangens publicerade innehåll — menyer, sidsektioner, gallerier och öppettider — och ta emot bokningsförfrågningar. Ett JSON-API med API-nycklar du skapar själv i backoffice.

Maskinläsbar specifikation: OpenAPI 3.1 — genererad ur samma scheman som API:et validerar mot, så den kan inte glida isär från verkligheten.

Steg 1

Skaffa en nyckel

Gå till Backoffice → Inställningar → API-nycklar, välj typ och scopes, och skapa nyckeln. Klartexten visas exakt en gång — Bistro lagrar bara en SHA-256-hash och kan aldrig visa den igen. Tappar du bort den återkallar du nyckeln och skapar en ny.

Publicerbar — bis_pub_…

Avsedd för webbläsarkod. Får bara hålla läs-scopes, och kan låsas till en lista av origins. Att den syns i din frontend-bundle är förväntat.

Hemlig — bis_sk_…

Hör hemma på en server du kontrollerar. Krävs för att skriva. Avvisas med 403 om anropet har en Origin-header, dvs. om den hamnat i klientkod.

Steg 2

Autentisera

Varje anrop bär nyckeln som bearer-token. Prefixet före punkten är inte hemligt — det är vad som gör nyckeln identifierbar i loggar och supportärenden utan att någon behöver hantera hemligheten.

http
Authorization: Bearer bis_pub_a1b2c3d4e5f6.<hemlighet>

Organisationen avgörs alltid av nyckeln. Frågeparametern ?org= finns bara som kontroll: pekar den på någon annan organisation svarar API:et 403 organization_mismatch.

Referens

Endpoints

get/api/v1/sitecontent:read

Allt publicerat innehåll i ett anrop

Aggregatet en hel sajt kan renderas från: menyer, sektioner, gallerier, öppettider och avvikelser, plus `revision` att jämföra mot `/api/v1/version`. Detta är efterföljaren till det gamla öppna `/api/content`.

org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.
get/api/v1/versioncontent:read

Innehållets fingeravtryck

Billig poll-endpoint. `revision` är ogenomskinlig — jämför den med den du senast hämtade och läs om innehållet när den ändrats. Cachas aldrig.

org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.
get/api/v1/menusmenus:read

Lista publicerade menyer

Endast metadata — hämta `/api/v1/menus/{slug}` för själva menyinnehållet.

org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.
get/api/v1/menus/{slug}menus:read

Hämta en meny

`body` är ett strukturerat dokument per språk (`byLocale['sv-SE']`), se guiden i /docs. Opublicerade och borttagna menyer ger 404.

slug (path, krävs)
Menyns slug.
org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.
get/api/v1/sectionssections:read

Lista publicerade sidsektioner

Textsektioner (brödtext, citat) i sorteringsordning.

org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.
get/api/v1/galleriesgalleries:read

Lista publicerade gallerier

Inklusive bildlista och layoutkonfiguration.

org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.
get/api/v1/galleries/{slug}galleries:read

Hämta ett galleri

Opublicerade gallerier ger 404.

slug (path, krävs)
Galleriets slug.
org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.
get/api/v1/opening-hourshours:read

Öppettider och avvikelser

`openHoursArr` är söndagsförst: varje dag är en lista av `[öppnar, stänger]` i decimaltimmar (`[]` = stängt, `[[11,14],[17,22]]` = lunch + middag). `exceptions` täcker de närmaste 60 dagarna.

org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.
post/api/v1/bookingsbookings:write

Skapa en bokningsförfrågan

Kräver en hemlig nyckel (`bis_sk_…`) — en publicerbar nyckel kan aldrig hålla `bookings:write`. Bokningen skapas med status `requested` och bekräftas i backoffice. Bokningar kan inte läsas via API:et: gästuppgifter lämnar aldrig Bistro.

post/api/v1/contact-messagescontact:write

Skicka ett kontaktmeddelande

Kräver en hemlig nyckel (`bis_sk_…`) — en publicerbar nyckel kan aldrig hålla `contact:write`. Meddelandet lagras och personalen notifieras per e-post. Meddelanden kan inte läsas via API:et — samma resonemang som för bokningar.

post/api/v1/newsletter/subscribersnewsletter:write

Lägg till en nyhetsbrevsprenumerant

Kräver en hemlig nyckel (`bis_sk_…`) — en publicerbar nyckel kan aldrig hålla `newsletter:write`. `consent` måste vara `true`. Idempotent — en redan prenumererande e-post svarar 200 utan att skapa en dubblett.

post/api/v1/menusmenus:write

Skapa en meny

Skapar en ny meny. Idempotent via `Idempotency-Key`-header — samma nyckel och body ger samma svar utan att skapa en dubblett. Kräver hemlig nyckel och att CMS-modulen är aktiv.

patch/api/v1/menus/{slug}menus:write

Uppdatera en meny

Uppdaterar metadata (titel, kind, published) eller body för en meny. Skicka `If-Match: "<revision>"` (från `/api/v1/version`) för optimistisk låsning. `?dry_run=true` validerar utan att skriva.

slug (path, krävs)
Menyns slug.
delete/api/v1/menus/{slug}menus:write

Ta bort en meny (papperskorg)

Mjuktabort — menyn hamnar i papperskorgen och kan återställas i backoffice. En hårdtabort kräver ett ytterligare steg i backoffice. Returnerar 200 med `deleted: true` om raden hittades.

slug (path, krävs)
Menyns slug.
post/api/v1/menus/{slug}/sectionsmenus:write

Lägg till en sektion i en meny

Lägger till en ny `menuSection`-nod i menyns body (alla locales). Idempotent via `Idempotency-Key`. Returnerar den uppdaterade menyn.

slug (path, krävs)
Menyns slug.
patch/api/v1/menus/{slug}/sections/{id}menus:write

Uppdatera en sektion i en meny

Uppdaterar en `menuSection`-nod (titel, layout, osv.) i menyns body. `?dry_run=true` validerar utan att skriva.

slug (path, krävs)
Menyns slug.
id (path, krävs)
Sektionens id i body-trädet.
delete/api/v1/menus/{slug}/sections/{id}menus:write

Ta bort en sektion ur en meny

Tar bort `menuSection`-noden med givet id ur menyns body.

slug (path, krävs)
Menyns slug.
id (path, krävs)
Sektionens id i body-trädet.
patch/api/v1/menus/{slug}/items/{id}menus:write

Uppdatera ett menyobjekt

Uppdaterar ett `menuItem`-nod (namn, pris, beskrivning, osv.) i menyns body. `?dry_run=true` validerar utan att skriva.

slug (path, krävs)
Menyns slug.
id (path, krävs)
Menyobjektets id i body-trädet.
delete/api/v1/menus/{slug}/items/{id}menus:write

Ta bort ett menyobjekt

Tar bort `menuItem`-noden med givet id ur menyns body.

slug (path, krävs)
Menyns slug.
id (path, krävs)
Menyobjektets id i body-trädet.
patch/api/v1/sections/{id}sections:write

Uppdatera en sidssektion

Uppdaterar en sidsektion (brödtext, citat) med id. Stöder `If-Match` och `?dry_run=true`.

id (path, krävs)
Sektionens uuid.
post/api/v1/galleries/{slug}/imagesgalleries:write

Importera en bild från URL

Importerar en bild till ett galleri via URL (ingen filuppladdning). Skapar en `media_assets`-rad med `source_url` och lägger till bilden i galleriet. Idempotent via `Idempotency-Key`.

slug (path, krävs)
Galleriets slug.
delete/api/v1/galleries/{slug}/images/{id}galleries:write

Ta bort en bild från ett galleri

Tar bort bilden med givet id (media_assets.id) från galleriet och raderar media-asset-raden.

slug (path, krävs)
Galleriets slug.
id (path, krävs)
Bildens uuid (media_assets.id).
put/api/v1/opening-hourshours:write

Ersätt veckoschemat

Ersätter hela veckoschemat atomärt — DELETE alla befintliga rader + INSERT de nya. Stöder `If-Match` för optimistisk låsning och `?dry_run=true`. Kräver hemlig nyckel och att Hours-modulen är aktiv.

post/api/v1/opening-hours/exceptionshours:write

Skapa en avvikelse

Lägger till en stängt/fullbokat-avvikelse. Idempotent via `Idempotency-Key`.

delete/api/v1/opening-hours/exceptions/{id}hours:write

Ta bort en avvikelse

Tar bort avvikelsen med givet id.

id (path, krävs)
Avvikelsens uuid.
get/api/v1/availabilityavailability:read

Lediga bordstider

Returnerar tillgängliga tidsluckor för ett datum eller ett intervall (max 14 dagar). Kräver scopet `availability:read` och modulen Bokningssystem. Ingår **inte** i `content:read`.

date (query)
Enstaka dag, format `YYYY-MM-DD`. Uteslutande med `from`/`to`.
from (query)
Startdag för intervall, format `YYYY-MM-DD`. Kräver `to`.
to (query)
Slutdag (inklusiv) för intervall, format `YYYY-MM-DD`. Max 14 dagar från `from`.
covers (query)
Antal gäster. Avgör vilka luckor som markeras `available`. Standard: 1.
org (query)
Organisationens slug. Valfri — nyckeln avgör alltid vilken organisation som läses. Anges den och inte matchar nyckeln svarar API:et 403 `organization_mismatch`.

Behörighet

Scopes

En nyckel håller de scopes du gav den när du skapade den. Ge så få som möjligt: en menyskärm behöver inte kunna läsa öppettider, och ingenting utanför din egen server behöver kunna skriva.

content:read
Samlingsscope för hela läs-ytan — inkluderar menyer, sektioner, gallerier och öppettider, och följer med när nya innehållstyper tillkommer.
menus:read
Publicerade menyer och lunchmenyer.
sections:read
Publicerade sidsektioner (brödtext, citat).
galleries:read
Publicerade gallerier med bilder och layout.
hours:read
Veckans öppettider samt avvikelser (stängt/fullbokat).
content:write
Samlingsscope för hela skriv-ytan — täcker menus:write, sections:write, galleries:write och hours:write. Kräver hemlig nyckel.
menus:write
Skapa, uppdatera och ta bort menyer och menyinnehåll. Kräver hemlig nyckel och att CMS-modulen är aktiv.
sections:write
Uppdatera sidsektioner (brödtext, citat). Kräver hemlig nyckel och att CMS-modulen är aktiv.
galleries:write
Lägg till och ta bort bilder i gallerier (URL-import). Kräver hemlig nyckel och att CMS-modulen är aktiv.
hours:write
Ersätt veckoschema och hantera avvikelser (stängt/fullbokat). Kräver hemlig nyckel.
bookings:write
Skapa bokningsförfrågningar. Endast hemliga nycklar — en publicerbar nyckel får aldrig skriva.
contact:write
Skicka kontaktformulärmeddelanden. Endast hemliga nycklar — en publicerbar nyckel får aldrig skriva.
newsletter:write
Lägg till en prenumerant på nyhetsbrevet (t.ex. från en extern integration). Endast hemliga nycklar — en publicerbar nyckel får aldrig skriva.
availability:read
Lediga bordstider och kapacitet per lucka. Kräver modulen Bokningssystem. Ingår inte i content:read.

Exempel

curl

Hämta allt innehåll

Ett anrop som räcker för att rendera en hel sajt. Använd `/api/v1/version` för att avgöra när du behöver hämta om.

bash
curl -s "https://bistro.blimp.se/api/v1/site" \
  -H "Authorization: Bearer $BISTRO_API_KEY"

Bara menyerna

Kräver enbart `menus:read` — ge en menyskärm en nyckel som inte kan läsa något annat.

bash
curl -s "https://bistro.blimp.se/api/v1/menus" \
  -H "Authorization: Bearer $BISTRO_API_KEY"

curl -s "https://bistro.blimp.se/api/v1/menus/a-la-carte" \
  -H "Authorization: Bearer $BISTRO_API_KEY"

Villkorad hämtning med ETag

Skicka tillbaka ETag:en du fick förra gången och få 304 utan kropp om ingenting ändrats.

bash
# Första anropet: notera ETag-headern
curl -si "https://bistro.blimp.se/api/v1/menus" \
  -H "Authorization: Bearer $BISTRO_API_KEY" | grep -i '^etag'

# Nästa anrop: 304 Not Modified om innehållet är oförändrat
curl -s -o /dev/null -w '%{http_code}\n' "https://bistro.blimp.se/api/v1/menus" \
  -H "Authorization: Bearer $BISTRO_API_KEY" \
  -H 'If-None-Match: W/"…"'

Skapa en bokningsförfrågan

Kräver `bookings:write`, en hemlig nyckel och modulen vit etikett. Anropet måste ske från din server — en hemlig nyckel som används från en webbläsare avvisas med 403. Utan vit etikett går bokning bara genom Hyperform.

bash
curl -s -X POST "https://bistro.blimp.se/api/v1/bookings" \
  -H "Authorization: Bearer $BISTRO_SECRET_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "startsAt": "2026-10-04T18:00:00+02:00",
    "covers": 4,
    "guest": {
      "firstName": "Alva",
      "lastName": "Nord",
      "email": "alva@example.com",
      "phone": "+46701234567"
    },
    "message": "Gärna ett bord vid fönstret"
  }'

Skicka ett kontaktmeddelande

Kräver `contact:write`, en hemlig nyckel och modulen vit etikett, precis som bokningar. Kräver också CMS — egen modul, eller via bokningssystem eller beställningar. Utan vit etikett går kontakt bara genom Hyperform.

bash
curl -s -X POST "https://bistro.blimp.se/api/v1/contact-messages" \
  -H "Authorization: Bearer $BISTRO_SECRET_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "firstName": "Alva",
    "lastName": "Nord",
    "email": "alva@example.com",
    "phone": "+46701234567",
    "message": "Har ni glutenfria alternativ på menyn?"
  }'

Så ser ett fel ut

Grena alltid på `error.code`, aldrig på meddelandetexten eller på HTTP-statusen ensam.

json
{
  "error": {
    "code": "insufficient_scope",
    "message": "API-nyckeln saknar scope `bookings:write`.",
    "detail": { "required": "bookings:write", "granted": ["content:read"] },
    "docs": "/docs"
  }
}

Exempel

Rita själv

Meny, galleri, öppettider, öppet-status och nyhetsbrev är JSON. Exemplen hämtar API:et och ritar er egen HTML. Vi skickar inte med färdiga komponenter för de ytorna.

Server-side (Next.js App Router)

Rätt ställe för en hemlig nyckel: den lämnar aldrig din server, och svaret kan cachas där.

React · server
// app/meny/page.tsx
import type { MenuListResponse } from "./types";

async function getMenus(): Promise<MenuListResponse> {
  const res = await fetch("https://bistro.blimp.se/api/v1/menus", {
    headers: { Authorization: `Bearer ${process.env.BISTRO_API_KEY}` },
    // Bistro svarar med s-maxage=60; låt Next respektera det.
    next: { revalidate: 60 },
  });
  if (!res.ok) throw new Error(`Bistro svarade ${res.status}`);
  return res.json();
}

export default async function MenyPage() {
  const { menus } = await getMenus();
  return (
    <ul>
      {menus.map((menu) => (
        <li key={menu.slug}>{menu.title}</li>
      ))}
    </ul>
  );
}

Klienthook med poll på version

En publicerbar nyckel (bis_pub_…) får ligga i klientkod. Lås den till din domän under Tillåtna origins så den inte kan återanvändas någon annanstans. Hooken pollar /api/v1/version — 120 anrop/minut räcker gott för var 30:e sekund — och hämtar om innehållet först när fingeravtrycket ändrats.

React · klient
"use client";

import { useEffect, useState } from "react";

const BASE = "https://bistro.blimp.se";
const KEY = process.env.NEXT_PUBLIC_BISTRO_API_KEY!;

const auth = { Authorization: `Bearer ${KEY}` };

export function useBistroSite(pollMs = 30_000) {
  const [site, setSite] = useState<unknown>(null);
  const [revision, setRevision] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;

    async function sync() {
      const versionRes = await fetch(`${BASE}/api/v1/version`, { headers: auth });
      if (!versionRes.ok) return;
      const { revision: latest } = await versionRes.json();
      if (cancelled || latest === revision) return;

      const siteRes = await fetch(`${BASE}/api/v1/site`, { headers: auth });
      if (!siteRes.ok || cancelled) return;
      setSite(await siteRes.json());
      setRevision(latest);
    }

    void sync();
    const timer = setInterval(sync, pollMs);
    return () => {
      cancelled = true;
      clearInterval(timer);
    };
  }, [pollMs, revision]);

  return site;
}

Hyperform

Bokning och kontakt

Hyperform är den enda ytan vi ritar åt en sajt som inte ligger hos oss: en iframe, eller en egen länk. Bokning och kontakt sitter i samma formulär. Ingen API-nyckel, och temat är restaurangens.

Hyperform på er sajt

Den enda ytan vi ritar. Formuläret har både bokning och kontakt, använder restaurangens publicerade tema och skriver via den publika intaken — ingen nyckel i iframen. `data-bistro-org` är restaurangens slug. bistro-embed.js sätter höjden från ett postMessage.

html
<div
  data-bistro-embed="book"
  data-bistro-org="er-restaurang"
  data-bistro-lang="sv-SE"
  data-bistro-modes="booking,contact"
></div>
<script src="https://bistro.blimp.se/bistro-embed.js"></script>

Egen länk

Samma formulär, för den som inte har en egen sajt. Märket längst ned försvinner när modulen vit etikett är på. Egna formulär via API kräver samma modul.

url
https://bistro.blimp.se/boka?org=er-restaurang&lang=sv-SE&modes=booking,contact

Om höjden

Scriptet lyssnar på { source: "bistro-embed", type: "resize", height } och sätter iframe-höjden. data-bistro-lang blir ?lang=, data-bistro-theme="#112233" blir en accent ovanpå det publicerade temat. Meny, galleri, öppettider och öppet-status ritas inte här — de hämtas som JSON och HTML:en ligger på er domän.

html
<div
  data-bistro-embed="book"
  data-bistro-org="er-restaurang"
  data-bistro-lang="en-US"
  data-bistro-theme="#112233"
  data-bistro-modes="booking,contact"
></div>
<script src="https://bistro.blimp.se/bistro-embed.js"></script>

Kontrakt

Felkoder

Fel har alltid formen { "error": { "code", "message", "docs" } }. Koden är kontraktet — HTTP-statusen slår ihop flera distinkta orsaker och meddelandetexterna kan skrivas om.

  • 401missing_authorizationIngen Authorization-header skickades.
  • 401invalid_api_keyNyckeln känns inte igen. Samma svar ges för okänt prefix, trasig token och fel hemlighet — avsiktligt.
  • 401api_key_revokedNyckeln fanns men har återkallats i backoffice.
  • 403insufficient_scopeGiltig nyckel, men den saknar det scope endpointen kräver. `detail.required` säger vilket.
  • 403module_inactiveGiltig nyckel och scope, men organisationen har inte aktiverat modulen som krävs (t.ex. CMS eller Bokning). `detail.module` säger vilken — se /priser.
  • 403origin_not_allowedOrigin saknas i nyckelns lista — eller en hemlig nyckel användes från en webbläsare.
  • 403organization_mismatch`?org=` pekar på en annan organisation än nyckelns.
  • 404not_foundResursen finns inte, eller är inte publicerad.
  • 400invalid_requestKroppen eller parametrarna klarade inte valideringen.
  • 422idempotency_conflictIdempotency-Key har använts med en annan request-body. Använd en ny nyckel.
  • 412precondition_failedIf-Match matchar inte aktuell innehållsrevision. Hämta om innehållet och försök igen.
  • 429rate_limitedTaket är nått. Vänta `Retry-After` sekunder.
  • 500internal_errorFel hos oss. Säkert att försöka igen.
  • 409slot_fullLuckan är fullbokad. `detail.suggestions` innehåller närmaste lediga tider.

Drift

Rate limits och caching

120 läsanrop och 20 skrivanrop per minut och nyckel. Varje svar bär X-RateLimit-Limit, X-RateLimit-Remaining och X-RateLimit-Reset; ett 429 bär dessutom Retry-After.

Läs-endpoints svarar med en svag ETag och s-maxage=60. Skicka tillbaka ETag:en som If-None-Match för att få 304 utan kropp. /api/v1/version cachas aldrig och är den som är byggd för att pollas.

Skriv-API

Skriva innehåll

Alla skrivoperationer kräver en hemlig nyckel (bis_sk_…) och att motsvarande modul är aktiv. En publicerbar nyckel kan aldrig hålla ett skriv-scope. Skicka nyckeln som vanlig bearer-token — API:et avvisar den med 403 om anropet har en Origin-header, vilket skyddar mot att nyckeln råkar hamna i klientkod.

Tillgängliga skriv-scopes: content:write, menus:write, sections:write, galleries:write, hours:write, bookings:write, contact:write, newsletter:write.

curl
# Skapa en ny meny
curl -X POST https://bistro.blimp.se/api/v1/menus \
  -H "Authorization: Bearer bis_sk_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "slug": "lunch", "title": "Lunchmeny", "kind": "lunch" }'
curl
# Uppdatera en meny (optimistisk låsning med If-Match)
curl -X PATCH https://bistro.blimp.se/api/v1/menus/lunch \
  -H "Authorization: Bearer bis_sk_…" \
  -H "Content-Type: application/json" \
  -H "If-Match: \"<revision>\"" \
  -d '{ "published": true }'

Kontrakt

Idempotens och ETag

Idempotency-Key på POST-endpoints: skicka ett UUID eller ULID som du genererat för just det anropet. Samma nyckel med samma body ger samma svar utan att skriva en ny rad — trygg att skicka om efter ett nätverksfel. Samma nyckel med annan body ger 422 idempotency_conflict.

ETag och If-Match på PATCH- och PUT-endpoints: hämta revisionen från /api/v1/version och skicka tillbaka den som If-Match: "<revision>". Om innehållet har ändrats sedan du läste det svarar API:et 412 precondition_failed — hämta om och försök igen.

?dry_run=true på stödda endpoints validerar och returnerar resultatet utan att skriva till databasen. Bra för att verifiera payloaden innan en riktig skrivning.

curl
# Hämta aktuell revision
REVISION=$(curl -s https://bistro.blimp.se/api/v1/version \
  -H "Authorization: Bearer bis_pub_…" | jq -r .revision)

# Uppdatera med optimistisk låsning
curl -X PATCH https://bistro.blimp.se/api/v1/menus/lunch \
  -H "Authorization: Bearer bis_sk_…" \
  -H "Content-Type: application/json" \
  -H "If-Match: \"$REVISION\"" \
  -d '{ "published": false }'

Bokningar

Tillgänglighet

Lediga bordstider hämtas med GET /api/v1/availability. Kräver scopet availability:read och att modulen Bokningssystem är aktiv. Scopet ingår inte i content:read och måste beviljas separat.

Parametrar: date=YYYY-MM-DD (enstaka dag) eller from=…&to=… (max 14 dagar) och covers=N (antal gäster, default 1). Svaret listar alla tidsluckor med available: true/false och remainingCovers.

curl
curl "https://bistro.blimp.se/api/v1/availability?date=2026-11-15&covers=4" \
  -H "Authorization: Bearer bis_pub_…"

Agenter

För AI-agenter

Bistro exponerar tre maskinläsbara ingångar som en agent kan använda utan att läsa källkoden: /llms.txt (kort sammanfattning), /llms-full.txt (fullständig API-referens i markdown) och en MCP-server på /api/mcp.

llms.txt och llms-full.txt

Genereras från routes.ts och scopes.ts och kan aldrig glida isär från det faktiska API:et. En agent börjar med att hämta /llms.txt för att orientera sig, och /llms-full.txt för hela endpoint-referensen.

curl
curl https://bistro.blimp.se/llms.txt
curl https://bistro.blimp.se/llms-full.txt

MCP-server (Streamable HTTP)

MCP-servern exponerar alla API-endpoints som verktyg, genererade från routes.ts. Verktyg som ligger utanför nyckelns scopes visas aldrig. Auth sker med samma bearer-nyckel som REST API:et.

claude_desktop_config.json
{
  "mcpServers": {
    "bistro": {
      "type": "http",
      "url": "https://bistro.blimp.se/api/mcp",
      "headers": {
        "Authorization": "Bearer bis_pub_<prefix>.<hemlighet>"
      }
    }
  }
}
.mcp.json (Claude Code)
{
  "mcpServers": {
    "bistro": {
      "type": "http",
      "url": "https://bistro.blimp.se/api/mcp",
      "headers": {
        "Authorization": "Bearer bis_sk_<prefix>.<hemlighet>"
      }
    }
  }
}

Exempelprompt för en agent med en nyckel med content:read:

prompt
Du har tillgång till MCP-verktyget "bistro". Gör följande:
1. Anropa list_menus för att se vilka menyer som finns.
2. Hämta menyn med get_menu (slug från listan).
3. Sammanfatta innehållet på svenska.