API Endpoints
Complete reference for all Petal API endpoints.
Authentication Endpoints
These endpoints don't require authentication.
POST /auth/login
Sign in with email and password.
Request:
{
"email": "user@example.com",
"password": "your-password"
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "v1.MjAyNi0wMS0yN...",
"expires_at": "2026-01-27T16:30:00Z",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"full_name": "John Doe"
}
}
Error Codes:
INVALID_CREDENTIALS- Wrong email or passwordUSER_NOT_FOUND- No account with this email
POST /auth/signup
Create a new account.
Request:
{
"email": "newuser@example.com",
"password": "secure-password",
"full_name": "Jane Smith"
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "v1.MjAyNi0wMS0yN...",
"expires_at": "2026-01-27T16:30:00Z",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"email": "newuser@example.com",
"full_name": "Jane Smith"
}
}
Error Codes:
EMAIL_EXISTS- Account already existsVALIDATION_ERROR- Invalid email or password format
POST /auth/refresh
Refresh an expired access token.
Request:
{
"refresh_token": "v1.MjAyNi0wMS0yN..."
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "v1.MjAyNi0wMS0yOC...",
"expires_at": "2026-01-27T17:30:00Z"
}
Subscription Endpoints
Requires Bearer token authentication.
GET /subscription/status
Get current subscription and license information.
Response:
{
"has_subscription": true,
"subscription": {
"plan": "standard",
"status": "active",
"current_period_start": "2026-01-01T00:00:00Z",
"current_period_end": "2026-02-01T00:00:00Z",
"cancel_at_period_end": false
},
"license": {
"key_preview": "PETAL-XXXX...XXXX",
"plan": "standard",
"status": "active",
"activations": 1,
"max_activations": 1
},
"features": {
"real_time_visualization": true,
"osc_lsl_streaming": true,
"session_recording": true,
"csv_export": true,
"api_access": true,
"signal_filtering": false,
"custom_preprocessing": false,
"mental_state_detection": false,
"max_devices": 1
}
}
License Endpoints
Requires Bearer token authentication.
POST /license/validate
Validate a license key for a specific device.
Request:
{
"license_key": "PETAL-XXXX-XXXX-XXXX-XXXX",
"device_id": "HW-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX"
}
Response (valid):
{
"valid": true,
"plan": "standard",
"status": "active",
"activations": 1,
"max_activations": 1,
"can_activate": false,
"already_activated_on_device": true,
"features": {
"real_time_visualization": true,
"osc_lsl_streaming": true,
"csv_export": true,
"api_access": true,
"max_devices": 1
}
}
Response (invalid):
{
"valid": false,
"error": "License not found",
"code": "LICENSE_NOT_FOUND"
}
Error Codes:
LICENSE_NOT_FOUND- Key doesn't existLICENSE_REVOKED- License has been revokedLICENSE_EXPIRED- License has expiredSUBSCRIPTION_INACTIVE- Subscription is not active
POST /license/activate
Activate a license on a device.
Request:
{
"license_key": "PETAL-XXXX-XXXX-XXXX-XXXX",
"device_id": "HW-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX",
"device_name": "My Desktop PC",
"platform": "Windows"
}
Response:
{
"success": true,
"activation_id": "550e8400-e29b-41d4-a716-446655440002",
"activations": 1,
"max_activations": 1,
"message": "Device activated successfully"
}
Error Codes:
LICENSE_NOT_FOUND- Key doesn't existLICENSE_INACTIVE- License is not activeMAX_ACTIVATIONS_REACHED- No more device slots available
API Key Endpoints
POST /metrics/api-key
Generate or retrieve your API key. Requires Bearer token.
Response (new key):
{
"api_key": "petal_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"is_legacy": false,
"plan": "standard",
"features": {
"api_access": true
},
"created_at": "2026-01-27T15:00:00Z",
"message": "New API key generated"
}
Response (existing key):
{
"api_key_prefix": "petal_live_xxxx",
"is_legacy": false,
"plan": "standard",
"features": {
"api_access": true
},
"created_at": "2026-01-20T10:00:00Z",
"message": "Existing API key (showing prefix only)"
}
POST /metrics/api-key/validate
Validate an API key. No authentication required (rate limited).
Request:
{
"api_key": "petal_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
Response (valid):
{
"valid": true,
"plan": "standard",
"source": "new",
"features": {
"api_access": true,
"csv_export": true
},
"subscription_active": true
}
Response (invalid):
{
"valid": false,
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}
Response (expired - legacy customers):
{
"valid": false,
"code": "SUBSCRIPTION_EXPIRED",
"expires_at": "2026-02-27T00:00:00Z"
}
Error Codes:
INVALID_API_KEY- Key doesn't exist or is malformedSUBSCRIPTION_INACTIVE- Associated subscription is not activeSUBSCRIPTION_EXPIRED- Grandfathered access has ended (see Migration Guide)API_ACCESS_DISABLED- Plan doesn't include API access
Utility Endpoints
POST /heartbeat
Send device heartbeat for session tracking. Requires Bearer token.
Request:
{
"device_id": "HW-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX"
}
Response:
{
"success": true,
"timestamp": "2026-01-27T15:30:00Z"
}
Response (with warning):
{
"success": true,
"timestamp": "2026-01-27T15:30:00Z",
"warning": "Unusual activity detected on this device"
}
GET /binary-hash
Get SHA256 hashes of installer files. No authentication required.
Response:
{
"version": "1.0.0",
"hashes": {
"windows_x64": "sha256:abc123def456...",
"macos_arm64": "sha256:789xyz012...",
"linux_amd64": "sha256:345mno678..."
},
"updated_at": "2026-01-27T12:00:00Z"
}
Response (not configured):
{
"error": "Binary hashes not configured",
"message": "Hashes are set during release builds"
}