Auth (Reference)
For most clients the login + refresh pair in Getting Started → Authentication is all you need. This page documents the endpoints that aren’t strictly part of the daily loop but are useful for programmatic onboarding (signup) and profile management (me).
POST /auth/signup
Section titled “POST /auth/signup”Create a new account. Optional profile fields are stored on the account and applied on the first authenticated request.
Auth: None
Required vs. optional
Section titled “Required vs. optional”Only email and password are required. Every profile field below is optional and can be set (or changed) later via PATCH /auth/me.
Example
Section titled “Example”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 }'Request body
Section titled “Request body”| Field | Type | Required | Notes |
|---|---|---|---|
email | string | Yes | Must be unique |
password | string | Yes | Subject to the account password policy |
location_zip | string | No | US zip code, used for weather forecasts |
home_size_sqft | integer | No | Used to estimate appliance power draw |
pricing_location | integer | No | Rate-catalog id (see available_pricing_zones from GET /api/v1/rates; default 1) |
newsletter_opt_in | boolean | No | Newsletter checkbox state. Omitted means opted in. |
Response (200) — session returned
Section titled “Response (200) — session returned”When the account doesn’t require email confirmation, the response is a full 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 email confirmation is required, 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.”
Errors
Section titled “Errors”| Status | Detail | Cause |
|---|---|---|
| 400 | "User already registered" | Email is already in use (or another signup failure message) |
| 422 | "Password should be at least 6 characters" | Password policy rejection |
| 502 | "Auth service unreachable" | Identity provider upstream failure |
| 503 | "Auth not configured" | Auth not configured on the API |
GET /auth/me
Section titled “GET /auth/me”Get the current user’s profile and subscription tier. Creates the profile row on first call.
Auth: Required (Bearer JWT)
Example
Section titled “Example”curl https://api.hungrymachines.io/auth/me \ -H "Authorization: Bearer YOUR_TOKEN"Response (200)
Section titled “Response (200)”{ "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"}Response fields
Section titled “Response fields”| Field | Type | Notes |
|---|---|---|
user_id | string (UUID) | Account id (matches the JWT subject) |
email | string | |
location_zip | string | May be empty |
home_size_sqft | integer | May be 0 |
pricing_location | integer | Rate-catalog id (see available_pricing_zones) |
timezone | string | IANA timezone |
subscription_tier | string | "free" or "premium". Defaults to "free". |
weather_entity_id | string | The Home Assistant weather.* entity the user picked for forecasts. Empty when unset (a fallback weather source is then used). |
Errors
Section titled “Errors”| Status | Detail | Cause |
|---|---|---|
| 401 | "Not authenticated" / "Invalid token" / "Token expired" | Missing, malformed, or expired token |
| 503 | "Database unavailable" / "Auth not configured" | Backend dependency unavailable |
PATCH /auth/me
Section titled “PATCH /auth/me”Update the profile row. Send only the fields you want to change.
Auth: Required (Bearer JWT)
Required vs. optional
Section titled “Required vs. optional”All fields are optional — include only what you want to change. Sending null clears the value.
Example
Section titled “Example”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" }'Request body
Section titled “Request body”{ "location_zip": "94110", "home_size_sqft": 1800, "pricing_location": 3, "timezone": "America/Los_Angeles", "weather_entity_id": "weather.home"}| Field | Type | Validation |
|---|---|---|
location_zip | string | null | US zip code |
home_size_sqft | integer | null | |
pricing_location | integer | null | Rate-catalog id (see available_pricing_zones) |
timezone | string | null | IANA timezone |
weather_entity_id | string | null | HA weather.* entity id. The nightly forecast resolver prefers a pushed forecast from this entity over the fallback source. |
Response (200)
Section titled “Response (200)”Returns the full profile object after the update — same shape as GET /auth/me.
Errors
Section titled “Errors”| Status | Detail | Cause |
|---|---|---|
| 401 | "Not authenticated" | Missing or invalid token |
| 503 | "Database unavailable" | Database not configured or write failed |