Skip to content

Auth (Reference)

For most users the login + refresh pair in Getting Started → Authentication is all you need. This page documents the two endpoints that aren’t strictly necessary for a daily-loop client but are required for programmatic onboarding (signup) and user-profile management (me).


Create a new account via Supabase Auth. Optional profile fields are stored on the Supabase user’s user_metadata and seeded into public.users on the first authenticated request.

Auth: None

Terminal window
curl -X POST https://api.hungrymachines.io/auth/signup \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword",
"location_zip": "92101",
"home_size_sqft": 2000,
"pricing_location": 1
}'
{
"email": "user@example.com",
"password": "securepassword",
"location_zip": "92101",
"home_size_sqft": 2000,
"pricing_location": 1
}
FieldTypeRequiredNotes
emailstringYesMust be unique
passwordstringYesSubject to the project’s Supabase password policy
location_zipstringNoUS zip code, used for weather forecasts. Stored on user_metadata.location_zip.
home_size_sqftintegerNoUsed to estimate HVAC power draw. Stored on user_metadata.home_size_sqft.
pricing_locationintegerNoTOU pricing zone 1–8 (default: 1). Stored on user_metadata.pricing_location.

When the project does not require email confirmation, the response is a full Supabase session:

{
"access_token": "eyJhbGciOi...",
"refresh_token": "JKLrM3...",
"expires_in": 3600,
"expires_at": 1762450800,
"token_type": "bearer",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com"
}
}

Response (200) — email confirmation pending

Section titled “Response (200) — email confirmation pending”

When the project requires email confirmation, the session fields (access_token, refresh_token, expires_in, expires_at, token_type) may be absent and the body contains only the pending user row:

{
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com"
}
}

Clients must handle both shapes — typically by treating the absence of access_token as “show a confirm-your-email screen.”

StatusDetailCause
400"User already registered"Email is already in use (or other Supabase signup failure message)
422"Password should be at least 6 characters"Supabase password policy rejection
502"Auth service unreachable"Supabase upstream failure
503"Auth not configured"SUPABASE_URL / SUPABASE_PUBLISHABLE_KEY missing on the API

Get the current user’s profile and subscription tier. Lazily creates the user’s public.users row keyed to auth.users(id) on first call, seeded from the JWT’s user_metadata claim.

Auth: Required (Bearer JWT)

Terminal window
curl https://api.hungrymachines.io/auth/me \
-H "Authorization: Bearer YOUR_TOKEN"
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"location_zip": "92101",
"home_size_sqft": 2000,
"pricing_location": 1,
"timezone": "America/New_York",
"subscription_tier": "free",
"weather_entity_id": "weather.home"
}
FieldTypeNotes
user_idstring (UUID)Matches the Supabase auth.users.id (the JWT sub claim)
emailstring
location_zipstringMay be empty
home_size_sqftintegerMay be 0
pricing_locationintegerTOU pricing zone 1–8
timezonestringIANA timezone
subscription_tierstring"free" or "premium". Defaults to "free" if no active subscription.
weather_entity_idstringThe Home Assistant weather.* entity the user picked in the panel’s Settings tab. Empty string when unset — the API then falls back to Open-Meteo for nightly forecasts.
StatusDetailCause
401"Not authenticated" / "Invalid token" / "Token expired"Missing, malformed, or expired token
503"Database unavailable" / "Auth not configured"Backend dependency unavailable

Update the user’s profile row. Send only the fields you want to change.

Auth: Required (Bearer JWT)

Terminal window
curl -X PATCH https://api.hungrymachines.io/auth/me \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"location_zip": "94110",
"home_size_sqft": 1800,
"pricing_location": 3,
"timezone": "America/Los_Angeles"
}'

All fields are optional — include only what you want to change. Sending null clears the value.

{
"location_zip": "94110",
"home_size_sqft": 1800,
"pricing_location": 3,
"timezone": "America/Los_Angeles",
"weather_entity_id": "weather.home"
}
FieldTypeValidation
location_zipstring | nullUS zip code
home_size_sqftinteger | null
pricing_locationinteger | null1–8
timezonestring | nullIANA timezone
weather_entity_idstring | nullHA weather.* entity id. The nightly job’s forecast resolver prefers a pushed forecast from this entity over the Open-Meteo fallback.

Returns the full profile object after the update — same shape as GET /auth/me.

StatusDetailCause
401"Not authenticated"Missing or invalid token
503"Database unavailable"Database not configured or write failed