v1Stabil · HTTPS · JSON

geembee REST API

Integriere Standortdaten direkt in deine Anwendung. Die aktuelle v1 deckt Standorte, Öffnungszeiten, Reviews, versionierte Google-Business-Snapshots, Menüs, den öffentlichen geembee Blog und einen gebundenen Sync-Trigger für Partner-Workflows ab.

Basis-URL

https://www.geembee.com/api/v1

Alle Anfragen werden über HTTPS verarbeitet. HTTP-Anfragen werden automatisch auf HTTPS umgeleitet.

Authentifizierung

Jede Anfrage muss zwei Header enthalten:

HeaderBeschreibung
X-GeemBee-KeyÖffentlicher API Key (beginnt mit gbk_live_)
X-GeemBee-SecretAPI Secret (wurde beim Erstellen des Keys einmalig angezeigt)
curl https://www.geembee.com/api/v1/locations \
  -H "X-GeemBee-Key: gbk_live_deinKey" \
  -H "X-GeemBee-Secret: deinSecret"

Optionale Request-Signierung (empfohlen)

Für erhöhte Sicherheit kannst du Anfragen mit HMAC-SHA256 signieren. Damit wird Replay-Attacken vorgebeugt (±5 Minuten Zeitfenster). Für Google-Post- und Blog-Schreibendpunkte sowie Standort-Sync und das Trennen einer Partner-Google-Verbindung ist diese Signierung verpflichtend.

# Signierung: HMAC-SHA256(secret, "{timestamp}.{body}")
X-GeemBee-Timestamp: 1740000000
X-GeemBee-Signature: hmac_sha256(secret, "1740000000.{requestBody}")

Berechtigungen (Scopes)

Jeder API Key hat definierte Berechtigungen. Beim Anfordern eines Keys gibst du an, welche Scopes du benötigst.

ScopeBeschreibung
LOCATIONS_READStandortdaten, Öffnungszeiten und Details lesen
REVIEWS_READGoogle Reviews für deine Standorte abrufen
SYNC_TRIGGERDatensync mit Google Business Profile auslösen
WEBHOOKS_MANAGEWebhook-URL im Partner-Key hinterlegen (aktuell Admin-/Partner-Setup)
POSTS_WRITEGoogle Business Profile Posts für eigene Standorte veröffentlichen
BLOG_WRITEBlogbeiträge und Blogbilder auf geembee.com erstellen und verwalten

Endpunkte

Hinweis: Die meisten Endpunkte arbeiten mit der Google `placeId`. Der Menü-Endpunkt verwendet aktuell die interne geembee-`locationId`.

GET/api/v1/locationsScope: LOCATIONS_READ

Gibt alle aktiven Standorte des API Key-Inhabers zurück.

Beispiel-Antwort

{
  "success": true,
  "data": [
    {
      "id": "clx1234...",
      "name": "Mein Unternehmen GmbH",
      "address": "Mariahilfer Straße 1, 1060 Wien",
      "phone": "+43 1 234567",
      "website": "https://example.at",
      "category": "Restaurant",
      "placeId": "ChIJN1t_tDeuEmsRUsoyG83frY4",
      "gmbLocationId": "locations/12345678901234567",
      "lastSyncedAt": "2026-02-27T10:00:00Z",
      "connectionId": "55d24db0-52cf-4df2-8b15-51cb27064972"
    }
  ],
  "meta": { "total": 1, "apiVersion": "v1" }
}
GET/api/v1/locations/:placeIdScope: LOCATIONS_READ

Gibt Details zu einem einzelnen Standort anhand der Google Place ID zurück.

Parameter

NameTypPflichtBeschreibung
placeIdstring✓Google Place ID (ChIJ...)

Beispiel-Antwort

{
  "success": true,
  "data": {
    "id": "clx1234...",
    "name": "Mein Unternehmen GmbH",
    "address": "Mariahilfer Straße 1, 1060 Wien",
    "phone": "+43 1 234567",
    "website": "https://example.at",
    "placeId": "ChIJN1t_tDeuEmsRUsoyG83frY4",
    "lastSyncedAt": "2026-02-27T10:00:00Z",
    "connectionId": "55d24db0-52cf-4df2-8b15-51cb27064972",
    "openingHours": {
      "monday": { "open": "09:00", "close": "18:00" },
      "tuesday": { "open": "09:00", "close": "18:00" }
    }
  }
}
GET/api/v1/locations/:placeId/hoursScope: LOCATIONS_READ

Gibt die Öffnungszeiten eines Standorts zurück.

Parameter

NameTypPflichtBeschreibung
placeIdstring✓Google Place ID

Beispiel-Antwort

{
  "success": true,
  "data": {
    "monday":    { "open": "09:00", "close": "18:00" },
    "tuesday":   { "open": "09:00", "close": "18:00" },
    "wednesday": { "open": "09:00", "close": "18:00" },
    "thursday":  { "open": "09:00", "close": "18:00" },
    "friday":    { "open": "09:00", "close": "17:00" },
    "saturday":  { "open": "10:00", "close": "14:00" },
    "sunday":    null
  }
}
GET/api/v1/locations/:placeId/reviewsScope: REVIEWS_READ

Gibt Google Reviews für einen Standort zurück (paginiert).

Parameter

NameTypPflichtBeschreibung
placeIdstring✓Google Place ID
limitnumber–Anzahl pro Seite (max. 100, default: 20)
cursorstring–Cursor für Paginierung

Beispiel-Antwort

{
  "success": true,
  "data": [
    {
      "id": "rev_abc123",
      "reviewer": "Max Mustermann",
      "rating": 5,
      "comment": "Sehr guter Service!",
      "reply": null,
      "repliedAt": null,
      "publishedAt": "2026-02-01T14:30:00Z",
      "updatedAt": "2026-02-01T14:30:00Z"
    }
  ],
  "meta": {
    "limit": 20,
    "nextCursor": "rev_xyz456"
  }
}
GET/api/v1/locations/:placeId/connections/:connectionId/snapshotScope: LOCATIONS_READ + REVIEWS_READ

Liefert den persistenten, versionierten Google-Business-Last-good-Snapshot und den getrennten aktuellen Providerzustand. Der GET ist exakt an API-Key, User, aktive Location, Place ID und Connection ID gebunden, ruft Google nicht live auf und liefert auch Providerfehler als fail-closed Vertragsantwort mit HTTP 200. Öffnungszeiten enthalten ausschließlich 00:00 bis 23:59; ein exaktes Google-Tagesende 24:00 wird vor dem Commit als 00:00 am folgenden Wochentag beziehungsweise Datum normalisiert. Eine einzelne reguläre Google-24/7-Periode wird verlustfrei als sieben Tagesperioden ausgegeben.

Parameter

NameTypPflichtBeschreibung
placeIdstring (Pfad)✓Exakt gebundene Google Place ID
connectionIdUUID (Pfad)✓Exakt gebundene GeemBee-Connection-ID

Beispiel-Antwort

{
  "success": true,
  "data": {
    "schemaVersion": "google-business-location-snapshot.v1",
    "placeId": "ChIJN1t_tDeuEmsRUsoyG83frY4",
    "connectionId": "55d24db0-52cf-4df2-8b15-51cb27064972",
    "geembeeLocationId": "clx1234...",
    "providerRevision": "17",
    "providerStateRevision": "23",
    "providerSyncedAt": "2026-08-25T09:00:00.000Z",
    "snapshot": {
      "name": "Mein Unternehmen GmbH",
      "address": {
        "formatted": "Mariahilfer Straße 1, 1060 Wien",
        "addressLines": ["Mariahilfer Straße 1"],
        "locality": "Wien",
        "administrativeArea": "Wien",
        "postalCode": "1060",
        "regionCode": "AT"
      },
      "phone": "+43 1 234567",
      "website": "https://example.at",
      "primaryCategory": {
        "id": "gcid:restaurant",
        "displayName": "Restaurant"
      },
      "timeZone": null,
      "businessStatus": "OPEN",
      "regularHours": {
        "periods": [{
          "openDay": "MONDAY",
          "openTime": "09:00",
          "closeDay": "MONDAY",
          "closeTime": "17:00"
        }]
      },
      "specialHours": null,
      "reviews": { "averageRating": 4.8, "totalCount": 124 }
    },
    "fieldCompleteness": {
      "name": "COMPLETE",
      "address": "COMPLETE",
      "phone": "COMPLETE",
      "website": "COMPLETE",
      "primaryCategory": "COMPLETE",
      "timeZone": "UNAVAILABLE",
      "businessStatus": "COMPLETE",
      "regularHours": "COMPLETE",
      "specialHours": "EMPTY",
      "reviews.averageRating": "COMPLETE",
      "reviews.totalCount": "COMPLETE"
    },
    "providerState": {
      "status": "OK",
      "lastAttemptAt": "2026-08-25T09:00:00.000Z",
      "lastSuccessfulRevision": "17",
      "lastSuccessfulAt": "2026-08-25T09:00:00.000Z",
      "errorCode": null,
      "retryable": false,
      "stale": false
    }
  }
}
GET/api/v1/menus/:locationIdScope: LOCATIONS_READ

Gibt die aktiven Menüs einer geembee-Location inklusive Sektionen und verfügbarer Einträge zurück.

Parameter

NameTypPflichtBeschreibung
locationIdstring✓Interne geembee Location-ID (nicht die Google Place ID)

Beispiel-Antwort

{
  "success": true,
  "data": [
    {
      "id": "menu_123",
      "name": "Frühstück",
      "isActive": true,
      "sortOrder": 0,
      "sections": [
        {
          "id": "section_abc",
          "name": "Getränke",
          "sortOrder": 0,
          "items": [
            {
              "id": "item_xyz",
              "name": "Cappuccino",
              "description": "Mit Hafermilch erhältlich",
              "price": 4.2,
              "priceText": null,
              "isAvailable": true
            }
          ]
        }
      ]
    }
  ],
  "meta": {
    "locationId": "clx1234...",
    "totalMenus": 1,
    "apiVersion": "v1"
  }
}
POST/api/v1/locations/syncScope: SYNC_TRIGGER

Synchronisiert die API-Key-genau gebundene Partner-Google-Verbindung erneut mit Google Business Profile. Standortdaten, reguläre und besondere Öffnungszeiten sowie alle Review-Seiten werden aktualisiert. Eine HMAC-Signatur ist verpflichtend.

Parameter

NameTypPflichtBeschreibung
placeIdstring✓Google Place ID des zu synchronisierenden Standorts
connectionIdUUID✓Exakt gebundene GeemBee-Connection-ID

Beispiel-Antwort

{
  "success": true,
  "data": {
    "locationId": "clx1234...",
    "placeId": "ChIJN1t_tDeuEmsRUsoyG83frY4",
    "syncedAt": "2026-02-27T10:15:00Z",
    "status": "synced",
    "connectionId": "55d24db0-52cf-4df2-8b15-51cb27064972",
    "providerRevision": "17",
    "providerStateRevision": "23",
    "providerStatus": "OK",
    "snapshotUrl": "/api/v1/locations/ChIJN1t_tDeuEmsRUsoyG83frY4/connections/55d24db0-52cf-4df2-8b15-51cb27064972/snapshot",
    "reviewsSynced": 27
  }
}
DELETE/api/v1/locations/:placeId/connectionScope: SYNC_TRIGGER

Widerruft zuerst den dauerhaften Google-Refresh-Token und entfernt anschließend die API-Key-genaue Partnerverbindung lokal. Eine HMAC-Signatur ist verpflichtend; ein Provider-Fehler lässt die lokale Verbindung unverändert.

Parameter

NameTypPflichtBeschreibung
placeIdstring (Pfad)✓Google Place ID der gebundenen Partnerverbindung
connectionIdUUID (JSON-Body)✓Opake Verbindungs-ID aus dem Location-Endpunkt

Beispiel-Antwort

{
  "success": true,
  "data": {
    "revoked": true,
    "connectionId": "55d24db0-52cf-4df2-8b15-51cb27064972"
  }
}
POST/api/v1/locations/:placeId/postsScope: POSTS_WRITE

Erstellt und veröffentlicht einen idempotenten Standard-Post im Google Business Profile. Der Pfad akzeptiert die Google Place ID oder die interne geembee Location-ID. HMAC-Signatur ist verpflichtend.

Parameter

NameTypPflichtBeschreibung
placeIdstring (Pfad)✓Google Place ID oder interne geembee Location-ID
sourcestring✓Stabile Integrationsquelle, z.B. pressefeuer
externalIdstring✓Stabile Quell-ID für idempotente Wiederholungen
contentstring✓Post-Text mit maximal 1.500 Zeichen
callToActionstring–NONE, BOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP oder CALL
ctaUrlurl–Ziel-URL; für die meisten CTAs erforderlich
mediaUrlurl–Öffentlich erreichbare Bild-URL

Beispiel-Antwort

{
  "success": true,
  "created": true,
  "data": {
    "id": "clxpost...",
    "status": "PUBLISHED",
    "googleState": "LIVE",
    "publicUrl": "https://www.google.com/search?...",
    "publishedAt": "2026-07-14T10:30:00.000Z",
    "source": "pressefeuer",
    "externalId": "release-123"
  }
}
POST/api/v1/blog/mediaScope: BLOG_WRITE

Lädt ein KI-generiertes Blogbild als Base64/Data-URL in den geembee Storage hoch. HMAC-Signatur ist verpflichtend.

Parameter

NameTypPflichtBeschreibung
imagestring✓Base64 oder data:image/png;base64,... (PNG, JPEG oder WebP, max. 10 MB)
filenamestring–Dateiname, z.B. kmu-ki-google-business.png
contentTypestring–image/png, image/jpeg oder image/webp
altstring–Alt-Text für das Bild

Beispiel-Antwort

{
  "success": true,
  "file": {
    "id": "clxmedia...",
    "filename": "kmu-ki-google-business.png",
    "url": "https://bucket.s3.eu-central-1.amazonaws.com/blog/...",
    "key": "blog/user/...",
    "contentType": "image/png",
    "alt": "Unternehmerin plant KI-gestützte Google-Beiträge"
  }
}
POST/api/v1/blog/postsScope: BLOG_WRITE

Erstellt einen Blogbeitrag für den öffentlichen geembee Blog. Vollständige KI-unterstützte Beiträge können sofort als PUBLISHED angelegt werden und tragen bis zur separaten redaktionellen Bestätigung eine wahrheitsgemäße Kennzeichnung mit ausstehender Prüfung. HMAC-Signatur ist verpflichtend; der Content wird sicher als Markdown-light/Text gerendert.

Parameter

NameTypPflichtBeschreibung
titlestring✓Titel des Blogbeitrags
contentstring✓Artikeltext mit Absätzen, ##/### Überschriften und Listen
statusstring–DRAFT, PUBLISHED oder ARCHIVED; Default: DRAFT
categorystring–Primäre redaktionelle Kategorie
coverImageUrlurl–URL des Blogbilds, z.B. aus /api/v1/blog/media
coverImageAltstring–Motivbeschreibung; bei KI-Bildern mit - AI GENERATED oder - AI MODIFIED abschließen
aiAssistedboolean–Aktiviert Kennzeichnung und Veröffentlichungs-Gate
aiImageClassificationstring–AI_GENERATED oder AI_MODIFIED
aiImageClassificationNotestring–Dokumentierte Begründung der Bildklassifikation
aiOverlayVariantstring–BLACK_50 oder WHITE_50 nach Kontrastprüfung
showAiOverlayExamplesboolean–Zeigt alle vier lokalen 50-%-Beispiele, wenn der Artikel die Kennzeichnung selbst erklärt
seoTitlestring–SEO-Titel
seoDescriptionstring–Meta-Description

Beispiel-Antwort

{
  "success": true,
  "data": {
    "id": "clxpost...",
    "title": "KI für KMU: Google Business Profile effizienter nutzen",
    "slug": "ki-fuer-kmu-google-business-profile-effizienter-nutzen",
    "status": "PUBLISHED",
    "publishedAt": "2026-08-03T09:00:00.000Z",
    "aiAssisted": true,
    "aiImageClassification": "AI_GENERATED",
    "aiOverlayVariant": "BLACK_50",
    "coverImageUrl": "https://bucket.s3.eu-central-1.amazonaws.com/blog/...",
    "url": "https://www.geembee.com/blog/ki-fuer-kmu-google-business-profile-effizienter-nutzen"
  }
}
PUT/api/v1/blog/posts/:slugScope: BLOG_WRITE

Aktualisiert einen bestehenden Blogbeitrag. KI-Beiträge dürfen veröffentlicht bleiben, während die redaktionelle Prüfung aussteht. Nach öffentlicher Prüfung bestätigt ein separater PUT mit editorialReviewConfirmed=true die menschliche Freigabe. Jede spätere materielle Änderung setzt diese Freigabe zurück und aktiviert wieder die ausstehende Kennzeichnung. HMAC-Signatur ist verpflichtend.

Parameter

NameTypPflichtBeschreibung
slugstring (Pfad)✓Slug des zu aktualisierenden Blogbeitrags
titlestring–Titel (5–180 Zeichen)
slug (Body)string–Neuer Slug (3–180 Zeichen); wird immer normalisiert und bei Kollision automatisch eindeutig gemacht
categorystring | null–Primäre Kategorie (max. 80 Zeichen)
excerptstring | null–Kurzbeschreibung (max. 500 Zeichen); null entfernt sie
contentstring–Artikeltext (120–120.000 Zeichen)
statusstring–DRAFT, PUBLISHED oder ARCHIVED
publishedAtdatetime | null–ISO-8601-Zeitstempel; null entfernt das Veröffentlichungsdatum
tagsstring[]–Max. 12 Tags (je 1–48 Zeichen)
coverImageUrlurl | null–URL des Blogbilds; null entfernt es
coverImageAltstring | null–Alt-Text mit Motiv und abschließender Bildklasse (max. 180 Zeichen)
aiAssistedboolean–Aktiviert Text- und Bildkennzeichnung samt Gate
aiImageClassificationstring | null–AI_GENERATED oder AI_MODIFIED
aiImageClassificationNotestring | null–Begründung der Klassifikation
aiOverlayVariantstring | null–BLACK_50 oder WHITE_50
showAiOverlayExamplesboolean–Alle vier offiziellen Beispielgrafiken anzeigen
editorialReviewConfirmedboolean–Nur als separater PUT nach Prüfung der final gespeicherten und öffentlich sichtbaren Fassung
seoTitlestring | null–SEO-Titel (max. 180 Zeichen)
seoDescriptionstring | null–Meta-Description (max. 300 Zeichen)

Beispiel-Antwort

{
  "success": true,
  "data": {
    "id": "clxpost...",
    "title": "KI für KMU: Google Business Profile effizienter nutzen",
    "slug": "ki-fuer-kmu-google-business-profile-effizienter-nutzen",
    "category": "Google Business Profile",
    "excerpt": "So setzen kleine Unternehmen KI für ihr Google Business Profile ein.",
    "content": "## Warum lokale Sichtbarkeit zählt\n\n...",
    "status": "PUBLISHED",
    "publishedAt": "2026-05-19T08:15:00.000Z",
    "tags": ["KI", "KMU", "Google Business Profile"],
    "coverImageUrl": "https://bucket.s3.eu-central-1.amazonaws.com/blog/...",
    "coverImageAlt": "Unternehmerin plant KI-gestützte Google-Beiträge - AI GENERATED",
    "aiAssisted": true,
    "aiImageClassification": "AI_GENERATED",
    "aiImageClassificationNote": "Das Bild wurde vollständig mit einem Bildmodell erzeugt.",
    "aiOverlayVariant": "BLACK_50",
    "editorialReviewedAt": "2026-05-19T08:10:00.000Z",
    "seoTitle": null,
    "seoDescription": null,
    "createdAt": "2026-05-18T09:00:00.000Z",
    "updatedAt": "2026-05-19T08:20:00.000Z",
    "url": "https://www.geembee.com/blog/ki-fuer-kmu-google-business-profile-effizienter-nutzen"
  }
}
DELETE/api/v1/blog/posts/:slugScope: BLOG_WRITE

Archiviert einen Blogbeitrag (Soft-Delete): Der Status wird auf ARCHIVED gesetzt, der Beitrag verschwindet aus der öffentlichen Ansicht, bleibt aber erhalten. HMAC-Signatur ist verpflichtend; da die Anfrage keinen Body hat, wird die Signatur über den leeren Body gebildet (timestamp + Punkt). Unbekannter Slug liefert 404.

Parameter

NameTypPflichtBeschreibung
slugstring (Pfad)✓Slug des zu archivierenden Blogbeitrags

Beispiel-Antwort

{
  "success": true,
  "data": {
    "id": "clxpost...",
    "title": "KI für KMU: Google Business Profile effizienter nutzen",
    "slug": "ki-fuer-kmu-google-business-profile-effizienter-nutzen",
    "status": "ARCHIVED",
    "publishedAt": "2026-05-19T08:15:00.000Z",
    "tags": ["KI", "KMU", "Google Business Profile"],
    "createdAt": "2026-05-18T09:00:00.000Z",
    "updatedAt": "2026-05-20T11:42:00.000Z",
    "url": "https://www.geembee.com/blog/ki-fuer-kmu-google-business-profile-effizienter-nutzen"
  }
}

Fehlercodes

HTTP StatusBedeutung
200Erfolgreich
400Ungültige Anfrage (fehlende oder falsche Parameter)
401Authentifizierung fehlgeschlagen (falscher Key/Secret)
403Fehlender Scope für diese Aktion
404Ressource nicht gefunden
429Rate Limit überschritten
500Interner Serverfehler

Fehler-Antwort Format

{ "error": "Beschreibung des Fehlers" }

Rate Limiting

Standardmäßig sind 60 Anfragen pro Minute erlaubt. Bei Überschreitung wird HTTP 429 zurückgegeben. Für höhere Limits kontaktiere uns.

Code-Beispiele

JavaScript / TypeScript

const response = await fetch(
  "https://www.geembee.com/api/v1/locations",
  {
    headers: {
      "X-GeemBee-Key": process.env.GEEMBEE_API_KEY,
      "X-GeemBee-Secret": process.env.GEEMBEE_API_SECRET,
    },
  }
);

const { data } = await response.json();
console.log(data); // Array of locations

Signierter KI-Blog-Entwurf

import crypto from "node:crypto";

const body = JSON.stringify({
  title: "KI für KMU: Google Business Profile effizienter nutzen",
  content: "## Warum lokale Sichtbarkeit zählt\n\n...",
  status: "DRAFT",
  category: "Google Business Profile",
  excerpt: "So setzen kleine Unternehmen KI kontrolliert ein.",
  tags: ["KI", "KMU", "Google Business Profile"],
  coverImageUrl: "https://geembee-uploads.s3.eu-central-1.amazonaws.com/blog/...",
  coverImageAlt: "Fachleute prüfen einen lokalen Redaktionsplan - AI GENERATED",
  aiAssisted: true,
  aiImageClassification: "AI_GENERATED",
  aiImageClassificationNote: "Das Bild wurde vollständig mit einem Bildmodell erzeugt.",
  aiOverlayVariant: "BLACK_50",
});

const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
  .createHmac("sha256", process.env.GEEMBEE_API_SECRET!)
  .update(`${timestamp}.${body}`)
  .digest("hex");

await fetch("https://www.geembee.com/api/v1/blog/posts", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-GeemBee-Key": process.env.GEEMBEE_API_KEY!,
    "X-GeemBee-Secret": process.env.GEEMBEE_API_SECRET!,
    "X-GeemBee-Timestamp": timestamp,
    "X-GeemBee-Signature": signature,
  },
  body,
});

PHP

$response = file_get_contents(
  "https://www.geembee.com/api/v1/locations",
  false,
  stream_context_create([
    "http" => [
      "header" => implode("\r\n", [
        "X-GeemBee-Key: " . getenv("GEEMBEE_API_KEY"),
        "X-GeemBee-Secret: " . getenv("GEEMBEE_API_SECRET"),
      ]),
    ],
  ])
);
$data = json_decode($response, true);

API Key anfragen

Die geembee API ist für externe Partner verfügbar. Kontaktiere uns für einen API Key.

[email protected]