# b0esche.cloud API Reference

Base URL: `https://go.b0esche.cloud`

## Authentication

All authenticated endpoints require a JWT token in the Authorization header:
```
Authorization: Bearer <token>
```

---

## Health Check

### GET /health
Check if the API is running.

**Response:**
```json
{
  "status": "ok",
  "timestamp": "2026-01-13T19:00:00Z"
}
```

---

## Authentication Endpoints

### Passkey Registration

#### POST /auth/passkey/register/start
Start passkey registration for a new user.

**Request Body:**
```json
{
  "username": "johndoe"
}
```

**Response:**
```json
{
  "publicKey": {
    "challenge": "base64-encoded-challenge",
    "rp": {
      "name": "b0esche.cloud",
      "id": "www.b0esche.cloud"
    },
    "user": {
      "id": "base64-user-id",
      "name": "johndoe",
      "displayName": "johndoe"
    },
    "pubKeyCredParams": [...],
    "timeout": 300000,
    "attestation": "none"
  }
}
```

#### POST /auth/passkey/register/verify
Complete passkey registration.

**Request Body:**
```json
{
  "username": "johndoe",
  "credential": {
    "id": "credential-id",
    "rawId": "base64-raw-id",
    "type": "public-key",
    "response": {
      "clientDataJSON": "base64-client-data",
      "attestationObject": "base64-attestation"
    }
  }
}
```

**Response:**
```json
{
  "user": {
    "id": "uuid",
    "username": "johndoe"
  },
  "token": "jwt-token"
}
```

### Passkey Login

#### POST /auth/passkey/login/start
Start passkey authentication.

**Request Body:**
```json
{
  "username": "johndoe"
}
```

**Response:**
```json
{
  "publicKey": {
    "challenge": "base64-challenge",
    "timeout": 300000,
    "rpId": "www.b0esche.cloud",
    "allowCredentials": [...]
  }
}
```

#### POST /auth/passkey/login/verify
Complete passkey authentication.

**Request Body:**
```json
{
  "username": "johndoe",
  "credential": {
    "id": "credential-id",
    "rawId": "base64-raw-id",
    "type": "public-key",
    "response": {
      "clientDataJSON": "base64-client-data",
      "authenticatorData": "base64-auth-data",
      "signature": "base64-signature"
    }
  }
}
```

**Response:**
```json
{
  "user": {
    "id": "uuid",
    "username": "johndoe",
    "role": "user"
  },
  "token": "jwt-token"
}
```

### Device Management

#### GET /auth/passkey/devices
List user's registered passkeys.

**Response:**
```json
{
  "devices": [
    {
      "id": "uuid",
      "credentialId": "credential-id",
      "deviceLabel": "MacBook Pro",
      "createdAt": "2026-01-01T00:00:00Z",
      "lastUsedAt": "2026-01-13T19:00:00Z",
      "backupEligible": true
    }
  ]
}
```

#### POST /auth/passkey/devices/add
Add a new passkey to existing account.

#### DELETE /auth/passkey/devices/{passkeyId}
Remove a passkey from account.

### Recovery Codes

#### POST /auth/recovery/codes/generate
Generate new recovery codes (invalidates old ones).

**Response:**
```json
{
  "codes": [
    "XXXX-XXXX-XXXX",
    "YYYY-YYYY-YYYY",
    ...
  ],
  "expiresAt": "2027-01-13T00:00:00Z"
}
```

#### POST /auth/recovery/codes/use
Use a recovery code to authenticate.

**Request Body:**
```json
{
  "username": "johndoe",
  "code": "XXXX-XXXX-XXXX"
}
```

### Password (Optional Fallback)

#### POST /auth/password/add
Add password to account.

**Request Body:**
```json
{
  "password": "secure-password"
}
```

#### DELETE /auth/password/remove
Remove password from account.

---

## User Endpoints

### GET /api/me
Get current user profile.

**Response:**
```json
{
  "id": "uuid",
  "username": "johndoe",
  "email": "john@example.com",
  "displayName": "John Doe",
  "role": "user",
  "createdAt": "2026-01-01T00:00:00Z"
}
```

### PATCH /api/me
Update user profile.

**Request Body:**
```json
{
  "displayName": "John D.",
  "email": "newemail@example.com"
}
```

---

## Organization Endpoints

### GET /api/organizations
List user's organizations.

**Response:**
```json
{
  "organizations": [
    {
      "id": "uuid",
      "name": "My Team",
      "slug": "my-team",
      "role": "owner",
      "memberCount": 5,
      "createdAt": "2026-01-01T00:00:00Z"
    }
  ]
}
```

### POST /api/organizations
Create a new organization.

**Request Body:**
```json
{
  "name": "My New Team",
  "slug": "my-new-team"
}
```

### GET /api/organizations/{orgId}
Get organization details.

### PATCH /api/organizations/{orgId}
Update organization.

### DELETE /api/organizations/{orgId}
Delete organization (owner only).

### GET /api/organizations/{orgId}/members
List organization members.

**Response:**
```json
{
  "members": [
    {
      "id": "uuid",
      "userId": "user-uuid",
      "username": "johndoe",
      "displayName": "John Doe",
      "role": "owner",
      "joinedAt": "2026-01-01T00:00:00Z"
    }
  ]
}
```

### POST /api/organizations/{orgId}/members
Add member to organization.

**Request Body:**
```json
{
  "userId": "user-uuid",
  "role": "member"
}
```

### PATCH /api/organizations/{orgId}/members/{memberId}
Update member role.

### DELETE /api/organizations/{orgId}/members/{memberId}
Remove member from organization.

---

## File Endpoints

### GET /api/files
List files in a directory.

**Query Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `path` | string | Directory path (default: `/`) |
| `orgId` | string | Organization ID (optional) |

**Response:**
```json
{
  "files": [
    {
      "id": "uuid",
      "name": "document.pdf",
      "path": "/documents/document.pdf",
      "type": "file",
      "mimeType": "application/pdf",
      "size": 1048576,
      "createdAt": "2026-01-01T00:00:00Z",
      "modifiedAt": "2026-01-13T19:00:00Z"
    },
    {
      "id": "uuid",
      "name": "photos",
      "path": "/photos",
      "type": "folder",
      "createdAt": "2026-01-01T00:00:00Z"
    }
  ]
}
```

### POST /api/files/upload
Upload a file.

**Request:** `multipart/form-data`
| Field | Type | Description |
|-------|------|-------------|
| `file` | file | The file to upload |
| `path` | string | Destination path |
| `orgId` | string | Organization ID (optional) |

**Response:**
```json
{
  "file": {
    "id": "uuid",
    "name": "uploaded-file.pdf",
    "path": "/documents/uploaded-file.pdf",
    "size": 1048576
  }
}
```

### GET /api/files/download
Download a file.

**Query Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `path` | string | File path |
| `orgId` | string | Organization ID (optional) |

**Response:** File binary with appropriate Content-Type header.

### POST /api/files/folder
Create a folder.

**Request Body:**
```json
{
  "path": "/new-folder",
  "orgId": "org-uuid"
}
```

### DELETE /api/files
Delete a file or folder.

**Query Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `path` | string | Path to delete |
| `orgId` | string | Organization ID (optional) |

### POST /api/files/move
Move/rename a file or folder.

**Request Body:**
```json
{
  "sourcePath": "/old-name.pdf",
  "destinationPath": "/new-name.pdf",
  "orgId": "org-uuid"
}
```

### POST /api/files/copy
Copy a file or folder.

**Request Body:**
```json
{
  "sourcePath": "/original.pdf",
  "destinationPath": "/copy.pdf",
  "orgId": "org-uuid"
}
```

---

## Admin Endpoints

*Requires admin or superadmin role.*

### GET /api/admin/users
List all users.

**Query Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `page` | int | Page number (default: 1) |
| `limit` | int | Items per page (default: 50) |
| `search` | string | Search by username/email |

### GET /api/admin/users/{userId}
Get user details.

### PATCH /api/admin/users/{userId}
Update user (role, status).

### DELETE /api/admin/users/{userId}
Delete user account.

### Admin Invitations

#### GET /auth/admin/invitations
List admin invitations.

#### POST /auth/admin/invitations
Create admin invitation.

**Request Body:**
```json
{
  "username": "newadmin",
  "roleId": "admin-role-uuid",
  "expiresIn": 86400
}
```

**Response:**
```json
{
  "invitation": {
    "id": "uuid",
    "token": "invite-token",
    "expiresAt": "2026-01-14T19:00:00Z"
  }
}
```

#### POST /auth/admin/invitations/{token}/accept
Accept an admin invitation.

#### DELETE /auth/admin/invitations/{token}
Revoke an invitation.

---

## Activity Endpoints

### GET /api/activities
Get activity log.

**Query Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `page` | int | Page number |
| `limit` | int | Items per page |
| `orgId` | string | Filter by organization |
| `userId` | string | Filter by user |
| `action` | string | Filter by action type |

**Response:**
```json
{
  "activities": [
    {
      "id": "uuid",
      "userId": "user-uuid",
      "username": "johndoe",
      "action": "file.upload",
      "resourceType": "file",
      "resourceId": "/documents/report.pdf",
      "metadata": {
        "size": 1048576
      },
      "createdAt": "2026-01-13T19:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 150
  }
}
```

---

## Error Responses

All errors follow this format:

```json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {}
  }
}
```

### Common Error Codes

| Code | HTTP Status | Description |
|------|-------------|-------------|
| `UNAUTHORIZED` | 401 | Missing or invalid token |
| `FORBIDDEN` | 403 | Insufficient permissions |
| `NOT_FOUND` | 404 | Resource not found |
| `VALIDATION_ERROR` | 400 | Invalid request data |
| `CONFLICT` | 409 | Resource already exists |
| `INTERNAL_ERROR` | 500 | Server error |

---

## Rate Limiting

- **Authentication endpoints**: 10 requests/minute
- **API endpoints**: 100 requests/minute
- **File uploads**: 50 requests/hour

Rate limit headers:
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1705172400
```

---

## Webhooks (Future)

Planned webhook events:
- `user.created`
- `user.deleted`
- `file.uploaded`
- `file.deleted`
- `org.member.added`
- `org.member.removed`
