Skip to main content

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 password
  • USER_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 exists
  • VALIDATION_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 exist
  • LICENSE_REVOKED - License has been revoked
  • LICENSE_EXPIRED - License has expired
  • SUBSCRIPTION_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 exist
  • LICENSE_INACTIVE - License is not active
  • MAX_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 malformed
  • SUBSCRIPTION_INACTIVE - Associated subscription is not active
  • SUBSCRIPTION_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"
}