Getting started with PHY API
Introduction to the PHY API — authentication, base URL, response format, and quick-start examples.
PHY API lets you programmatically manage your utility infrastructure — meters, gateways, building blocks, tariffs, and invoices — for any organization you belong to.
Getting started
- Sign up or log in at phy.engineering.
- Obtain an access token by calling
POST /api/v1/auth/loginwith your email and password. - Include the token in every subsequent request using the
Authorization: Bearer <access_token>header.
You can also import our ready-to-use Postman collection and start testing immediately.
- Download: PHY API Postman Collection
- Import into Postman, set the
base_urlandaccount_idcollection variables, then run Authentication → Login to auto-populate theaccess_token.
Base URL
- Production:
https://phy.engineering
Authentication
All endpoints (except Login, Signup, Refresh, and the Postman collection download) require a Bearer JWT in the Authorization header.
Login example
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "your_password"}' \
https://phy.engineering/api/v1/auth/login
Example response:
{
"success": true,
"message": "Authentication successful",
"data": {
"access_token": "eyJhbGci...",
"refresh_token": "...",
"expires_at": 1735689600,
"expires_in": 3600,
"user": {
"id": "8b4cdb8d-...",
"email": "user@example.com",
"created_at": "2025-11-13T10:00:00Z"
}
}
}
Use the access_token from the response in subsequent calls:
ACCESS_TOKEN="eyJhbGci..." ACCOUNT_ID="your-organization-uuid" curl -s \ -H "Authorization: Bearer $ACCESS_TOKEN" \ "https://phy.engineering/api/v1/meters?account_id=$ACCOUNT_ID" | jq
Account scoping
Most resource endpoints are scoped to an organization via the account_id parameter (UUID). You can find your organization's account_id from the GET /api/v1/auth/organizations endpoint.
- List / read / delete — pass
account_idas a query parameter - Create / update — include
account_idin the JSON request body
Response envelope
All endpoints return a consistent JSON envelope:
{
"success": true,
"message": "optional human readable message",
"data": {},
"count": 1,
"error": "error text when success is false"
}
Success examples
List (200):
{
"success": true,
"data": [{ "id": 1, "name": "Example" }],
"count": 1
}
Create (201):
{
"success": true,
"message": "Resource created successfully",
"data": { "id": 42, "name": "New Resource" }
}
Error examples
Validation error (400):
{
"success": false,
"message": "Invalid request body",
"error": "account_id: Invalid uuid"
}
Unauthorized (401):
{
"success": false,
"message": "Authentication required",
"error": "invalid or missing bearer token"
}
Quick-start with curl
# 1. Log in and capture the access token
ACCESS_TOKEN=$(curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "your_password"}' \
https://phy.engineering/api/v1/auth/login | jq -r '.data.access_token')
# 2. Find your organization IDs
curl -s \
-H "Authorization: Bearer $ACCESS_TOKEN" \
https://phy.engineering/api/v1/auth/organizations | jq
# 3. List meters for an organization
ACCOUNT_ID="your-organization-uuid"
curl -s \
-H "Authorization: Bearer $ACCESS_TOKEN" \
"https://phy.engineering/api/v1/meters?account_id=$ACCOUNT_ID" | jq
# 4. Create a tariff
curl -s -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"account_id": "'$ACCOUNT_ID'",
"name": "Residential 2026",
"meter_type": "ELECTRICITY",
"tariff_type": "FLAT"
}' \
https://phy.engineering/api/v1/tariffs | jq
Common HTTP status codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Resource created |
| 204 | Success, no content (e.g., delete) |
| 400 | Bad request — validation error |
| 401 | Unauthorized — missing or invalid token |
| 403 | Forbidden — resource belongs to a different organization |
| 404 | Not found |
| 500 | Internal server error |