⎿ # V2-Docker API Reference

## Authentication

### API Key Authentication

All License Server API endpoints require authentication using an API key. The API key must be included in the
request headers.

**Header Format:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

**API Key Management:**
- API keys can be managed through the Admin Panel under "Lizenzserver Administration" → "System-API-Key
generieren"
- Keys follow the format: `AF-YYYY-[32 random characters]`
- Only one system API key is active at a time
- Regenerating the key will immediately invalidate the old key
- The initial API key is automatically generated on first startup
- To retrieve the initial API key from database: `SELECT api_key FROM system_api_key WHERE id = 1;`

**Error Response (401 Unauthorized):**
```json
{
  "error": "Invalid or missing API key",
  "code": "INVALID_API_KEY",
  "status": 401
}
```

## License Server API

**Base URL:** `https://api-software-undso.intelsight.de`

### Public Endpoints

#### GET /
Root endpoint - Service status.

**Response:**
```json
{
  "status": "ok",
  "service": "V2 License Server",
  "timestamp": "2025-06-19T10:30:00Z"
}
```

#### GET /health
Health check endpoint.

**Response:**
```json
{
  "status": "healthy",
  "timestamp": "2025-06-19T10:30:00Z"
}
```

#### GET /metrics
Prometheus metrics endpoint.

**Response:**
Prometheus metrics in CONTENT_TYPE_LATEST format.

### License API Endpoints

All license endpoints require API key authentication via `X-API-Key` header.

#### POST /api/license/activate
Activate a license on a new system.

**Headers:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/json
```

**Request:**
```json
{
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "hardware_hash": "unique-hardware-identifier",
  "machine_name": "DESKTOP-ABC123",
  "app_version": "1.0.0"
}
```

**Response:**
```json
{
  "message": "License activated successfully",
  "activation": {
    "id": 123,
    "license_key": "XXXX-XXXX-XXXX-XXXX",
    "hardware_hash": "unique-hardware-identifier",
    "machine_name": "DESKTOP-ABC123",
    "activated_at": "2025-06-19T10:30:00Z",
    "last_heartbeat": "2025-06-19T10:30:00Z",
    "is_active": true
  }
}
```

#### POST /api/license/verify
Verify an active license.

**Headers:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/json
```

**Request:**
```json
{
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "hardware_hash": "unique-hardware-identifier",
  "app_version": "1.0.0"
}
```

**Response:**
```json
{
  "valid": true,
  "message": "License is valid",
  "license": {
    "key": "XXXX-XXXX-XXXX-XXXX",
    "valid_until": "2026-01-01",
    "max_users": 10
  },
  "update_available": false,
  "latest_version": "1.0.0"
}
```

#### GET /api/license/info/{license_key}
Get license information.

**Headers:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

**Response:**
```json
{
  "license": {
    "id": 123,
    "key": "XXXX-XXXX-XXXX-XXXX",
    "customer_name": "ACME Corp",
    "type": "perpetual",
    "valid_from": "2025-01-01",
    "valid_until": "2026-01-01",
    "max_activations": 5,
    "max_users": 10,
    "is_active": true
  },
  "activations": [
    {
      "id": 456,
      "hardware_hash": "unique-hardware-identifier",
      "machine_name": "DESKTOP-ABC123",
      "activated_at": "2025-06-19T10:00:00Z",
      "last_heartbeat": "2025-06-19T14:30:00Z",
      "is_active": true
    }
  ]
}
```

### Session Management API Endpoints

**Note:** Session endpoints require that the client application is configured in the `client_configs` table.
The default client "Account Forger" is pre-configured.

#### POST /api/license/session/start
Start a new session for a license.

**Headers:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/json
```

**Request:**
```json
{
  "license_key": "XXXX-XXXX-XXXX-XXXX",
  "machine_id": "DESKTOP-ABC123",
  "hardware_hash": "unique-hardware-identifier",
  "version": "1.0.0"
}
```

**Response:**
- 200 OK: Returns session_token and optional update info
- 409 Conflict: "Es ist nur eine Sitzung erlaubt..." (single session enforcement)

#### POST /api/license/session/heartbeat
Keep session alive with heartbeat.

**Headers:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/json
```

**Request:**
```json
{
  "session_token": "550e8400-e29b-41d4-a716-446655440000",
  "license_key": "XXXX-XXXX-XXXX-XXXX"
}
```

**Response:** 200 OK with last_heartbeat timestamp

#### POST /api/license/session/end
End an active session.

**Headers:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/json
```

**Request:**
```json
{
  "session_token": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Response:** 200 OK with session duration and end reason

### Version API Endpoints

#### POST /api/version/check
Check for available updates.

**Headers:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

**Request:**
```json
{
  "current_version": "1.0.0",
  "license_key": "XXXX-XXXX-XXXX-XXXX"
}
```

**Response:**
```json
{
  "update_available": true,
  "latest_version": "1.1.0",
  "download_url": "https://example.com/download/v1.1.0",
  "release_notes": "Bug fixes and performance improvements"
}
```

#### GET /api/version/latest
Get latest version information.

**Headers:**
```
X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

**Response:**
```json
{
  "version": "1.1.0",
  "release_date": "2025-06-20",
  "download_url": "https://example.com/download/v1.1.0",
  "release_notes": "Bug fixes and performance improvements"
}
```

## Admin Panel API

**Base URL:** `https://admin-panel-undso.intelsight.de`

### Customer API Endpoints

#### GET /api/customers
Search customers for Select2 dropdown.

**Query Parameters:**
- `q`: Search query
- `page`: Page number (default: 1)

**Response:**
```json
{
  "results": [
    {
      "id": 123,
      "text": "ACME Corp - admin@acme.com"
    }
  ],
  "pagination": {
    "more": false
  }
}
```


### License Management API

- `POST /api/license/{id}/toggle` - Toggle active status
- `POST /api/licenses/bulk-activate` - Activate multiple (license_ids array)
- `POST /api/licenses/bulk-deactivate` - Deactivate multiple
- `POST /api/licenses/bulk-delete` - Delete multiple
- `POST /api/license/{id}/quick-edit` - Update validity/limits
- `GET /api/license/{id}/devices` - List registered devices

#### POST /api/license/{license_id}/quick-edit
Quick edit license properties.

**Request:**
```json
{
  "valid_until": "2027-01-01",
  "max_activations": 10,
  "max_users": 50
}
```

**Response:**
```json
{
  "success": true,
  "message": "License updated successfully"
}
```

#### POST /api/generate-license-key
Generate a new license key.

**Response:**
```json
{
  "license_key": "NEW1-NEW2-NEW3-NEW4"
}
```

### Device Management API

#### GET /api/license/{license_id}/devices
Get devices for a license.

**Response:**
```json
{
  "devices": [
    {
      "id": 123,
      "hardware_hash": "unique-hardware-identifier",
      "machine_name": "DESKTOP-ABC123",
      "activated_at": "2025-01-01T10:00:00Z",
      "last_heartbeat": "2025-06-19T14:30:00Z",
      "is_active": true,
      "app_version": "1.0.0"
    }
  ]
}
```

#### POST /api/license/{license_id}/register-device
Register a new device.

**Request:**
```json
{
  "hardware_hash": "unique-hardware-identifier",
  "machine_name": "DESKTOP-XYZ789",
  "app_version": "1.0.0"
}
```

**Response:**
```json
{
  "success": true,
  "device_id": 456,
  "message": "Device registered successfully"
}
```

#### POST /api/license/{license_id}/deactivate-device/{device_id}
Deactivate a device.

**Response:**
```json
{
  "success": true,
  "message": "Device deactivated successfully"
}
```

### Resource Management API

#### GET /api/license/{license_id}/resources
Get resources for a license.

**Response:**
```json
{
  "resources": [
    {
      "id": 789,
      "type": "server",
      "identifier": "SRV-001",
      "status": "allocated",
      "allocated_at": "2025-06-01T10:00:00Z"
    }
  ]
}
```

#### POST /api/resources/allocate
Allocate resources to a license.

**Request:**
```json
{
  "license_id": 123,
  "resource_ids": [789, 790]
}
```

**Response:**
```json
{
  "success": true,
  "allocated": 2,
  "message": "2 resources allocated successfully"
}
```

#### GET /api/resources/check-availability
Check resource availability.

**Query Parameters:**
- `type`: Resource type
- `count`: Number of resources needed

**Response:**
```json
{
  "available": true,
  "count": 5,
  "resources": [
    {
      "id": 791,
      "type": "server",
      "identifier": "SRV-002"
    }
  ]
}
```


### Search API

#### GET /api/global-search
Global search across all entities.

**Query Parameters:**
- `q`: Search query
- `type`: Entity type filter (customer, license, device)
- `limit`: Maximum results (default: 20)

**Response:**
```json
{
  "results": [
    {
      "type": "customer",
      "id": 123,
      "title": "ACME Corp",
      "subtitle": "admin@acme.com",
      "url": "/customer/edit/123"
    },
    {
      "type": "license",
      "id": 456,
      "title": "XXXX-XXXX-XXXX-XXXX",
      "subtitle": "ACME Corp - Active",
      "url": "/license/edit/456"
    }
  ],
  "total": 15
}
```

### Lead Management API

#### GET /leads/api/institutions
Get all institutions with pagination.

**Query Parameters:**
- `page`: Page number (default: 1)
- `per_page`: Items per page (default: 20)
- `search`: Search query

**Response:**
```json
{
  "institutions": [
    {
      "id": 1,
      "name": "Tech University",
      "contact_count": 5,
      "created_at": "2025-06-19T10:00:00Z"
    }
  ],
  "total": 100,
  "page": 1,
  "per_page": 20
}
```

#### POST /leads/api/institutions
Create a new institution.

**Request:**
```json
{
  "name": "New University"
}
```

**Response:**
```json
{
  "id": 101,
  "name": "New University",
  "created_at": "2025-06-19T15:00:00Z"
}
```

#### GET /leads/api/contacts/{contact_id}
Get contact details.

**Response:**
```json
{
  "id": 1,
  "first_name": "John",
  "last_name": "Doe",
  "position": "IT Manager",
  "institution_id": 1,
  "details": [
    {
      "id": 1,
      "type": "email",
      "value": "john.doe@example.com",
      "label": "Work"
    },
    {
      "id": 2,
      "type": "phone",
      "value": "+49 123 456789",
      "label": "Mobile"
    }
  ],
  "notes": [
    {
      "id": 1,
      "content": "Initial contact",
      "version": 1,
      "created_at": "2025-06-19T10:00:00Z",
      "created_by": "admin"
    }
  ]
}
```

#### POST /leads/api/contacts/{contact_id}/details
Add contact detail (phone/email).

**Request:**
```json
{
  "type": "email",
  "value": "secondary@example.com",
  "label": "Secondary"
}
```

**Response:**
```json
{
  "id": 3,
  "type": "email",
  "value": "secondary@example.com",
  "label": "Secondary"
}
```

### Resource Management API

#### POST /api/resources/allocate
Allocate resources to a license.

**Request:**
```json
{
  "license_id": 123,
  "resource_type": "domain",
  "resource_ids": [45, 46, 47]
}
```

**Response:**
```json
{
  "success": true,
  "allocated": 3,
  "message": "3 resources allocated successfully"
}
```


## Lead Management API

### GET /leads/api/stats
Get lead statistics.

**Response:**
```json
{
  "total_institutions": 150,
  "total_contacts": 450,
  "recent_activities": 25,
  "conversion_rate": 12.5,
  "by_type": {
    "university": 50,
    "company": 75,
    "government": 25
  }
}
```

### Lead Routes (HTML Pages)
- `GET /leads/` - Lead overview page
- `GET /leads/create` - Create lead form
- `POST /leads/create` - Save new lead
- `GET /leads/edit/{lead_id}` - Edit lead form
- `POST /leads/update/{lead_id}` - Update lead
- `POST /leads/delete/{lead_id}` - Delete lead
- `GET /leads/export` - Export leads
- `POST /leads/import` - Import leads

## Common Response Codes

- `200 OK`: Successful request
- `201 Created`: Resource created
- `400 Bad Request`: Invalid request data
- `401 Unauthorized`: Missing or invalid authentication
- `403 Forbidden`: Insufficient permissions
- `404 Not Found`: Resource not found
- `409 Conflict`: Resource conflict (e.g., duplicate)
- `429 Too Many Requests`: Rate limit exceeded
- `500 Internal Server Error`: Server error

## Rate Limiting
- API endpoints: 100 requests/minute
- Login attempts: 5 per minute
- Configurable via Admin Panel

## Error Response Format
All errors return JSON with `error`, `code`, and `status` fields.

## Client Integration

Example request with required headers:
```bash
curl -X POST https://api-software-undso.intelsight.de/api/license/activate \
  -H "X-API-Key: AF-2025-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "license_key": "XXXX-XXXX-XXXX-XXXX",
    "hardware_hash": "unique-hardware-id",
    "machine_name": "DESKTOP-123",
    "app_version": "1.0.0"
  }'
```

## Testing

### Test Credentials
- Admin Users:
  - Username: `rac00n` / Password: `1248163264`
  - Username: `w@rh@mm3r` / Password: `Warhammer123!`
- API Key: Generated in Admin Panel under "Lizenzserver Administration"

### Getting the Initial API Key
If you need to retrieve the API key directly from the database:
```bash
docker exec -it v2_postgres psql -U postgres -d v2_db -c "SELECT api_key FROM system_api_key WHERE id = 1;"
```

### Test Endpoints
- Admin Panel: `https://admin-panel-undso.intelsight.de/`
- License Server API: `https://api-software-undso.intelsight.de/`