API:t erbjuds på förfrågan. Kontakta oss på hej@floowlie.se.

    API & Webhooks

    API & Webhooks

    Bygg in Floowlies recensionsdata var som helst. 14 REST-endpoints plus HMAC-signerade realtids-webhooks. Allt över HTTPS, JSON in/ut, scopes per nyckel.

    Översikt

    REST + JSON

    Standardiserade endpoints över HTTPS.

    Scopes

    Begränsa varje nyckel till exakt vad den behöver.

    Webhooks

    HMAC-signerade events i realtid.

    Rate limit

    Standard: 60 anrop/minut per nyckel, burst 20. Högre gräns kan avtalas per plan/kund.

    Quickstart

    1. Logga in på Floowlie och gå till Konto → API & Webhooks.
    2. Skapa en nyckel, välj scopes och kopiera värdet (den visas bara en gång – nycklar börjar med flw_live_).
    3. Anropa /health för att verifiera nyckeln och se vilka scopes den har.
    4. Bygg din integration – Zapier, Make, n8n, en intern dashboard eller en widget.
    Officiell bas-URL: https://api.floowlie.se/v1. Direkta anrop till backend-värden blockeras med 403.
    bash
    curl https://api.floowlie.se/v1/health \
      -H "Authorization: Bearer flw_live_xxx"

    Autentisering & scopes

    Alla anrop kräver headern Authorization: Bearer flw_live_.... Skapa nycklar från Konto → API & Webhooks.

    ScopeGer åtkomst till
    reviews:readLäs recensioner, AI-utkast och publicerade svar.
    analytics:readLäs stats, sentiment, ratings, timeseries och scans.
    employees:readLäs medarbetare, deras scans och topplistor.
    webhooks:readLäs era registrerade webhooks och leveranshistorik.
    *Full läsåtkomst till alla nuvarande och framtida read-endpoints.

    Tips: skapa en separat nyckel per integration. Roterar du en nyckel? Skapa en ny, byt i din integration, återkalla sedan den gamla från Konto-vyn.

    Base URL & versionering

    url
    https://api.floowlie.se/v1

    Versionen är inbyggd i pathen (/v1/...). Breaking changes släpps som/v2; nya endpoints och fält i existerande svar räknas inte som breaking. Alla tidsstämplar är ISO 8601 i UTC. Alla request- och response-bodies är JSON.

    Endpoint-referens

    Alla endpoints är scopade till företaget som äger API-nyckeln. Ingen cross-tenant data lämnar någonsin servern.

    Core

    GET/health

    Verifierar din API-nyckel och returnerar dina scopes.

    Exempelsvar

    json
    {
      "ok": true,
      "company_id": "8c2…",
      "scopes": ["reviews:read", "analytics:read", "employees:read"],
      "server_time": "2026-06-25T10:00:00Z"
    }

    Analytics

    GET/stats

    Personal och Floowlies egna skanningar senaste 7/30 dagar; Google-sammanställningar ingår inte.

    Exempelsvar

    json
    {
      "employees": 14,
      "scans_last_7_days": 84,
      "scans_last_30_days": 421
    }
    GET/analytics/sentiment

    Avvecklad: HTTP 410. Google-recensioner sammanställs inte för sentiment.

    Exempelsvar

    json
    {
      "total": 312,
      "positive": 268,
      "neutral": 28,
      "negative": 16,
      "positive_pct": 86,
      "by_language": { "sv": 240, "en": 60, "ar": 12 }
    }
    GET/analytics/ratings

    Distribution över 1–5 stjärnor med total och snitt.

    Exempelsvar

    json
    {
      "total": 312,
      "average": 4.78,
      "distribution": { "1": 4, "2": 6, "3": 18, "4": 52, "5": 232 }
    }
    GET/analytics/timeseries?metric=scans&days=30

    Dagliga counts. metric=scans|reviews, days=1–365 för skanningar, högst 30 för recensioner (default 30).

    Exempelsvar

    json
    {
      "metric": "scans",
      "days": 30,
      "series": [
        { "date": "2026-05-27", "count": 12 },
        { "date": "2026-05-28", "count": 18 }
      ]
    }
    GET/analytics/top-employees?period=30d&limit=10

    Intern medarbetarstatistik i namnordning, utan ranking. Äldre adress behålls. period=all|7d|30d|90d.

    Exempelsvar

    json
    {
      "period": "30d",
      "top": [
        { "id": "…", "name": "Sara", "avatar_url": null, "scan_count": 84 }
      ]
    }
    GET/scans?since=2026-06-01&limit=200

    Alla scans för företaget. Filtrera med since (ISO-datum), limit 1–500.

    Exempelsvar

    json
    {
      "scans": [
        { "id": "…", "employee_id": "…", "scanned_at": "…", "clicked_through_at": "…" }
      ]
    }

    Employees & Scans

    GET/employees

    Lista alla medarbetare med totalt antal QR-scans.

    Exempelsvar

    json
    {
      "employees": [
        { "id": "…", "name": "Sara", "avatar_url": null, "scan_count": 132 }
      ]
    }
    GET/employees/{id}

    Detaljer för en medarbetare med scan-totaler och senaste scan-tid.

    Exempelsvar

    json
    {
      "employee": {
        "id": "…",
        "name": "Sara",
        "avatar_url": null,
        "scan_count": 132,
        "last_scan_at": "2026-06-24T19:11:00Z"
      }
    }
    GET/employees/{id}/scans?limit=50

    Senaste QR-scans för en specifik medarbetare (max 500).

    Exempelsvar

    json
    {
      "employee_id": "…",
      "scans": [
        { "id": "…", "scanned_at": "2026-06-25T08:12:00Z", "clicked_through_at": "2026-06-25T08:12:14Z" }
      ]
    }
    GET/leaderboard

    Avslutad. Returnerar HTTP 410; använd intern medarbetarstatistik utan ranking.

    Exempelsvar

    json
    { "error": "Den publika topplistan har avslutats." }

    Reviews

    GET/reviews?min_rating=4&language=sv&limit=20

    Lista recensioner. Filtrera med min_rating, max_rating, since (ISO), language (sv/en/ar/de), limit 1–100.

    Exempelsvar

    json
    {
      "reviews": [
        {
          "id": "…",
          "rating": 5,
          "text": "Bästa kaffet i stan!",
          "reviewer_name": "Anna",
          "created_at": "2026-06-20T13:02:00Z",
          "language": "sv",
          "status": "published",
          "reply": "Tack Anna! …",
          "reply_published_at": "2026-06-20T13:30:00Z"
        }
      ]
    }
    GET/reviews/{id}

    Hämta en specifik recension med AI-utkast och slutligt svar.

    Exempelsvar

    json
    {
      "review": {
        "id": "…",
        "rating": 5,
        "review_text": "…",
        "reviewer_name": "Anna",
        "review_created_at": "…",
        "ai_draft": "…",
        "final_reply": "…",
        "published_at": "…",
        "detected_language": "sv",
        "status": "published"
      }
    }

    Webhooks

    GET/webhooks

    Lista era registrerade webhooks och senaste leveransstatus.

    Exempelsvar

    json
    {
      "webhooks": [
        {
          "id": "…",
          "url": "https://example.com/floowlie",
          "events": ["review.created", "review.reply_published"],
          "is_active": true,
          "last_delivery_at": "…",
          "last_status": 200
        }
      ]
    }

    SDK-exempel

    Hämta senaste 5 svenska 5-stjärniga recensionerna:

    bash
    curl "https://api.floowlie.se/v1/reviews?min_rating=5&language=sv&limit=5" \
      -H "Authorization: Bearer flw_live_xxx"

    Node / TypeScript:

    ts
    const res = await fetch("https://api.floowlie.se/v1/analytics/sentiment", {
      headers: { Authorization: `Bearer ${process.env.FLOOWLIE_KEY}` },
    });
    const data = await res.json();
    console.log(data.positive_pct, data.by_language);

    Python:

    python
    import requests
    r = requests.get(
      "https://api.floowlie.se/v1/employees",
      headers={"Authorization": f"Bearer {KEY}"},
    )
    print(r.json())

    PHP:

    php
    $ch = curl_init("https://api.floowlie.se/v1/stats");
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
      "Authorization: Bearer " . getenv("FLOOWLIE_KEY")
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $data = json_decode(curl_exec($ch), true);
    print_r($data);

    Zapier / Make / n8n: använd en HTTP-modul med GET, lägg headern Authorization: Bearer flw_live_… och peka mot Base URL ovan.

    Webhooks

    Floowlie POSTar event-payloaden till din URL. Headers vi alltid skickar:

    • Content-Type: application/json
    • X-Floowlie-Event – eventnamnet (t.ex. review.created)
    • X-Floowlie-Delivery – unikt leverans-id (idempotens-nyckel)
    • X-Floowlie-Signature – HMAC-SHA256 av timestamp.body med er webhook-secret, format sha256=<hex>
    • X-Floowlie-Signature-Legacy – tidigare signatur av enbart råa bodyn, för övergång till tidsstämplad verifiering
    • X-Floowlie-Timestamp – Unix-tid när eventet skickades (avvisa > 5 min skew)

    Events

    review.createdNy recension synkad från Google.
    json
    {
      "event": "review.created",
      "id": "evt_01HZ…",
      "created_at": "2026-06-25T10:00:00Z",
      "company_id": "…",
      "data": {
        "review_id": "…",
        "rating": 5,
        "text": "Bästa kaffet i stan!",
        "reviewer_name": "Anna",
        "language": "sv",
        "google_review_id": "ChdD…"
      }
    }
    review.reply_draftedAI har skapat ett utkast som väntar på godkännande.
    json
    {
      "event": "review.reply_drafted",
      "id": "evt_…",
      "company_id": "…",
      "data": {
        "review_id": "…",
        "rating": 4,
        "ai_draft": "Tack för din feedback! …",
        "requires_approval": true
      }
    }
    review.reply_publishedSvar publicerades till Google.
    json
    {
      "event": "review.reply_published",
      "id": "evt_…",
      "company_id": "…",
      "data": {
        "review_id": "…",
        "rating": 5,
        "final_reply": "Tack Anna! …",
        "published_at": "2026-06-25T10:01:00Z"
      }
    }
    scan.createdQR-kod skannades av en kund (kopplad till en medarbetare om sådan finns).
    json
    {
      "event": "scan.created",
      "company_id": "…",
      "data": {
        "scan_id": "…",
        "employee_id": "…",
        "location_id": "…",
        "scanned_at": "2026-06-25T10:00:00Z"
      }
    }
    employee.createdNy medarbetare lades till i ert konto.
    json
    {
      "event": "employee.created",
      "company_id": "…",
      "data": { "employee_id": "…", "name": "Anna Andersson", "location_id": "…" }
    }
    support.message.createdNytt meddelande i ett av era supportärenden.
    json
    {
      "event": "support.message.created",
      "company_id": "…",
      "data": { "thread_id": "…", "message_id": "…", "sender": "admin", "preview": "Hej, …" }
    }
    subscription.changedAbonnemangsplan eller status ändrades.
    json
    {
      "event": "subscription.changed",
      "company_id": "…",
      "data": { "tier": "business", "status": "active", "changed_at": "2026-06-25T10:00:00Z" }
    }

    Verifiera signaturen (Node):

    ts
    import crypto from "crypto";
    
    export function verifyFloowlie(rawBody: string, header: string, timestamp: string, secret: string) {
      if (!/^\d+$/.test(timestamp) || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
      if (!/^sha256=[a-f0-9]{64}$/.test(header)) return false;
      const expected = crypto.createHmac("sha256", secret).update(timestamp + "." + rawBody).digest("hex");
      const a = Buffer.from(expected, "hex");
      const b = Buffer.from(header.slice(7), "hex");
      return a.length === b.length && crypto.timingSafeEqual(a, b);
    }

    Leverans & retries:

    • Svara 2xx inom 10 sekunder. Annat räknas som fail.
    • Misslyckade leveranser försöker vi igen med exponentiell backoff i upp till 24 timmar.
    • Använd X-Floowlie-Delivery som idempotens-nyckel – samma event kan komma flera gånger.

    Fel & rate limits

    Standardiserade felkoder över alla endpoints.

    StatusInnebördFältet error
    400Ogiltiga query-parametrarinvalid_parameter
    401Saknad / ogiltig / återkallad nyckelInvalid or revoked API key
    403Nyckeln saknar rätt scopeinsufficient_scope
    404Okänd endpoint eller resurs ej i ert kontonot_found / employee_not_found
    429Rate limit (standard 60 anrop/min · burst 20)rate_limit_exceeded
    5xxServerfel – försök igen med backoffinternal_error

    Alla fel returneras som JSON: { "error": "..." }.

    Rate limit i detalj

    Standardgränsen är 60 anrop per minut och nyckel, plus en burst på 20, alltså upp till 80 anrop inom samma minutfönster. Gränsen är konfigurerbar per nyckel: vissa planer och kunder kan efter överenskommelse ha ett högre värde.

    Varje svar innehåller X-RateLimit-Limit, X-RateLimit-Burst, X-RateLimit-Remaining och X-RateLimit-Reset. När gränsen överskrids svarar API:t med 429, kroppen { "error": "rate_limit_exceeded", "limit": 60, "burst": 20, "retry_after_seconds": 12 } och headern Retry-After i sekunder. Värdet är alltid den tid som återstår av just er nyckels aktuella minutfönster, läs headern och vänta den tiden istället för att anta 60 sekunder.

    Changelog

    2026-10-17 Google API-innehåll och samtycken. Sparat recensionsinnehåll gallras inom 30 dagar. Recensionstidsserier, betygsfördelning, sentiment och Google-embeds returnerar 410; stats och MCP-översikt innehåller inte Google-sammanställningar. Automatisk publicering kräver ägarens separata samtycke efter övergångstiden.

    2026-10-17 Versionsbundet FloowStar-godkännande. Personal, QR-skanningar och skanningsstatistik kräver enhetens godkännande av aktuell regelversion. Annars returneras 403 med floowstar_rules_required. Befintliga gästers QR-länkar påverkas inte.

    2026-10-17 Google-recensionsregler. Publika topplistor avslutas. Medarbetarstatistik visas i namnordning utan ranking; godkända recensionssvar köas för utspridd publicering.

    2026-10-13 Betrodd klient-IP. IP-baserade gränser och tillåtelselistor använder plattformens betrodda IP, aldrig klientens första X-Forwarded-For-värde.

    • 2026-10-13 Säkrare webhooks. Signaturen omfattar nu timestamp.body; tidigare bodysignatur finns i X-Floowlie-Signature-Legacy. DNS-adresser kontrolleras före leverans och privata adresser blockeras. Oväntade klientfel får neutrala meddelanden och referens-id.
    • 2026-09-22 Fakturamejl blir underlag automatiskt. Den interna e-posthämtningen (POST /api/public/email-poll) registrerar nu mejl som klassats som faktura som fakturaunderlag i FloowStock för bolagskonton där tillvalet invoice_inbox är påslaget. Svaret innehåller ett nytt fält invoices med scanned, imported, skipped och results. Samma mejl läses aldrig in två gånger, och ingenting tolkas, attesteras eller bokförs automatiskt. Befintliga fält i svaret är oförändrade.
    • 2026-09-20 Rate limit: 60 anrop/minut + burst 20 är standard. En tidigare changelogpost angav felaktigt 600 anrop/minut som standard. Det faktiska basvärdet är 60 anrop per minut och nyckel med en burst på 20 (upp till 80 anrop inom samma minutfönster). Gränsen är nu konfigurerbar per nyckel och kan höjas för enskilda planer eller kunder efter överenskommelse, ändringen börjar gälla omedelbart. Svaren innehåller även X-RateLimit-Burst, och 429-svar har Retry-After beräknad på nyckelns faktiska gräns och fönster.
    • 2026-09-19 Personal på kedjenivå. /v1/employees, /v1/employees/:id, /v1/employees/:id/scans, /v1/analytics/top-employees och /v1/stats omfattar nu hela kedjans personal, enhetens egna poster plus kedjekollegor som samlat skanningar på enheten. Alla scan_count räknas enbart på skanningar som skedde på den enhet nyckeln gäller. Nytt fält paused (boolean) på medarbetare; avbokad personal räknas inte i stats.employees.
    • 2026-09-10 Samlad fakturering via Huvudföretag. Regeln “fakturering sker per enhet” gäller fortfarande som standard, men en kedja kan nu peka ut ett Huvudföretag som tar emot fakturan för kedjans enheter. Enheter som tillkommer senare läggs till med ett tilläggsavtal som Huvudföretaget signerar.
    • 2026-09-04 MCP-servern kräver nu modulen API & Webhooks och har fått tre skrivande verktyg: save_review_reply, publish_review_reply och update_inventory_product.
    • 2026-09-04 Ny MCP-server på https://floowlie.se/mcp för AI-assistenter (ChatGPT, Claude m.fl.). OAuth-inloggning och samma behörigheter som i appen. Se AI-assistenter (MCP).
    • 2026-09-03 Autentiserade supportmeddelanden binder nu avsändaridentiteten till den inloggade användaren.
    • 2026-08-27 Alla delar av Floowlie är moduler. FloowStar (QR-koder, personal och intern statistik) kan slås av eller på per företag, precis som FloowAgent, FloowStock och API. Konton utan FloowStar kan inte skapa nya medarbetare eller ta emot QR-skanningar.
    • 2026-06-29 Endast den officiella URL:en https://api.floowlie.se/v1 är tillåten. Andra endpoints returnerar 403.
    • 2026-06-25 Nya webhook-events: scan.created, employee.created, support.message.created och subscription.changed. Ny leveranslogg per webhook (status, HTTP-kod, försök, felmeddelande) med manuell retry från översikten. Automatisk retry med exponentiell backoff (1m → 5m → 15m → 1h → 6h, max 5 försök, sedan markerad dead).
    • 2026-06-25 API-nycklar och webhooks kräver API-modulen. Anrop från konton utan aktiv API-modul returnerar 402.
    • 2026-06-25 Per-nyckel rate limiting, IP-allowlist per nyckel (IPv4 + CIDR) och visning av senast använd IP i översikten. Svar inkluderar X-RateLimit-Limit/Remaining/Reset; vid överskridning returneras 429 med Retry-After. (Gränsvärdet i den ursprungliga texten var felaktigt, se posten 2026-09-20 för den faktiska gränsen.)
    • 2026-06-25 Webhook-URL:er måste använda https://. API-nycklar inaktiveras automatiskt om kontot pausas. HMAC-secrets visas endast en gång vid skapande och returneras aldrig av /v1/webhooks.
    • 2026-06-25 Lade till /analytics/ratings, /analytics/timeseries, /analytics/top-employees, /scans, /employees/{id} och /webhooks. Ny scope webhooks:read.
    • 2026-06-10 Webhooks GA med HMAC-signering och retries.
    • 2026-05-20 Initial v1: stats, sentiment, employees, reviews, leaderboard.

    Redo att börja?

    Skapa en nyckel på 10 sekunder och börja anropa.

    Till API-nycklar