> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Ishaq74/concordia/llms.txt
> Use this file to discover all available pages before exploring further.

# Public Bookings API

> Public endpoint for creating service bookings

# Public Bookings API

The Public Bookings API allows authenticated users to create bookings for active services. Unlike the admin bookings API, this is the customer-facing endpoint.

## Authentication

Requires valid user session (any authenticated user can create bookings).

```typescript theme={null}
Authorization: Bearer <session-token>
```

## Create booking

Create a new booking for a service.

**Endpoint:** `POST /api/services/bookings`

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://your-domain.com/api/services/bookings \
    -H "Authorization: Bearer <session-token>" \
    -H "Content-Type: application/json" \
    -d '{
      "serviceId": "service-uuid",
      "bookingDate": "2024-12-15",
      "bookingTime": "14:00",
      "customerMessage": "Looking forward to this service!"
    }'
  ```

  ```typescript SDK theme={null}
  const response = await fetch('/api/services/bookings', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${sessionToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      serviceId: 'service-uuid',
      bookingDate: '2024-12-15',
      bookingTime: '14:00',
      customerMessage: 'Looking forward to this service!'
    })
  });
  const booking = await response.json();
  ```
</CodeGroup>

**Request Body:**

<ParamField body="serviceId" type="string" required>
  UUID of the service to book
</ParamField>

<ParamField body="bookingDate" type="string" required>
  Date in `YYYY-MM-DD` format
</ParamField>

<ParamField body="bookingTime" type="string" required>
  Time in `HH:MM` format (24-hour)
</ParamField>

<ParamField body="customerMessage" type="text">
  Optional message from customer to provider
</ParamField>

## Validation & business logic

The endpoint performs comprehensive validation:

### 1. Service validation

* Service must exist
* Service status must be `"active"`
* Provider (owner) must exist

### 2. Availability check

* Converts `bookingDate` to day of week (0-6)
* Queries `servicesAvailability` table for matching slots
* Verifies `bookingTime` falls within an available slot
* Checks `isAvailable = true` for the slot

### 3. Conflict detection

* Queries existing bookings for the same service, date, and time
* Rejects if another booking exists (no double-booking)

### 4. Automatic calculations

* **Total price:** Uses service's `basePrice`
* **Currency:** Uses service's `currency`
* **Duration:** Uses service's `durationMinutes`
* **Booking end time:** Calculated as `bookingTime + durationMinutes`

## Response

<ResponseField name="id" type="string">
  Booking UUID
</ResponseField>

<ResponseField name="serviceId" type="string">
  Service UUID
</ResponseField>

<ResponseField name="providerId" type="string">
  Provider (service owner) user ID
</ResponseField>

<ResponseField name="customerId" type="string">
  Customer (current user) ID
</ResponseField>

<ResponseField name="bookingDate" type="string">
  Booking date (YYYY-MM-DD)
</ResponseField>

<ResponseField name="bookingTime" type="string">
  Start time (HH:MM)
</ResponseField>

<ResponseField name="bookingEndTime" type="string">
  Calculated end time (HH:MM)
</ResponseField>

<ResponseField name="durationMinutes" type="number">
  Service duration
</ResponseField>

<ResponseField name="totalPrice" type="number">
  Price in minor currency units (e.g., cents)
</ResponseField>

<ResponseField name="currency" type="string">
  Currency code (e.g., "EUR")
</ResponseField>

<ResponseField name="status" type="string">
  Always `"pending"` for new bookings
</ResponseField>

<ResponseField name="customerMessage" type="text">
  Customer's message (if provided)
</ResponseField>

<ResponseField name="createdAt" type="timestamp">
  Booking creation timestamp
</ResponseField>

**Example response:**

```json theme={null}
{
  "id": "booking-uuid",
  "serviceId": "service-uuid",
  "providerId": "provider-user-id",
  "customerId": "customer-user-id",
  "bookingDate": "2024-12-15",
  "bookingTime": "14:00",
  "bookingEndTime": "15:30",
  "durationMinutes": 90,
  "totalPrice": 5000,
  "currency": "EUR",
  "status": "pending",
  "customerMessage": "Looking forward to this service!",
  "createdAt": "2024-12-01T10:30:00Z"
}
```

## Error responses

### Authentication required

```json theme={null}
{
  "error": "Authentification requise"
}
```

**Status:** 401

### Invalid JSON

```json theme={null}
{
  "error": "JSON invalide"
}
```

**Status:** 400

### Missing required fields

```json theme={null}
{
  "error": "serviceId, bookingDate et bookingTime sont requis"
}
```

**Status:** 400

### Service not found

```json theme={null}
{
  "error": "Service introuvable"
}
```

**Status:** 404

### Service not active

```json theme={null}
{
  "error": "Ce service n'est pas disponible"
}
```

**Status:** 400

### Time slot not available

```json theme={null}
{
  "error": "Aucun créneau disponible pour ce jour et cette heure"
}
```

**Status:** 400

### Booking conflict

```json theme={null}
{
  "error": "Ce créneau est déjà réservé"
}
```

**Status:** 409

## Booking workflow

1. **Customer submits booking** → Status: `pending`
2. **Provider reviews** (via admin API)
3. **Provider confirms** → Status: `confirmed`
4. **Service delivered** → Status: `completed`

Alternative flows:

* Provider can `cancel` or `reject` bookings
* Customer no-show → Status: `no_show`

<Info>
  The booking status can only be changed by the provider through the admin API (`/api/admin/services/bookings`). Customers cannot cancel or modify bookings through this endpoint.
</Info>

## Day of week calculation

The availability system uses JavaScript's `Date.getDay()`:

* **0** = Sunday
* **1** = Monday
* **2** = Tuesday
* **3** = Wednesday
* **4** = Thursday
* **5** = Friday
* **6** = Saturday

Example: `2024-12-15` (Sunday) → `dayOfWeek = 0`

## Time slot matching

A booking time is valid if:

```typescript theme={null}
bookingTime >= slot.startTime && bookingTime <= slot.endTime
```

Example:

* Slot: `09:00` - `17:00`
* Booking time `14:00` → **Valid** ✓
* Booking time `18:00` → **Invalid** ✗

## Implementation reference

Source: `/src/pages/api/services/bookings.ts`

Key implementation details:

* Session extraction from `locals.session` or `locals.user`
* Drizzle ORM queries for validation
* Date/time calculations using JavaScript Date
* Conflict detection with `eq()` and `and()` operators
* Automatic field population from service data

<Warning>
  **Timezone Note:** The current implementation does not handle timezone conversions. All times are treated as local to the application server. Consider adding timezone support for multi-region deployments.
</Warning>

## See also

* [Bookings Feature Guide](/features/bookings)
* [Services API (Admin)](/development/api/services#bookings)
* [Availability Management](/development/api/services#availability)
* [Database Schema](/development/database/schema#services-bookings)
