API Reference
Base URL
https://api.vbatpower.com
All endpoints are prefixed with /api/v1. Authentication is via session cookies (for browser clients) or API keys (for MCU/server clients). The API is free with no usage limits beyond the abuse-protection rate limits described below.
Authentication
/api/v1/auth/register Create a new account with email and password (minimum 8 characters, maximum 72).
{"email": "user@example.com", "password": "securePassword123"} Returns 201 with user object and sets session cookie. Returns 409 if email already exists. Rate limited to 5 requests / 15 min per IP in production.
/api/v1/auth/login Sign in with email and password.
{"email": "user@example.com", "password": "securePassword123"} Returns 200 with user object and sets session cookie. Returns 401 on wrong credentials. Rate limited to 10 requests / 15 min per IP in production.
/api/v1/auth/me Get the current authenticated user. Requires session cookie.
Returns 200 with user object containing id, email, name, role fields, or 401 if not authenticated.
/api/v1/auth/logout End the current session. Clears the session cookie and deletes the session row.
/api/v1/auth/logout-all Revoke every session for the current user (sign out on all devices). Requires session cookie. Returns 200 with {"status": "ok"}, or 401 if not authenticated.
/api/v1/auth/providers List the OAuth providers currently enabled on the server. Public β no authentication required. Returns {"providers": ["google", "github"]} (the array contains only providers configured at deploy time).
/api/v1/auth/oauth/:provider Redirect to OAuth provider login. Supported providers: google, microsoft, github. After consent the provider returns to /api/v1/auth/oauth/:provider/callback, which sets the session cookie and redirects back to the app.
Projects
All project endpoints require authentication (session cookie). Project bodies may be up to 2 MB.
/api/v1/projects List all projects for the authenticated user, ordered by last update. Returns id, name, description, tags, and timestamps (not the full data blob).
/api/v1/projects Create a new project. name is required (max 255 chars); description (max 4096 chars), tags (array of up to 50 strings, each up to 64 chars), and data are optional. Returns 201.
{"name": "Sensor Node", "data": {"batteries": [...]}} /api/v1/projects/:id Get a project by ID (returns full data including batteries). Returns 404 if not found or not owned by user.
/api/v1/projects/:id Update a project. Only provided fields are updated (PATCH semantics β omitted fields keep their current value). Returns 404 if the project is not owned by the user.
/api/v1/projects/:id Delete a project and all associated data. Returns 204 on success.
Project data schema
The data field holds the project model: an object with a batteries array. Each battery has a numeric id (its depth-1 hierarchical index) and a components array; each component has an id and a states array; each state has an id plus its operating-mode fields. The id values map directly onto the dot-notation telemetry IDs (battery 0 β component 0.0 β state 0.0.0).
{
"name": "Sensor Node",
"description": "ESP32 + INA219",
"tags": ["esp32", "lipo"],
"data": {
"batteries": [
{
"id": 0,
"name": "18650 cell",
"voltageMin": 3.0,
"voltageMax": 4.2,
"current": 2.5,
"currentUnit": "Ah",
"components": [
{
"id": 0,
"name": "ESP32",
"states": [
{"id": 0, "name": "Deep Sleep", "alwaysOn": true, "current": 10, "currentUnit": "u"},
{"id": 1, "name": "Active", "current": 80, "currentUnit": "m", "interval": 60, "intervalUnit": "s", "execTime": 5, "execTimeUnit": "s"}
]
}
]
}
]
}
} Common state fields: name, alwaysOn (boolean), current + currentUnit, interval + intervalUnit, execTime + execTimeUnit, and runOnce (boolean). The data object is stored as-is, so any fields produced by the app are round-tripped.
Telemetry
/api/v1/telemetry Upload telemetry records. Requires API key as Authorization: Bearer <key> header. Up to 10,000 records per request; the key determines the target project. Rate limited to 60 requests / minute per project (returns 429 when exceeded). Returns 201 with {"status": "ok", "inserted": N}.
{"records": [
{"id": "0", "type": "v", "value": 3.28, "unit": "V", "nonce": 1, "runid": 1},
{"id": "0.0.0", "type": "t", "value": 1523, "unit": "ms", "nonce": 1, "runid": 1},
{"id": "0.0.0", "type": "v", "value": 12.5, "unit": "mA", "nonce": 1, "runid": 1}
]} /api/v1/telemetry/:projectId Retrieve telemetry records for a project. Requires API key as Authorization: Bearer <key>; the key must be scoped to the requested project (otherwise 403).
Results are paginated by id cursor. Query params: limit (1β1000, default 1000) and cursor (return rows with id greater than this value, default 0). The response includes next_cursor β pass it back as cursor to fetch the next page; it is null when no rows were returned.
{
"project_id": 1,
"records": [
{"id": 42, "record_id": "0", "record_type": "v", "value": 3.28, "unit": "V", "nonce": 1, "runid": 1, "received_at": "2026-01-01T12:00:00.000Z"}
],
"next_cursor": 42
} Formula History
All formula-history endpoints require authentication (session cookie).
/api/v1/formulas/history Save a formula calculation to history. formula_id and solve_for are required. Returns 201.
{"formula_id": "ohms-law", "solve_for": "V", "inputs": {"I": 0.5, "R": 100}, "result": 50} /api/v1/formulas/history?limit=50 Get recent formula calculations, newest first. limit is clamped to 1β500 (default 50).
/api/v1/formulas/history/:id Delete a single history entry by ID. Returns 200 with {"status": "ok"}, or 404 if the entry is not found or not owned by the user.
/api/v1/formulas/history Clear the entire formula history for the current user. Returns 200 with {"status": "ok"}.
API Keys
All API-key management endpoints require authentication (session cookie). Keys are used by MCUs and scripts to upload telemetry without a browser session.
/api/v1/keys Create an API key scoped to a project. project_id is required; name is optional (max 128 chars). Up to 50 active keys per user.
{"project_id": 1, "name": "ESP32 Sensor"} Returns 201 with the key string (prefixed vbat_). Store it securely β it cannot be retrieved again.
/api/v1/keys List the user's API keys, newest first. Returns id, project_id, key prefix, name, created timestamp, and revoked flag β never the full key.
/api/v1/keys/:id Revoke an API key by ID. The key stops working immediately. Returns 200 with {"status": "ok"}, or 404 if the key is not found or already revoked.
Rate Limits
VBatPower is free with no usage quotas. The only limits are abuse-protection rate limits, enforced per IP (auth) or per project (telemetry) in production:
POST /api/v1/auth/registerβ 5 requests per 15 minutes per IPPOST /api/v1/auth/loginβ 10 requests per 15 minutes per IPPOST /api/v1/telemetryβ 60 requests per minute per project
Exceeding a limit returns 429 with body {"error": "Too many requests"}. Request bodies are also capped: 64 KB for auth, keys, and formula-history routes; 2 MB for projects and telemetry. Oversized bodies return 413 with {"error": "Payload too large"}.
Error Responses
All errors return JSON with an error field describing the problem:
{"error": "Not authenticated"} HTTP status codes used by the API:
400β bad request (invalid JSON, missing or malformed field)401β not authenticated (missing/expired session or invalid API key)403β forbidden (API key not scoped to the requested project)404β not found (or not owned by the authenticated user)409β conflict (email already registered)413β payload too large429β too many requests (rate limit exceeded)500β internal error
End-to-End MCU Walkthrough
This ties the endpoints together for the typical hardware flow: generate a key, create a project, push telemetry, and read it back. All requests use the base URL https://api.vbatpower.com.
1. Create a project (browser session)
Sign in to the app, or call the API with your session cookie:
curl -X POST https://api.vbatpower.com/api/v1/projects \
-H "Content-Type: application/json" \
--cookie "session=YOUR_SESSION" \
-d '{"name":"Sensor Node","data":{"batteries":[{"id":0,"components":[{"id":0,"states":[{"id":0}]}]}]}}'
# -> 201 {"project": {"id": 1, ...}} 2. Generate an API key for that project
curl -X POST https://api.vbatpower.com/api/v1/keys \
-H "Content-Type: application/json" \
--cookie "session=YOUR_SESSION" \
-d '{"project_id":1,"name":"ESP32 Sensor"}'
# -> 201 {"key": "vbat_xxxxxxxx...", "project_id": 1}
# Copy the key now β it is shown only once. 3. POST telemetry from the device (Bearer key)
No session or cookie needed β the key authenticates the device and selects the project. See MCU Integration for Arduino/ESP32/STM32 code that produces this request.
curl -X POST https://api.vbatpower.com/api/v1/telemetry \
-H "Content-Type: application/json" \
-H "Authorization: Bearer vbat_xxxxxxxx..." \
-d '{"records":[
{"id":"0","type":"v","value":3.28,"unit":"V","nonce":1,"runid":1},
{"id":"0.0.0","type":"t","value":1523,"unit":"ms","nonce":1,"runid":1},
{"id":"0.0.0","type":"v","value":12.5,"unit":"mA","nonce":1,"runid":1},
{"id":"0.0.0","type":"n","value":0,"unit":"ms","nonce":1,"runid":1}
]}'
# -> 201 {"status": "ok", "inserted": 4} 4. Verify the data landed
Read it back with the same key, or open the project's Graphs page in the app:
curl https://api.vbatpower.com/api/v1/telemetry/1?limit=1000 \
-H "Authorization: Bearer vbat_xxxxxxxx..."
# -> 200 {"project_id": 1, "records": [...], "next_cursor": 42}
# Page through more rows by passing ?cursor=42 on the next call.