Integrations - BevvyTech/BrewskiDocs GitHub Wiki

Integrations

Method Path Description
GET /integrations List integration records for a team (manager access only).
POST /integrations/breww/connect Store/refresh the Breww API key after validating credentials.
GET /integrations/breww/products Search Breww products for the connected team.
GET /integrations/breww/catalog Retrieve the full Breww product catalog (50 items per page, auto-paginated).
GET /integrations/breww/container-types Fetch container type metadata from Breww (auto-paginated).
POST /integrations/breww/link Link a Breww product/container to a Brewski beer.
DELETE /integrations/breww/link Remove an existing Breww ↔︎ beer mapping.

GET /integrations

  • Auth: Bearer token; caller must belong to the team and hold owner or admin role.
  • Query Parameters: teamId (uuid, required).
  • Response 200:
    {
      "integrations": [
        {
          "id": "9d94...",
          "teamId": "d43c046a-10a1-4f52-bd0a-9bf16f828ab7",
          "integration": "breww",
          "lastState": "connected",
          "hasConfig": true,
          "connectedAt": "2025-02-14T10:12:00.000Z",
          "lastSeenAt": "2025-02-14T10:12:00.000Z",
          "metadata": {
            "business": { "id": 10, "name": "Lantern Brewery" }
          }
        }
      ]
    }
    • Secrets remain redacted; a connected record exposes a metadata.business summary for UI display.
  • Errors: 400 invalid query, 401 unauthorized, 403 insufficient role, 404 when integration namespace not recognised.

POST /integrations/breww/connect

  • Auth: Bearer token; caller must be a team owner/admin.
  • Body:
    {
      "teamId": "d43c046a-10a1-4f52-bd0a-9bf16f828ab7",
      "apiKey": "breww_xxxxx"
    }
  • Behaviour:
    • Calls https://breww.com/api/business-details/ to validate the key before storing it in team_integrations.config.
    • Updates/creates the integration record with lastState = "connected", tracked timestamps, and cached business metadata.
  • Response 200: { "integration": { ... } } matching the list representation above.
  • Errors: 400 invalid payload or Breww rejecting the key, 401, 403 (non-manager), 404 invalid integration slug, 502 upstream Breww failure.

GET /integrations/breww/products

  • Auth: Bearer token; caller must be owner/admin on the team and have a connected Breww integration.
  • Query Parameters:
    • teamId (uuid, required)
    • q (string, required) — search term; at least two characters.
    • page (integer, optional, default 1) — forwarded to Breww (page_size fixed at 20).
  • Response 200:
    {
      "results": [
        {
          "productId": "101",
          "productName": "Lantern Pale 30L Keg",
          "productCode": "LAN-30K",
          "containerId": "5001",
          "containerName": "30 L Keg",
          "containerType": "keg"
        }
      ],
      "pagination": {
        "count": 1,
        "next": null,
        "previous": null
      }
    }
    • Results flatten Breww’s component_drinks so each product/container pair appears as a discrete option for the UI autocomplete.
  • Errors: 400 invalid query or integration not connected, 401, 403 (non-manager), 502 Breww API failure.

GET /integrations/breww/catalog

  • Auth: Bearer token; caller must be owner/admin on the team and have a connected Breww integration.
  • Query Parameters:
    • teamId (uuid, required)
  • Behaviour:
    • Fetches the Breww /products/ endpoint sequentially, 50 records per page, ordered by name.
    • Aggregates component containers by containerName so the UI can present a single row per beer with its available package formats.
    • Caps traversal at 200 pages (~10k records) to avoid runaway syncs; truncates and logs a warning if the limit is hit.
  • Response 200:
    {
      "products": [
        {
          "productId": "101",
          "productName": "Lantern Pale",
          "productCode": "LAN-PALE",
          "containers": [
            { "containerId": "5001", "containerName": "Lantern Pale 30L Keg", "containerType": "keg" },
            { "containerId": "9001", "containerName": "Lantern Pale 500ml Bottle", "containerType": "bottle" }
          ]
        }
      ]
    }
  • Errors: 400 invalid query or integration not connected, 401, 403 (non-manager), 502 Breww API failure.

GET /integrations/breww/container-types

  • Auth: Bearer token; caller must be owner/admin on the team and have a connected Breww integration.
  • Query Parameters:
    • teamId (uuid, required)
  • Behaviour:
    • Traverses the Breww /container-types/ endpoint 100 records per page, ordered by name, until pagination ends or 200 pages are fetched.
    • Normalises each record into Brewski container types (keg, cask, bottle, can) using Breww’s type and smallpack_sub_type metadata.
    • Converts litre capacities to integer millilitres for downstream containersService.create calls and deduplicates by Breww container id.
  • Response 200:
    {
      "containers": [
        {
          "id": "301",
          "name": "30L Keg",
          "containerType": "keg",
          "brewwType": "KEG",
          "smallpackSubType": null,
          "volumeMl": 30000
        },
        {
          "id": "401",
          "name": "440ml Can",
          "containerType": "can",
          "brewwType": "SMALL",
          "smallpackSubType": 1,
          "volumeMl": 440
        }
      ],
      "sourceCount": 2
    }
  • Errors: 400 invalid query or integration not connected, 401, 403 (non-manager), 502 Breww API failure.

POST /integrations/breww/link

  • Auth: Bearer token; caller must be owner/admin on the beer’s team.
  • Body:
    {
      "teamId": "d43c046a-10a1-4f52-bd0a-9bf16f828ab7",
      "beerId": "8f62...",
      "product": {
        "id": "101",
        "name": "Lantern Pale 30L Keg",
        "code": "LAN-30K",
        "containerId": "5001",
        "containerName": "30 L Keg",
        "containerType": "keg"
      }
    }
  • Behaviour:
    • Upserts a beer_integrations record scoped to (beerId, integration = "breww").
    • Stores external ids, container details, and helper metadata (code, containerType) in JSON for downstream sync jobs.
    • Rejects beers whose inventoryMode is managed; only manual beers can be linked.
  • Response 200:
    {
      "integration": {
        "integration": "breww",
        "externalBeerId": "101",
        "externalBeerName": "Lantern Pale 30L Keg",
        "externalContainerId": "5001",
        "externalContainerName": "30 L Keg",
        "metadata": {
          "code": "LAN-30K",
          "containerType": "keg"
        },
        "createdAt": "2025-02-14T10:12:00.000Z",
        "updatedAt": "2025-02-14T10:12:00.000Z"
      }
    }
  • Errors: 400 invalid payload, missing Breww integration, or beer inventory mode not manual; 401, 403 (non-manager), 404 beer not found.

DELETE /integrations/breww/link

  • Auth: Bearer token; caller must be owner/admin on the beer’s team.
  • Body: { "teamId": "...", "beerId": "..." }.
  • Response 204: Mapping removed (idempotent; deleting a non-existent link also returns 204).
  • Errors: 400 invalid payload, 401, 403 (non-manager), 404 beer not found, 500 unexpected delete failure.
⚠️ **GitHub.com Fallback** ⚠️