Portal API
Authenticate external apps, desktop tools, and scripts with email/password, then read company, license, project, and device inventory via Bearer tokens.
Overview
The Portal API is a read-only JSON API for user accounts (not devices).
It is separate from the device APIs that use X-Device-Token and from CLI provisioning tokens.
- Auth: Laravel Sanctum personal access tokens
- Base path:
/api - All inventory responses are scoped to the authenticated user's company
Authentication flow
- Call
POST /api/auth/loginwith email and password. - Store the returned
token. - Send
Authorization: Bearer <token>on subsequent requests. - Call
POST /api/auth/logoutto revoke the current token.
Login
POST /api/auth/login
Content-Type: application/json
{
"email": "you@company.com",
"password": "your-password",
"device_name": "graphlab-desktop"
}
Optional device_name labels the token (default: portal-api). Rate limited to 10 requests per minute.
{
"token": "1|xxxxxxxx",
"token_type": "Bearer",
"user": { "id": 1, "name": "...", "email": "...", "role": "admin", "company_id": 1 },
"company": { "id": 1, "name": "Acme Corp" }
}
Current user
GET /api/auth/me
Authorization: Bearer 1|xxxxxxxx
Logout
POST /api/auth/logout
Authorization: Bearer 1|xxxxxxxx
Inventory endpoints
All require Authorization: Bearer <token> and are rate limited to 60 requests per minute.
| Method | Path | Description |
|---|---|---|
| GET | /api/portal/company |
Company profile, onboarding state, capabilities, summary counts |
| GET | /api/portal/licenses |
Device license pools, platform licenses (+ maintenance), display integrations |
| GET | /api/portal/projects |
Projects with nested groups overview |
| GET | /api/portal/projects/{id} |
Single project + groups |
| GET | /api/portal/devices |
Device list (never includes api_token) |
| GET | /api/portal/devices/{device_id} |
Device detail by UUID string or numeric DB id |
Error codes
| HTTP | Meaning |
|---|---|
| 401 | Missing/invalid Bearer token, or login failed credentials |
| 403 | Authenticated user has no company linked |
| 404 | Resource not found or belongs to another company |
| 422 | Validation error (e.g. login fields) |
| 429 | Rate limit exceeded |
Curl examples
# Login
TOKEN=$(curl -s -X POST "$APP_URL/api/auth/login" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"email":"you@company.com","password":"your-password"}' \
| php -r 'echo json_decode(stream_get_contents(STDIN))->token;')
# Company
curl -s "$APP_URL/api/portal/company" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
# Licenses
curl -s "$APP_URL/api/portal/licenses" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
# Projects + devices
curl -s "$APP_URL/api/portal/projects" -H "Authorization: Bearer $TOKEN" -H "Accept: application/json"
curl -s "$APP_URL/api/portal/devices" -H "Authorization: Bearer $TOKEN" -H "Accept: application/json"
# Logout
curl -s -X POST "$APP_URL/api/auth/logout" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
Token management in the portal
Under Account you can see every active personal access token for your user: name, created time, last used, and expiry. You can revoke a single token or all tokens. Revoking immediately invalidates that Bearer token for API calls.
Related APIs
- CLI Provisioning — group provision token →
license.bin - Devices — on-device APIs with
X-Device-Token - Licensing — meaning of platform / display / device pools