API Reference · v1

PowerLab REST API

Read-only access to your PowerLab projects. Pull calculations into a spreadsheet, wire up a client-handoff tool, or back up your designs with a scheduled script.

Base URL

https://powerlab.marinepowerlab.com/api/v1

Authentication

Every request requires a Bearer token. Generate a key from Settings → API Keys. Keys look like plk_… and are shown exactly once at creation.

curl -H "Authorization: Bearer plk_your_key_here" \
  https://powerlab.marinepowerlab.com/api/v1/projects

Invalid or revoked keys return 401 Unauthorized. A valid key whose user isn't on an active paid plan (Solo or Business) returns 403 Forbidden.

Rate limits

Per API key, not per user. Limits are advisory headers on every response (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) plus a 429 body when exceeded.

  • Project list: 100/hour
  • Project detail + loads + components: 200/hour each

Code samples

Replace plk_… with your real key. The same pattern works for every endpoint below.

cURLbash
curl -H "Authorization: Bearer plk_your_key_here" \
  https://powerlab.marinepowerlab.com/api/v1/projects
Python (requests)python
import os, requests

key = os.environ['POWERLAB_API_KEY']
res = requests.get(
    'https://powerlab.marinepowerlab.com/api/v1/projects',
    headers={'Authorization': f'Bearer {key}'},
    timeout=15,
)
res.raise_for_status()
for p in res.json()['data']:
    print(p['name'], '—', p['system_voltage'], 'V')
JavaScript (Node / fetch)javascript
const key = process.env.POWERLAB_API_KEY;
const res = await fetch('https://powerlab.marinepowerlab.com/api/v1/projects', {
  headers: { Authorization: `Bearer ${key}` },
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const { data } = await res.json();
for (const project of data) {
  console.log(project.name, '—', project.system_voltage, 'V');
}
Google Sheets (Apps Script)javascript
function importPowerLabProjects() {
  const key = PropertiesService.getScriptProperties().getProperty('POWERLAB_API_KEY');
  const res = UrlFetchApp.fetch(
    'https://powerlab.marinepowerlab.com/api/v1/projects',
    { headers: { Authorization: 'Bearer ' + key } }
  );
  const { data } = JSON.parse(res.getContentText());
  const rows = data.map(p => [p.name, p.vessel_type, p.system_voltage, p.updated_at]);
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange(1, 1, rows.length, rows[0].length).setValues(rows);
}

Endpoints

GET/projects

List your projects, newest first.

Query parameters

  • limit (integer)Default 25, max 100.
  • offset (integer)For pagination.

Response

{
  "data": [
    {
      "id": "uuid",
      "name": "Catalina 36 lithium conversion",
      "vessel_type": "sailboat",
      "system_voltage": 12,
      "location_name": "Vancouver, BC",
      "peak_sun_hours": 4.2,
      "share_token": "…",
      "is_public": false,
      "permit_report_unlocked_at": null,
      "created_at": "2026-04-01T13:00:00.000Z",
      "updated_at": "2026-04-12T18:22:01.000Z"
    }
  ],
  "pagination": { "limit": 25, "offset": 0, "total": 4 }
}
GET/projects/{id}

Full project detail — project row, loads, installed components, and freshly-computed calculations.

Response

{
  "project": { … project columns … },
  "loads": [ …project_loads rows, joined to appliance… ],
  "installed_components": [ … ],
  "calculations": {
    "loads":   { totalDailyWh, totalDailyAh, peakWatts, monthlyKwh, … },
    "battery": { recommendedCapacityAh, batteryConfig, estimatedCost, weightKg, reasoning },
    "solar":   { recommendedSolarWatts, panelCount, panelWattage, chargeControllerAmps, estimatedCost, reasoning }
  }
}
GET/projects/{id}/loads

Machine-readable load list for this project.

Query parameters

  • format (string)Pass format=csv for a CSV stream (otherwise JSON).

Response

{
  "data": [
    {
      "id": "uuid",
      "custom_name": null,
      "watts": 45,
      "quantity": 1,
      "hours_per_day": 16,
      "is_enabled": true,
      "is_critical": true,
      "sort_order": 3,
      "appliance": { "name": "12V Marine Fridge", "category": "Refrigeration" }
    }
  ]
}
GET/projects/{id}/components

Installed-component library for this project: brand/model/serial/warranty dates.

Response

{
  "data": [
    {
      "id": "uuid",
      "component_type": "battery",
      "brand": "Battle Born",
      "model": "BB10012",
      "serial_number": "…",
      "purchase_date": "2024-05-14",
      "warranty_expiry": "2034-05-14",
      "price_paid": 899.00,
      "currency": "CAD",
      "notes": "…",
      "created_at": "…",
      "updated_at": "…"
    }
  ]
}

Common integrations

Google Sheets

Apps Script snippet above. Schedule it on a time-driven trigger to keep your spreadsheet in sync nightly.

Zapier / Make

Use their generic "Webhooks by Zapier" / "HTTP" module with GET + Bearer auth. No dedicated connector yet.

Python / Pandas

pd.read_json on the JSON response or CSV loads endpoint. Good for BoM analysis across multiple projects.

Postman / Bruno

Set collection-level Authorization to Bearer. Import the full base URL and hit each endpoint interactively.

MCP server (for AI assistants)

PowerLab ships a free Model Context Protocol server — marinepowerlab-mcp — that gives Claude, and any other MCP-capable assistant, six electrical-design tools backed by the same verified calculation engine as the app: wire sizing, DC load, battery bank, solar array, inverter sizing, and a compliance-document summary. Every answer is deterministic and cites its code basis (ABYC E-11, NEC Table 310.16, CSA C22.1 Table 2).

{
  "mcpServers": {
    "powerlab-electrical": {
      "command": "npx",
      "args": ["-y", "marinepowerlab-mcp"]
    }
  }
}

No API key required for the calculator tools. Source lives alongside the app; results match the in-app engine verbatim (drift-tested).

What's NOT here

v1 is read-only on purpose. No write endpoints, no project mutations, no public appliance catalog. Writes live behind the session-authenticated UI. Future additions (webhooks, write endpoints, bulk exports) will be announced in the PowerLab dashboard.