Home › Developers
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
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.
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.
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
GET /v1/sessions/activeThe 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/sessionsYour sessions, newest first.
| Param | Meaning |
|---|---|
since | ISO 8601 date (2026-09-01) or date-time. Only sessions started at or after this. |
limit | 1–200, default 50. |
cursor | From 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/sipsYour sips, newest first.
| Param | Meaning |
|---|---|
since | ISO 8601 date or date-time. Only sips consumed at or after this. |
limit | 1–200, default 50. |
cursor | From a previous response's nextCursor, for the next page. |
session_id | Only 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
}
| Field | Type | Meaning |
|---|---|---|
id | string | Session id. |
name | string | null | User-defined or auto-generated label. |
tag | string | null | Context tag for the occasion (e.g. with_friends). |
startedAt | string (ISO 8601, UTC) | Timestamp of the first sip. |
endedAt | string | null | null while the session is in progress. |
endReason | string | null | How the session was closed (auto or manual). |
createdAt | string (ISO 8601, UTC) | When the row was created. |
updatedAt | string (ISO 8601, UTC) | When the row last changed. |
| Field | Type | Meaning |
|---|---|---|
id | string | Sip id. |
sessionId | string | The session this sip belongs to. |
presetId | string | null | The saved quick log this sip was logged from, if any. |
name | string | Drink name, auto-generated or user-edited. |
isAutoNamed | boolean | null | Whether name was auto-generated rather than typed. |
date | string (ISO 8601, UTC) | When the drink was consumed. |
type | string | Drink type (e.g. beer, wine, spirit, cocktail). |
wineStyle | string | null | Wine sub-type. Only meaningful when type is wine. |
beerStyle | string | null | Beer sub-type. Only meaningful when type is beer. |
spiritCategory | string | null | Spirit sub-type. Only meaningful when type is spirit. |
quantityMl | number | Volume, in millilitres. |
abvPercent | number | Alcohol by volume, in percent. |
curatedRecipeId | string | null | Reference to a curated cocktail recipe, if logged from one. |
curatedCatalogId | string | null | Reference to a curated beer/spirit catalog item, if logged from one. |
createdAt | string (ISO 8601, UTC) | When the row was created. |
updatedAt | string (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.
A list response includes nextCursor. Pass it back as ?cursor= to fetch the next page; it's null on the last page.
Errors are a small JSON body: { "error": "<code>" }.
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | A query parameter is missing or malformed. |
| 401 | invalid_token | The bearer token is missing, malformed, unrecognized or revoked. |
| 403 | plus_required | The token's account doesn't currently have SipWiser Plus. |
| 404 | not_found | The route or resource doesn't exist. |
| 429 | rate_limited | Too many requests. See Retry-After. |
| 500 | internal | Something went wrong on our end. |
curl -s \
-H "Authorization: Bearer sw_your_token_here" \
https://rpnwaclrnttyvwepzoar.supabase.co/functions/v1/api/v1/sessions/active
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();
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()
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.