Developer Docs

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

  1. Call POST /api/auth/login with email and password.
  2. Store the returned token.
  3. Send Authorization: Bearer <token> on subsequent requests.
  4. Call POST /api/auth/logout to 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
401Missing/invalid Bearer token, or login failed credentials
403Authenticated user has no company linked
404Resource not found or belongs to another company
422Validation error (e.g. login fields)
429Rate 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