> For the complete documentation index, see [llms.txt](https://docs.beeoclock.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.beeoclock.com/services/service-management/api.md).

# API Documentation

## Overview

The Service Management API provides comprehensive service lifecycle management for the Bee O'clock platform. Services represent bookable offerings provided by businesses, including their configuration, pricing, scheduling, and presentation details.

## Base URL

```
{api_base_url}/api/v1/service
```

## Authentication

All endpoints require Bearer token authentication and business tenant identification.

**Headers Required:**

```http
Authorization: Bearer <access_token>
x-business-tenant-id: <tenant_id>
Content-Type: application/json
```

## Endpoints

### 1. Get Paged Services

Retrieve a paginated list of services with optional search functionality.

**Endpoint:** `GET /paged`

**Query Parameters:**

| Parameter | Type     | Required | Default | Description                                                 |
| --------- | -------- | -------- | ------- | ----------------------------------------------------------- |
| `page`    | `number` | No       | `1`     | Page number for pagination                                  |
| `size`    | `number` | No       | `10`    | Number of items per page                                    |
| `phrase`  | `string` | No       | -       | Search phrase for filtering by service title or description |

**Example Request:**

```http
GET /api/v1/service/paged?page=1&size=10&phrase=haircut
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
x-business-tenant-id: 12345
```

**Response Schema:**

```typescript
interface PaginatedServicesResponse {
  items: ServiceDto[];
  totalSize : number;
}
```

**Example Response:**

```json
{
  "items": [
    {
      "_id": "64a7b8f123456789abcdef01",
      "object": "ServiceDto",
      "languageVersions": [
        {
          "language": "en",
          "title": "Haircut and Styling",
          "description": "Professional haircut and styling service"
        }
      ],
      "durationVersions": [
        {
          "durationInSeconds": 3600,
          "breakInSeconds": 300,
          "prices": [
            {
              "price": 50.00,
              "currency": "USD"
            }
          ]
        }
      ],
      "presentation": {
        "color": "#FF5733",
        "media": []
      },
      "configuration": {
        "duration": {
          "durationVersionType": "RANGE"
        }
      },
      "prepaymentPolicy": {
        "isRequired": false
      },
      "schedules": [],
      "order": 1,
      "createdAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-01-15T10:30:00Z"
    }
  ],
  "totalSize": 1
}
```

### 2. Get Service by ID

Retrieve detailed information about a specific service.

**Endpoint:** `GET /{id}`

**Path Parameters:**

| Parameter | Type     | Required | Description               |
| --------- | -------- | -------- | ------------------------- |
| `id`      | `string` | Yes      | Unique service identifier |

**Example Request:**

```http
GET /api/v1/service/64a7b8f123456789abcdef01
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
x-business-tenant-id: 12345
```

**Response Schema:** `ServiceDto`

**Example Response:**

```json
{
  "_id": "64a7b8f123456789abcdef01",
  "object": "ServiceDto",
  "languageVersions": [
    {
      "language": "en",
      "title": "Haircut and Styling",
      "description": "Professional haircut and styling service with consultation"
    },
    {
      "language": "es",
      "title": "Corte y Peinado",
      "description": "Servicio profesional de corte y peinado con consulta"
    }
  ],
  "durationVersions": [
    {
      "durationInSeconds": 3600,
      "breakInSeconds": 300,
      "prices": [
        {
          "price": 50.00,
          "currency": "USD",
          "preferredLanguages": ["en"]
        },
        {
          "price": 45.00,
          "currency": "EUR",
          "preferredLanguages": ["es"]
        }
      ]
    }
  ],
  "presentation": {
    "color": "#FF5733",
    "media": [
      {
        "_id": "64a7b8f123456789abcdef02",
        "url": "https://storage.example.com/service-images/haircut.jpg",
        "mimeType": "image/jpeg"
      }
    ]
  },
  "configuration": {
    "duration": {
      "durationVersionType": "RANGE"
    }
  },
  "prepaymentPolicy": {
    "isRequired": true,
    "isPercentage": true,
    "value": "25",
    "minimalCancelTime": "86400"
  },
  "schedules": [
    {
      "weekDays": [1, 2, 3, 4, 5],
      "startTime": "09:00",
      "endTime": "17:00"
    }
  ],
  "order": 1,
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-20T14:45:00Z"
}
```

### 3. Create Service

Create a new service with complete configuration.

**Endpoint:** `POST /`

**Request Schema:** `ServiceDto`

**Example Request:**

```http
POST /api/v1/service
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
x-business-tenant-id: 12345
Content-Type: application/json

{
  "languageVersions": [
    {
      "language": "en",
      "title": "Deep Tissue Massage",
      "description": "Therapeutic deep tissue massage for muscle relief"
    }
  ],
  "durationVersions": [
    {
      "durationInSeconds": 5400,
      "breakInSeconds": 600,
      "prices": [
        {
          "price": 80.00,
          "currency": "USD"
        }
      ]
    }
  ],
  "presentation": {
    "color": "#4A90E2"
  },
  "configuration": {
    "duration": {
      "durationVersionType": "FIXED"
    }
  },
  "prepaymentPolicy": {
    "isRequired": false
  },
  "schedules": [
    {
      "weekDays": [1, 2, 3, 4, 5, 6],
      "startTime": "08:00",
      "endTime": "20:00"
    }
  ],
  "order": 2
}
```

**Response Schema:** `ServiceDto` (created service with generated ID)

**Example Response:**

```json
{
  "_id": "64a7b8f123456789abcdef03",
  "object": "ServiceDto",
  "languageVersions": [
    {
      "language": "en",
      "title": "Deep Tissue Massage",
      "description": "Therapeutic deep tissue massage for muscle relief"
    }
  ],
  "durationVersions": [
    {
      "durationInSeconds": 5400,
      "breakInSeconds": 600,
      "prices": [
        {
          "price": 80.00,
          "currency": "USD"
        }
      ]
    }
  ],
  "presentation": {
    "color": "#4A90E2",
    "media": []
  },
  "configuration": {
    "duration": {
      "durationVersionType": "FIXED"
    }
  },
  "prepaymentPolicy": {
    "isRequired": false
  },
  "schedules": [
    {
      "weekDays": [1, 2, 3, 4, 5, 6],
      "startTime": "08:00",
      "endTime": "20:00"
    }
  ],
  "order": 2,
  "createdAt": "2024-01-25T09:15:00Z",
  "updatedAt": "2024-01-25T09:15:00Z"
}
```

### 4. Update Service

Update an existing service's information.

**Endpoint:** `PUT /{id}`

**Path Parameters:**

| Parameter | Type     | Required | Description               |
| --------- | -------- | -------- | ------------------------- |
| `id`      | `string` | Yes      | Unique service identifier |

**Request Schema:** `ServiceDto`

**Example Request:**

```http
PUT /api/v1/service/64a7b8f123456789abcdef01
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
x-business-tenant-id: 12345
Content-Type: application/json

{
  "_id": "64a7b8f123456789abcdef01",
  "languageVersions": [
    {
      "language": "en",
      "title": "Premium Haircut and Styling",
      "description": "Premium haircut and styling service with luxury consultation"
    }
  ],
  "durationVersions": [
    {
      "durationInSeconds": 4200,
      "breakInSeconds": 300,
      "prices": [
        {
          "price": 65.00,
          "currency": "USD"
        }
      ]
    }
  ],
  "prepaymentPolicy": {
    "isRequired": true,
    "isPercentage": true,
    "value": "30",
    "minimalCancelTime": "172800"
  },
  "order": 1
}
```

**Response Schema:** `ServiceDto` (updated service)

### 5. Update Service Required Resources

Update the list of resources required for a service.

**Endpoint:** `PUT /{id}/required-resources`

**Path Parameters:**

| Parameter | Type     | Required | Description               |
| --------- | -------- | -------- | ------------------------- |
| `id`      | `string` | Yes      | Unique service identifier |

**Request Schema:** `RequiredResourceDto[]`

**Example Request:**

```http
PUT /api/v1/service/64a7b8f123456789abcdef01/required-resources
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
x-business-tenant-id: 12345
Content-Type: application/json

[
  {
    "resourceId": "64a7b8f123456789abcdef04",
    "quantity": 1,
    "isRequired": true
  },
  {
    "resourceId": "64a7b8f123456789abcdef05",
    "quantity": 2,
    "isRequired": false
  }
]
```

**Response:** `204 No Content`

### 6. Delete Service

Soft delete a service (marks as deleted while preserving data).

**Endpoint:** `DELETE /{id}`

**Path Parameters:**

| Parameter | Type     | Required | Description               |
| --------- | -------- | -------- | ------------------------- |
| `id`      | `string` | Yes      | Unique service identifier |

**Example Request:**

```http
DELETE /api/v1/service/64a7b8f123456789abcdef01
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
x-business-tenant-id: 12345
```

**Response Schema:**

```typescript
interface DeleteServiceResponse {
  deletedCount: number;
}
```

**Example Response:**

```json
{
  "deletedCount": 1
}
```

## Service Media Management

### Upload Service Media

**Endpoint:** `POST /{id}/media`

**Path Parameters:**

| Parameter | Type     | Required | Description               |
| --------- | -------- | -------- | ------------------------- |
| `id`      | `string` | Yes      | Unique service identifier |

**Request:** `multipart/form-data`

| Field         | Type     | Required | Description                 |
| ------------- | -------- | -------- | --------------------------- |
| `file`        | `File`   | Yes      | Image file (JPG, PNG, WebP) |
| `description` | `string` | No       | Media description           |

**Example Request:**

```http
POST /api/v1/service/64a7b8f123456789abcdef01/media
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
x-business-tenant-id: 12345
Content-Type: multipart/form-data

--boundary
Content-Disposition: form-data; name="file"; filename="service-image.jpg"
Content-Type: image/jpeg

[binary image data]
--boundary
Content-Disposition: form-data; name="description"

Main service promotional image
--boundary--
```

### Delete Service Media

**Endpoint:** `DELETE /{id}/media/{mediaId}`

**Path Parameters:**

| Parameter | Type     | Required | Description               |
| --------- | -------- | -------- | ------------------------- |
| `id`      | `string` | Yes      | Unique service identifier |
| `mediaId` | `string` | Yes      | Unique media identifier   |

## Data Transfer Objects

### ServiceDto

```typescript
interface ServiceDto {
  _id?: string;
  object?: 'ServiceDto';
  configuration?: ServiceConfigurationDto;
  presentation?: PresentationDto;
  prepaymentPolicy?: PrepaymentPolicyDto;
  languageVersions: LanguageVersionDto[];
  durationVersions?: DurationVersionDto[];
  schedules?: ScheduleDto[];
  order?: number | null;
  createdAt?: string;
  updatedAt?: string;
  entityState?: EntityStateDto[];
}
```

### ServiceConfigurationDto

```typescript
interface ServiceConfigurationDto {
  object?: 'ServiceConfigurationDto';
  duration?: DurationConfigurationDto;
}
```

### DurationConfigurationDto

```typescript
interface DurationConfigurationDto {
  object?: 'DurationConfigurationDto';
  durationVersionType: DurationVersionTypeEnum;
}
```

### PresentationDto

```typescript
interface PresentationDto {
  object?: 'PresentationDto';
  color?: string;
  media?: MediaDto[];
}
```

### PrepaymentPolicyDto

```typescript
interface PrepaymentPolicyDto {
  object?: 'PrepaymentPolicyDto';
  isRequired: boolean;
  isPercentage?: boolean;
  value?: string;
  minimalCancelTime?: string;
}
```

### DurationVersionDto

```typescript
interface DurationVersionDto {
  object?: 'DurationVersionDto';
  breakInSeconds?: number;
  durationInSeconds: number;
  prices?: PriceDto[];
}
```

### PriceDto

```typescript
interface PriceDto {
  object?: 'PriceDto';
  price: number;
  currency?: CurrencyCodeEnum;
  preferredLanguages?: LanguageCodeEnum[];
}
```

## Enums

### DurationVersionTypeEnum

```typescript
enum DurationVersionTypeEnum {
  FIXED = 'FIXED',
  RANGE = 'RANGE'
}
```

### CurrencyCodeEnum

```typescript
enum CurrencyCodeEnum {
  USD = 'USD',
  EUR = 'EUR',
  GBP = 'GBP',
  // ... other currency codes
}
```

### LanguageCodeEnum

```typescript
enum LanguageCodeEnum {
  en = 'en',
  es = 'es',
  fr = 'fr',
  de = 'de',
  // ... other language codes
}
```

## Error Responses

### Common Error Format

```typescript
interface ApiErrorResponse {
  statusCode: number;
  message: string;
  error: string;
  timestamp: string;
  path: string;
}
```

### Error Status Codes

| Status Code | Error Type            | Description                                       |
| ----------- | --------------------- | ------------------------------------------------- |
| `400`       | Bad Request           | Invalid request data or validation errors         |
| `401`       | Unauthorized          | Missing or invalid authentication token           |
| `403`       | Forbidden             | Insufficient permissions for the operation        |
| `404`       | Not Found             | Service not found                                 |
| `409`       | Conflict              | Service title conflict or business rule violation |
| `422`       | Unprocessable Entity  | Invalid service configuration                     |
| `500`       | Internal Server Error | Unexpected server error                           |

### Example Error Responses

**400 Bad Request - Validation Error:**

```json
{
  "statusCode": 400,
  "message": [
    "languageVersions should not be empty",
    "durationVersions[0].durationInSeconds must be a positive number"
  ],
  "error": "Bad Request",
  "timestamp": "2024-01-25T10:15:30Z",
  "path": "/api/v1/service"
}
```

**404 Not Found:**

```json
{
  "statusCode": 404,
  "message": "Service with ID 64a7b8f123456789abcdef01 not found",
  "error": "Not Found",
  "timestamp": "2024-01-25T10:15:30Z",
  "path": "/api/v1/service/64a7b8f123456789abcdef01"
}
```

**403 Forbidden:**

```json
{
  "statusCode": 403,
  "message": "Insufficient permissions to manage services",
  "error": "Forbidden",
  "timestamp": "2024-01-25T10:15:30Z",
  "path": "/api/v1/service"
}
```

## Business Rules

### Service Creation Rules

1. **Language Versions**: At least one language version is required
2. **Duration Versions**: At least one duration version is required
3. **Pricing**: Each duration version must have at least one price
4. **Schedules**: Schedules are optional but if provided must be valid
5. **Order**: Order numbers must be unique within tenant

### Service Update Rules

1. **Immutable Fields**: Service ID cannot be changed
2. **Language Versions**: Cannot remove all language versions
3. **Duration Versions**: Cannot remove all duration versions
4. **Active Orders**: Cannot delete services with active orders
5. **Media**: Media files must be valid image formats

### Validation Rules

1. **Duration**: Duration must be positive integer in seconds
2. **Price**: Price must be positive number
3. **Color**: Must be valid hex color code
4. **Schedule Times**: Start time must be before end time
5. **Prepayment**: Percentage values must be 0-100

## Permission Requirements

All service management operations require appropriate permissions:

* **READ\_SERVICE**: View service information
* **CREATE\_SERVICE**: Create new services
* **EDIT\_SERVICE**: Update existing services
* **DELETE\_SERVICE**: Delete services
* **MANAGE\_SERVICE\_MEDIA**: Upload/delete service media

## Rate Limiting

* **Read Operations**: 100 requests per minute
* **Write Operations**: 30 requests per minute
* **Media Upload**: 10 requests per minute

## Caching

* **Service Lists**: Cached for 5 minutes
* **Individual Services**: Cached for 15 minutes
* **Cache Invalidation**: Automatic on service updates

## Integration Examples

### JavaScript/TypeScript

```typescript
// Create service
const serviceData = {
  languageVersions: [
    {
      language: 'en',
      title: 'Massage Therapy',
      description: 'Relaxing massage therapy session'
    }
  ],
  durationVersions: [
    {
      durationInSeconds: 3600,
      prices: [{ price: 60, currency: 'USD' }]
    }
  ]
};

const response = await fetch('/api/v1/service', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'x-business-tenant-id': tenantId,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(serviceData)
});

const createdService = await response.json();
```

### cURL Examples

```bash
# Get paged services
curl -X GET "https://api.beeoclock.com/api/v1/service/paged?page=1&size=10" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "x-business-tenant-id: YOUR_TENANT_ID"

# Create service
curl -X POST "https://api.beeoclock.com/api/v1/service" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "x-business-tenant-id: YOUR_TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "languageVersions": [
      {
        "language": "en",
        "title": "Haircut",
        "description": "Professional haircut service"
      }
    ],
    "durationVersions": [
      {
        "durationInSeconds": 1800,
        "prices": [{"price": 30, "currency": "USD"}]
      }
    ]
  }'

# Update service
curl -X PUT "https://api.beeoclock.com/api/v1/service/SERVICE_ID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "x-business-tenant-id: YOUR_TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{"order": 2}'

# Delete service
curl -X DELETE "https://api.beeoclock.com/api/v1/service/SERVICE_ID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "x-business-tenant-id: YOUR_TENANT_ID"
```
