Skip to main content

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 CodeMeaningDescription
200SuccessRequest completed successfully
400Bad RequestInvalid request parameters or authentication error
403ForbiddenAccess denied to the requested resource
429Too Many RequestsRate limit exceeded
500Internal Server ErrorSomething went wrong on our end

Error Response Format

All errors follow a consistent JSON structure:
{
  "message": "error description here"
}

Common Errors

Authentication Errors

HTTP Status: 400 Bad RequestCause: The Authorization header is missing from the request.Solution: Include the Bearer token in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Example:
curl -X GET 'https://api.bookingshake.io/api/sources' \
  -H 'Authorization: Bearer YOUR_API_KEY'
HTTP Status: 400 Bad RequestCause: 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

Request Body Errors

HTTP Status: 400 Bad RequestCause: The request body is empty or not included in a POST request.Solution: Include a valid JSON body with your POST request:
curl -X POST 'https://api.bookingshake.io/api/events/create' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "bookings": [...],
    "contact": {...}
  }'
HTTP Status: 400 Bad RequestCause: 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:
// ❌ Invalid - missing comma
{
  "bookings": []
  "contact": {}
}

// ✅ Valid
{
  "bookings": [],
  "contact": {}
}

Missing Required Fields

HTTP Status: 400 Bad RequestCause: The bookings array is missing from the request body.Solution: Include at least one booking in the bookings array:
{
  "bookings": [
    {
      "date": "15-03-2025",
      "startTime": "14:00",
      "pax": "50"
    }
  ],
  "contact": {...}
}
HTTP Status: 400 Bad RequestCause: The contact object is missing from the request body.Solution: Include contact information with required fields:
{
  "bookings": [...],
  "contact": {
    "first_name": "John",
    "last_name": "Doe",
    "email": "[email protected]"
  }
}
HTTP Status: 400 Bad RequestCause: The pax (number of attendees) field is missing from a booking.Solution: Include the pax field in each booking:
{
  "date": "15-03-2025",
  "startTime": "14:00",
  "pax": "50"
}

Format Validation Errors

HTTP Status: 400 Bad RequestCause: 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"
{
  "date": "15-03-2025"
}
HTTP Status: 400 Bad RequestCause: 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"
{
  "startTime": "14:00",
  "endTime": "18:00"
}
HTTP Status: 400 Bad RequestCause: The end time is not in the correct HH:mm format.Solution: Same as startTime - use HH:mm format (24-hour).

Authorization Errors

HTTP Status: 403 ForbiddenCause: 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:
{
  "message": "This client does not belong to your venue"
}
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.

Rate Limiting Errors

HTTP Status: 429 Too Many RequestsCause: 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:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1700234567
Retry-After: 45
Response Body:
{
  "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 for detailed information and code examples.

Resource Validation Errors

HTTP Status: 400 Bad RequestCause: The space_id provided does not exist or is not valid for your venue.Solution:
  1. Retrieve available spaces first:
curl -X GET 'https://api.bookingshake.io/api/spaces' \
  -H 'Authorization: Bearer YOUR_API_KEY'
  1. Use a valid space_id from the response:
{
  "space_id": "space_conf_a"
}
  1. Or omit the space_id to use the default space.
HTTP Status: 400 Bad RequestCause: The source_slug or source_id provided does not exist.Solution:
  1. Retrieve available sources:
curl -X GET 'https://api.bookingshake.io/api/sources' \
  -H 'Authorization: Bearer YOUR_API_KEY'
  1. Use a valid source identifier from the response.

Product Validation Errors

When including products to create draft quotations, these validation errors may occur:
HTTP Status: 400 Bad RequestCause: A product in the products array is missing the required title field.Solution: Ensure every product has a title:
{
  "products": [
    {
      "title": "Conference Room Package",
      "quantity": 1,
      "price_without_tax": 50000,
      "vat": 2000
    }
  ]
}
HTTP Status: 400 Bad RequestCause: A product is missing the quantity field.Solution: Include a positive integer quantity for each product:
{
  "quantity": 2
}
HTTP Status: 400 Bad RequestCause: A product is missing the price_without_tax field.Solution: Include the price in cents/centimes (not euros/dollars):
{
  "price_without_tax": 15000  // €150.00 = 15000 cents
}
Important: Prices must be in cents, not euros/dollars.
  • €100.00 = 10000 cents
  • €35.50 = 3550 cents
HTTP Status: 400 Bad RequestCause: A product is missing the vat (VAT rate) field.Solution: Include the VAT rate in basis points (not percentage):
{
  "vat": 2000  // 20% VAT = 2000 basis points
}
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%)
HTTP Status: 400 Bad RequestCause: The VAT value is outside the valid range (0-10000 basis points).Solution: Ensure VAT is between 0 and 10000:
{
  "vat": 2000  // ✅ Valid: 20%
}
Common mistakes:
  • Using 20 instead of 2000 for 20% VAT ❌
  • Using negative values ❌
  • Using values over 10000 ❌

Server Errors

HTTP Status: 500 Internal Server ErrorCause: 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 [email protected]
  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

Error Handling Best Practices

1. Always Check Status Codes

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);

2. Validate Input Before Sending

Validate data client-side before making API requests to catch errors early:
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.startTime)) {
    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:
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:
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?