SipWiser

Home › Developers

SipWiser API

A read-only REST API for your own synced SipWiser sessions and sips. It's platform-neutral: curl, a script, a spreadsheet, a dashboard, or a home-automation platform can all call it the same way.

Last updated: September 2026

Overview

The API gives you read-only access to your own synced sessions and sips — the same rows the SipWiser app has already synced to your account. It's a SipWiser Plus feature. There's no server-side computation: no BAC, no stats, no goals — just the rows you've logged, with field names matching the app's data model.

Freshness follows sync. A drink logged while offline appears through the API once your phone has synced it. Every response carries a generatedAt timestamp so you know exactly when it was produced.

Getting a token

In the app: Settings → Integrations → Create token. The token is shown once — copy it somewhere safe. You can have up to 5 active tokens at a time, and revoke any of them from the same screen; a revoked token stops working immediately.

Authentication

Send the token as a bearer token on every request:

Authorization: Bearer sw_your_token_here

Base URL:

https://rpnwaclrnttyvwepzoar.supabase.co/functions/v1/api

Endpoints

GET /v1/sessions/active

The current in-progress session, if any, with the sips logged in it so far.

{
  "generatedAt": "2026-09-27T21:04:12.000Z",
  "session": {
    "id": "b3b6b8b0-…",
    "name": "Friday evening",
    "tag": "with_friends",
    "startedAt": "2026-09-27T19:12:00.000Z",
    "endedAt": null,
    "endReason": null,
    "createdAt": "2026-09-27T19:12:03.000Z",
    "updatedAt": "2026-09-27T20:58:41.000Z"
  },
  "sips": [
    {
      "id": "1a2b3c4d-…",
      "sessionId": "b3b6b8b0-…",
      "presetId": null,
      "name": "Beer 330ml",
      "isAutoNamed": true,
      "date": "2026-09-27T19:12:00.000Z",
      "type": "beer",
      "wineStyle": null,
      "beerStyle": "lager",
      "spiritCategory": null,
      "quantityMl": 330,
      "abvPercent": 5,
      "curatedRecipeId": null,
      "curatedCatalogId": null,
      "createdAt": "2026-09-27T19:12:03.000Z",
      "updatedAt": "2026-09-27T19:12:03.000Z"
    }
  ]
}

If no session is active, session is null and sips is an empty array.

GET /v1/sessions

Your sessions, newest first.

ParamMeaning
sinceISO 8601 date (2026-09-01) or date-time. Only sessions started at or after this.
limit1–200, default 50.
cursorFrom a previous response's nextCursor, for the next page.
{
  "generatedAt": "2026-09-27T21:04:12.000Z",
  "sessions": [
    {
      "id": "b3b6b8b0-…",
      "name": "Friday evening",
      "tag": "with_friends",
      "startedAt": "2026-09-27T19:12:00.000Z",
      "endedAt": null,
      "endReason": null,
      "createdAt": "2026-09-27T19:12:03.000Z",
      "updatedAt": "2026-09-27T20:58:41.000Z"
    }
  ],
  "nextCursor": null
}

GET /v1/sips

Your sips, newest first.

ParamMeaning
sinceISO 8601 date or date-time. Only sips consumed at or after this.
limit1–200, default 50.
cursorFrom a previous response's nextCursor, for the next page.
session_idOnly sips belonging to this session (sips endpoint only).
{
  "generatedAt": "2026-09-27T21:04:12.000Z",
  "sips": [
    {
      "id": "1a2b3c4d-…",
      "sessionId": "b3b6b8b0-…",
      "presetId": null,
      "name": "Beer 330ml",
      "isAutoNamed": true,
      "date": "2026-09-27T19:12:00.000Z",
      "type": "beer",
      "wineStyle": null,
      "beerStyle": "lager",
      "spiritCategory": null,
      "quantityMl": 330,
      "abvPercent": 5,
      "curatedRecipeId": null,
      "curatedCatalogId": null,
      "createdAt": "2026-09-27T19:12:03.000Z",
      "updatedAt": "2026-09-27T19:12:03.000Z"
    }
  ],
  "nextCursor": null
}

Objects

Session

FieldTypeMeaning
idstringSession id.
namestring | nullUser-defined or auto-generated label.
tagstring | nullContext tag for the occasion (e.g. with_friends).
startedAtstring (ISO 8601, UTC)Timestamp of the first sip.
endedAtstring | nullnull while the session is in progress.
endReasonstring | nullHow the session was closed (auto or manual).
createdAtstring (ISO 8601, UTC)When the row was created.
updatedAtstring (ISO 8601, UTC)When the row last changed.

Sip

FieldTypeMeaning
idstringSip id.
sessionIdstringThe session this sip belongs to.
presetIdstring | nullThe saved quick log this sip was logged from, if any.
namestringDrink name, auto-generated or user-edited.
isAutoNamedboolean | nullWhether name was auto-generated rather than typed.
datestring (ISO 8601, UTC)When the drink was consumed.
typestringDrink type (e.g. beer, wine, spirit, cocktail).
wineStylestring | nullWine sub-type. Only meaningful when type is wine.
beerStylestring | nullBeer sub-type. Only meaningful when type is beer.
spiritCategorystring | nullSpirit sub-type. Only meaningful when type is spirit.
quantityMlnumberVolume, in millilitres.
abvPercentnumberAlcohol by volume, in percent.
curatedRecipeIdstring | nullReference to a curated cocktail recipe, if logged from one.
curatedCatalogIdstring | nullReference to a curated beer/spirit catalog item, if logged from one.
createdAtstring (ISO 8601, UTC)When the row was created.
updatedAtstring (ISO 8601, UTC)When the row last changed.

Location is not part of the response: SipWiser can attach GPS coordinates and a place name to a sip, but the API never returns it, even to a valid token.

Pagination

A list response includes nextCursor. Pass it back as ?cursor= to fetch the next page; it's null on the last page.

Errors

Errors are a small JSON body: { "error": "<code>" }.

StatusCodeMeaning
400bad_requestA query parameter is missing or malformed.
401invalid_tokenThe bearer token is missing, malformed, unrecognized or revoked.
403plus_requiredThe token's account doesn't currently have SipWiser Plus.
404not_foundThe route or resource doesn't exist.
429rate_limitedToo many requests. See Retry-After.
500internalSomething went wrong on our end.

Limits

Examples

curl

curl -s \
  -H "Authorization: Bearer sw_your_token_here" \
  https://rpnwaclrnttyvwepzoar.supabase.co/functions/v1/api/v1/sessions/active

JavaScript (fetch)

const res = await fetch(
  "https://rpnwaclrnttyvwepzoar.supabase.co/functions/v1/api/v1/sessions?limit=20",
  { headers: { Authorization: "Bearer sw_your_token_here" } },
);
const { sessions, nextCursor } = await res.json();

Python (requests)

import requests

r = requests.get(
    "https://rpnwaclrnttyvwepzoar.supabase.co/functions/v1/api/v1/sips",
    headers={"Authorization": "Bearer sw_your_token_here"},
    params={"limit": 50},
)
data = r.json()

Home Assistant

One example consumer among many: a RESTful sensor that knows when a session is in progress and how many sips are in it. Store the token in secrets.yaml:

sipwiser_auth: "Bearer sw_your_token_here"

Then, in configuration.yaml:

rest:
  - resource: https://rpnwaclrnttyvwepzoar.supabase.co/functions/v1/api/v1/sessions/active
    headers:
      Authorization: !secret sipwiser_auth
    scan_interval: 60
    binary_sensor:
      - name: SipWiser session active
        value_template: "{{ value_json.session is not none }}"
    sensor:
      - name: SipWiser sips this session
        value_template: "{{ value_json.sips | length }}"

One line that applies to everything here. A blood-alcohol estimate is never a clearance to drive. Whatever you build on top of this data, never let it read as a green light. Never drive after drinking, whatever any number says.