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

# Error Handling

> Learn about HTTP status codes and error responses in the BookingShake API

## Overview

The BookingShake API uses standard HTTP status codes to indicate the success or failure of requests. Error responses include a JSON object with a descriptive `message` field to help you understand what went wrong.

## HTTP Status Codes

| Status Code | Meaning               | Description                                        |
| ----------- | --------------------- | -------------------------------------------------- |
| `200`       | Success               | Request completed successfully                     |
| `400`       | Bad Request           | Invalid request parameters or authentication error |
| `403`       | Forbidden             | Access denied to the requested resource            |
| `429`       | Too Many Requests     | Rate limit exceeded                                |
| `500`       | Internal Server Error | Something went wrong on our end                    |

## Error Response Format

All errors follow a consistent JSON structure:

```json theme={null}
{
  "message": "error description here"
}
```

## Common Errors

### Authentication Errors

<AccordionGroup>
  <Accordion title="missing token">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The `Authorization` header is missing from the request.

    **Solution:** Include the Bearer token in the Authorization header:

    ```http theme={null}
    Authorization: Bearer YOUR_API_KEY
    ```

    **Example:**

    ```bash theme={null}
    curl -X GET 'https://api.bookingshake.io/api/sources' \
      -H 'Authorization: Bearer YOUR_API_KEY'
    ```
  </Accordion>

  <Accordion title="invalid token">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The API key provided is incorrect, expired, or revoked.

    **Solution:**

    * Verify you copied the complete API key without extra spaces
    * Ensure you're using the correct API key from Settings > Integrations
    * Generate a new API key if needed

    **Troubleshooting:**

    1. Log in to BookingShake dashboard
    2. Go to Settings > Integrations
    3. Copy the API key again
    4. Try the request with the fresh key
  </Accordion>
</AccordionGroup>

### Request Body Errors

<AccordionGroup>
  <Accordion title="body is empty">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The request body is empty or not included in a POST request.

    **Solution:** Include a valid JSON body with your POST request:

    ```bash theme={null}
    curl -X POST 'https://api.bookingshake.io/api/events/create' \
      -H 'Authorization: Bearer YOUR_API_KEY' \
      -H 'Content-Type: application/json' \
      -d '{
        "bookings": [...],
        "contact": {...}
      }'
    ```
  </Accordion>

  <Accordion title="invalid body">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The request body is not valid JSON or cannot be parsed.

    **Solution:**

    * Ensure your JSON is properly formatted
    * Check for missing commas, quotes, or brackets
    * Validate your JSON using a JSON validator

    **Common Issues:**

    ```json theme={null}
    // ❌ Invalid - missing comma
    {
      "bookings": []
      "contact": {}
    }

    // ✅ Valid
    {
      "bookings": [],
      "contact": {}
    }
    ```
  </Accordion>
</AccordionGroup>

### Missing Required Fields

<AccordionGroup>
  <Accordion title="missing bookings">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The `bookings` array is missing from the request body.

    **Solution:** Include at least one booking in the `bookings` array:

    ```json theme={null}
    {
      "bookings": [
        {
          "date": "15-03-2025",
          "start_time": "14:00",
          "pax": "50"
        }
      ],
      "contact": {...}
    }
    ```
  </Accordion>

  <Accordion title="too many bookings - maximum 20 per request">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The `bookings` array contains more than 20 entries.

    **Solution:** Split your bookings into multiple requests of 20 or fewer. If you need to create more bookings, send them in successive calls (mind the `/events/create` rate limit of 10 requests/minute).
  </Accordion>

  <Accordion title="missing contact">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The `contact` object is missing from the request body.

    **Solution:** Include contact information with required fields:

    ```json theme={null}
    {
      "bookings": [...],
      "contact": {
        "first_name": "John",
        "last_name": "Doe",
        "email": "john.doe@example.com"
      }
    }
    ```
  </Accordion>

  <Accordion title="missing pax">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The `pax` (number of attendees) field is missing from a booking.

    **Solution:** Include the `pax` field in each booking:

    ```json theme={null}
    {
      "date": "15-03-2025",
      "start_time": "14:00",
      "pax": "50"
    }
    ```
  </Accordion>
</AccordionGroup>

### Format Validation Errors

<AccordionGroup>
  <Accordion title="date format must be DD-MM-YYYY">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The date is not in the correct DD-MM-YYYY format.

    **Solution:** Use the DD-MM-YYYY format:

    **Examples:**

    * ✅ Correct: `"15-03-2025"`, `"01-12-2024"`, `"31-01-2025"`
    * ❌ Incorrect: `"2025-03-15"`, `"03/15/2025"`, `"15.03.2025"`

    ```json theme={null}
    {
      "date": "15-03-2025"
    }
    ```
  </Accordion>

  <Accordion title="start_time format must be HH:mm">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The time is not in the correct HH:mm format (24-hour).

    **Solution:** Use the HH:mm format with 24-hour time:

    **Examples:**

    * ✅ Correct: `"14:00"`, `"09:30"`, `"23:45"`
    * ❌ Incorrect: `"2:00 PM"`, `"14:00:00"`, `"14h00"`

    ```json theme={null}
    {
      "start_time": "14:00",
      "end_time": "18:00"
    }
    ```
  </Accordion>

  <Accordion title="end_time format must be HH:mm">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The end time is not in the correct HH:mm format.

    **Solution:** Same as `start_time` - use HH:mm format (24-hour).
  </Accordion>
</AccordionGroup>

### Authorization Errors

<AccordionGroup>
  <Accordion title="Forbidden - client access denied">
    **HTTP Status:** `403 Forbidden`

    **Cause:** You're trying to access or use a `contact_id` that doesn't belong to your venue or venue group.

    **Solution:**

    * Ensure the `contact_id` belongs to your venue
    * Use the correct venue API key
    * Create a new contact instead of referencing an existing one

    **Example:**

    ```json theme={null}
    {
      "message": "This client does not belong to your venue"
    }
    ```

    <Tip>
      If you need to link to an existing contact, make sure the contact was created under your venue or is part of your venue group.
    </Tip>
  </Accordion>
</AccordionGroup>

### Rate Limiting Errors

<AccordionGroup>
  <Accordion title="Rate limit exceeded">
    **HTTP Status:** `429 Too Many Requests`

    **Cause:** You've exceeded the rate limit for the endpoint (e.g., 10 requests/minute for `/events/create` or 60 requests/minute for GET endpoints).

    **Response Headers:**

    ```http theme={null}
    X-RateLimit-Limit: 10
    X-RateLimit-Remaining: 0
    X-RateLimit-Reset: 1700234567
    Retry-After: 45
    ```

    **Response Body:**

    ```json theme={null}
    {
      "message": "Rate limit exceeded",
      "data": {
        "limit": 10,
        "window": "60 seconds",
        "remaining": 0,
        "resetAt": "2025-11-17T14:30:00.000Z",
        "retryAfter": 45
      }
    }
    ```

    **Solution:**

    1. Wait for the duration specified in the `Retry-After` header (in seconds)
    2. Implement exponential backoff for retries
    3. Monitor `X-RateLimit-Remaining` header to avoid hitting limits
    4. Cache GET endpoint responses (sources, spaces, status, fields)
    5. Batch multiple bookings in a single `/events/create` request

    **See also:** [Rate Limiting Guide](/api-reference/rate-limiting) for detailed information and code examples.
  </Accordion>
</AccordionGroup>

### Resource Validation Errors

<AccordionGroup>
  <Accordion title="invalid space">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The `space_id` provided does not exist or is not valid for your venue.

    **Solution:**

    1. Retrieve available spaces first:

    ```bash theme={null}
    curl -X GET 'https://api.bookingshake.io/api/spaces' \
      -H 'Authorization: Bearer YOUR_API_KEY'
    ```

    2. Use a valid `space_id` from the response:

    ```json theme={null}
    {
      "space_id": "space_conf_a"
    }
    ```

    3. Or omit the `space_id` to use the default space.
  </Accordion>

  <Accordion title="invalid source">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The `source_slug` or `source_id` provided does not exist.

    **Solution:**

    1. Retrieve available sources:

    ```bash theme={null}
    curl -X GET 'https://api.bookingshake.io/api/sources' \
      -H 'Authorization: Bearer YOUR_API_KEY'
    ```

    2. Use a valid source identifier from the response.
  </Accordion>
</AccordionGroup>

### Product Validation Errors

When including products to create draft quotations, these validation errors may occur:

<AccordionGroup>
  <Accordion title="missing products title">
    **HTTP Status:** `400 Bad Request`

    **Cause:** A product in the `products` array is missing the required `title` field.

    **Solution:** Ensure every product has a `title`:

    ```json theme={null}
    {
      "products": [
        {
          "title": "Conference Room Package",
          "quantity": 1,
          "price_without_tax": 50000,
          "vat": 2000
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="missing products quantity">
    **HTTP Status:** `400 Bad Request`

    **Cause:** A product is missing the `quantity` field.

    **Solution:** Include a positive integer quantity for each product:

    ```json theme={null}
    {
      "quantity": 2
    }
    ```
  </Accordion>

  <Accordion title="missing products price_without_tax">
    **HTTP Status:** `400 Bad Request`

    **Cause:** A product is missing the `price_without_tax` field.

    **Solution:** Include the price in **cents/centimes** (not euros/dollars):

    ```json theme={null}
    {
      "price_without_tax": 15000  // €150.00 = 15000 cents
    }
    ```

    <Warning>
      **Important:** Prices must be in **cents**, not euros/dollars.

      * €100.00 = `10000` cents
      * €35.50 = `3550` cents
    </Warning>
  </Accordion>

  <Accordion title="missing products vat">
    **HTTP Status:** `400 Bad Request`

    **Cause:** A product is missing the `vat` (VAT rate) field.

    **Solution:** Include the VAT rate in **basis points** (not percentage):

    ```json theme={null}
    {
      "vat": 2000  // 20% VAT = 2000 basis points
    }
    ```

    <Warning>
      **Important:** VAT must be in **basis points** (1/100th of a percent), not percentages.

      * 20% = `2000` basis points
      * 10% = `1000` basis points
      * 5.5% = `550` basis points
      * Valid range: `0` to `10000` (0% to 100%)
    </Warning>
  </Accordion>

  <Accordion title="Invalid VAT rate">
    **HTTP Status:** `400 Bad Request`

    **Cause:** The VAT value is outside the valid range (0-10000 basis points).

    **Solution:** Ensure VAT is between 0 and 10000:

    ```json theme={null}
    {
      "vat": 2000  // ✅ Valid: 20%
    }
    ```

    **Common mistakes:**

    * Using `20` instead of `2000` for 20% VAT ❌
    * Using negative values ❌
    * Using values over 10000 ❌
  </Accordion>
</AccordionGroup>

### Server Errors

<Accordion title="Internal server error">
  **HTTP Status:** `500 Internal Server Error`

  **Cause:** An unexpected error occurred on the server.

  **What to do:**

  1. Wait a moment and retry your request
  2. If the error persists, contact support at [support@bookingshake.com](mailto:support@bookingshake.com)
  3. Include the following information:
     * Timestamp of the request
     * Request method and endpoint
     * Request body (sanitize any sensitive data)
     * Any correlation ID if provided in the response
</Accordion>

## Error Handling Best Practices

### 1. Always Check Status Codes

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await fetch('https://api.bookingshake.io/api/events/create', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    const error = await response.json();
    console.error(`Error ${response.status}:`, error.message);
    throw new Error(error.message);
  }

  const result = await response.json();
  console.log('Success:', result);
  ```

  ```python Python theme={null}
  response = requests.post(
      'https://api.bookingshake.io/api/events/create',
      headers=headers,
      json=payload
  )

  if response.status_code != 200:
      error = response.json()
      print(f"Error {response.status_code}: {error['message']}")
      raise Exception(error['message'])

  result = response.json()
  print('Success:', result)
  ```

  ```php PHP theme={null}
  $response = curl_exec($ch);
  $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

  if ($statusCode !== 200) {
      $error = json_decode($response, true);
      throw new Exception("Error {$statusCode}: " . $error['message']);
  }

  $result = json_decode($response, true);
  ```
</CodeGroup>

### 2. Validate Input Before Sending

Validate data client-side before making API requests to catch errors early:

```javascript theme={null}
function validateBookingData(booking) {
  // Validate date format (DD-MM-YYYY)
  const dateRegex = /^\d{2}-\d{2}-\d{4}$/;
  if (!dateRegex.test(booking.date)) {
    throw new Error('Invalid date format. Use DD-MM-YYYY');
  }

  // Validate time format (HH:mm)
  const timeRegex = /^\d{2}:\d{2}$/;
  if (!timeRegex.test(booking.start_time)) {
    throw new Error('Invalid time format. Use HH:mm');
  }

  // Validate required fields
  if (!booking.pax) {
    throw new Error('Number of attendees (pax) is required');
  }

  return true;
}
```

### 3. Implement Retry Logic

For 500 errors, implement exponential backoff retry logic:

```javascript theme={null}
async function apiRequestWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.ok) {
        return await response.json();
      }

      // Don't retry on 400/403 errors (client errors)
      if (response.status === 400 || response.status === 403) {
        const error = await response.json();
        throw new Error(error.message);
      }

      // Handle rate limiting with Retry-After header
      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get('Retry-After')) || 60;
        console.warn(`Rate limited. Waiting ${retryAfter} seconds...`);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }

      // Retry on 500 errors
      if (response.status === 500 && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      throw new Error(`HTTP ${response.status}`);
    } catch (error) {
      if (attempt === maxRetries) throw error;
    }
  }
}
```

### 4. Log Errors for Debugging

Always log errors with sufficient context:

```javascript theme={null}
try {
  const result = await createEvent(bookingData);
  console.log('Event created successfully:', result);
} catch (error) {
  console.error('Failed to create event:', {
    error: error.message,
    timestamp: new Date().toISOString(),
    payload: bookingData,
    endpoint: '/events/create'
  });

  // Handle error appropriately (show user message, retry, etc.)
}
```

## Need More Help?

<CardGroup cols={2}>
  <Card title="Quickstart Guide" icon="rocket" href="/api-reference/quickstart">
    Review the quickstart guide for working examples
  </Card>

  <Card title="Contact Support" icon="life-ring" href="mailto:support@bookingshake.com">
    Get help from our support team
  </Card>
</CardGroup>
