Documenti

Alex Reservations - External Bookings API

REST API for creating reservations from external platforms such as TheFork, OpenTable, or any integration tool like Zapier.

Base URL: https://your-domain.com/wp-json/alexr/v1


Authentication

All requests must include a valid API key. Two methods are supported:

X-API-Key: your-api-key-here

Option 2: Authorization Bearer header

Authorization: Bearer your-api-key-here

API keys are 64-character hex strings tied to a specific restaurant. They can be revoked individually by setting them as inactive.

Authentication errors

HTTP Code Error Code Description
401 rest_missing_api_key No API key provided in the request headers
401 rest_invalid_api_key The API key does not exist or has been deactivated

Endpoints

Create Booking

POST /wp-json/alexr/v1/bookings

Creates a new reservation in Alex Reservations.

Request

Content-Type: application/json

Parameters

Field Type Required Default Description
first_name string Yes - Guest first name
last_name string No "" Guest last name
email string Yes - Guest email address
phone string No "" Guest phone number (e.g. "+34612345678")
date string Yes - Reservation date in YYYY-MM-DD format
time string Yes - Reservation time in HH:MM format (24h)
party integer Yes - Number of guests (must be >= 1)
restaurant_id integer No API key's restaurant Restaurant ID. If omitted, uses the restaurant associated with the API key
service_id integer No Auto-resolved Shift or Event ID. If omitted, the system automatically finds the active service for the given date and time
platform string No API key's platform or "API" Source platform name (e.g. "TheFork", "OpenTable"). Stored in the booking's source field
status string No "booked" Booking status. Allowed values: "pending", "booked"
notes string No null Guest notes or special requests
send_notifications boolean No false Whether to send confirmation email/SMS to the guest

Example request

curl -X POST https://your-domain.com/wp-json/alexr/v1/bookings \
  -H "Content-Type: application/json" \
  -H "X-API-Key: a1b2c3d4e5f6..." \
  -d '{
    "first_name": "John",
    "last_name": "Doe",
    "email": "john.doe@example.com",
    "phone": "+34612345678",
    "date": "2025-04-15",
    "time": "20:30",
    "party": 4,
    "platform": "TheFork",
    "notes": "Window table if possible",
    "status": "booked",
    "send_notifications": false
  }'

Successful response

HTTP 201 Created

{
  "success": true,
  "booking_id": 456,
  "uuid": "bo_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "booked"
}

Duplicate response

HTTP 200 OK - Returned when a booking with the same data already exists (see Idempotency / Duplicate Detection)

{
  "success": true,
  "booking_id": 456,
  "uuid": "bo_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "booked",
  "duplicate": true
}

The response contains the original booking data plus a "duplicate": true flag. No new booking is created.

Error responses

HTTP 400 Bad Request - Validation errors

{
  "success": false,
  "error": "Validation failed",
  "details": {
    "email": "email is required",
    "party": "party is required and must be >= 1"
  }
}

HTTP 400 Bad Request - Invalid time format

{
  "success": false,
  "error": "Invalid time format. Use HH:MM (e.g. 20:30)"
}

HTTP 400 Bad Request - Invalid status

{
  "success": false,
  "error": "Invalid status. Allowed values: pending, booked"
}

HTTP 401 Unauthorized - Missing or invalid API key

{
  "code": "rest_missing_api_key",
  "message": "API key is required. Send it via X-API-Key header or Authorization: Bearer <key>.",
  "data": { "status": 401 }
}

HTTP 404 Not Found - Restaurant not found

{
  "success": false,
  "error": "Restaurant not found"
}

How it works

Service auto-resolution

When service_id is not provided, the API automatically finds the active shift or event for the given date and time:

  1. Searches all active shifts for the restaurant
  2. Checks if the shift operates on the booking's day of the week
  3. Checks day-specific seating hours first, then falls back to the shift's default hours
  4. If no shift matches, searches active events
  5. The first matching service is used

If no service is found, the booking is still created but without a linked service.

Duration calculation

The booking duration is automatically calculated from the matched service configuration:

  • Fixed duration mode: Uses the service's configured duration_time (in seconds)
  • Per-covers mode: Duration depends on the party size, using the service's duration_covers mapping
  • Fallback: 5400 seconds (1.5 hours) if no service is found

Customer management

  • If a customer with the same email already exists for the restaurant, the booking is linked to that customer
  • If no customer exists, a new customer record is created automatically

Platform tracking

The platform value is stored in the booking's source field. This allows filtering bookings by origin in the dashboard:

  • source = "TheFork" - Booking came from TheFork
  • source = "OpenTable" - Booking came from OpenTable
  • source = "API" - Generic API booking (default when no platform is specified)
  • source = NULL - Booking created from the widget or dashboard

Notifications

By default, no email or SMS notifications are sent when creating a booking via API. This avoids duplicating notifications that the external platform (TheFork, OpenTable) already sends.

Set send_notifications: true if you want Alex Reservations to send its own notifications to the guest. When enabled, the following notifications are sent:

  • Email: Booking confirmation email
  • SMS: SMS notification
  • WhatsApp: WhatsApp notification (if configured)
  • Dashboard notification: The restaurant receives a BookingOnlineReceived notification

Idempotency / Duplicate Detection

The API includes built-in protection against duplicate bookings. When a request is received, the system generates a unique idempotency key based on the combination of:

  • restaurant_id
  • email (case-insensitive)
  • date
  • time
  • party

If a previous successful booking (HTTP 201) already exists with the same idempotency key, the API returns the original booking data with an additional "duplicate": true flag and an HTTP 200 status code. No new booking is created.

This is useful for scenarios where:

  • Zapier retries: If a webhook delivery fails and Zapier retries the same request, the booking won't be duplicated
  • Network issues: If the client doesn't receive the response and resends the request
  • Platform sync: If an external platform sends the same reservation twice

How it works

  1. A SHA-256 hash is generated from restaurant_id|email|date|time|party
  2. The hash is checked against previous successful API logs
  3. If a match is found, the original response is returned with "duplicate": true
  4. If no match is found, the booking is created normally
  5. The idempotency key is stored in the api_logs table for future checks

Important notes

  • The idempotency check only considers successful bookings (HTTP 201). Failed requests do not block future attempts
  • Two bookings for the same person, date, time, and party size at the same restaurant are considered duplicates
  • If you need to create a second booking for the same person at the same time (e.g., different party size), change the party value
  • The duplicate detection is logged as a separate action (create_booking_duplicate) in the API logs

API Logging

Every API request is logged in the api_logs table with:

  • Restaurant ID
  • API key used
  • Action performed (create_booking or create_booking_duplicate)
  • HTTP status code
  • Full request body (sensitive data excluded)
  • Full response body
  • Client IP address
  • Idempotency key (SHA-256 hash for duplicate detection)
  • Timestamp

Setting up API keys

API keys can be managed from the Alex Reservations dashboard:

  1. Go to Settings > Integrations > API Keys
  2. Click Generate New API Key
  3. Enter a name (e.g. "TheFork production key") and platform (e.g. "TheFork")
  4. The key is generated automatically and shown once. Copy it and store it securely
  5. You can toggle keys active/inactive, edit their name/platform, or delete them

Access to the API Keys settings page is controlled by the API Keys permission in the Roles section. By default, only the Super Manager role has this permission enabled.

Manual setup via SQL

API keys are stored in the api_keys database table. You can also insert them manually:

INSERT INTO {prefix}_api_keys
  (uuid, restaurant_id, api_key, platform, name, is_active, date_created, date_modified)
VALUES
  ('ak_unique_id', 1, 'your-64-char-hex-key', 'TheFork', 'TheFork via Zapier', 1, NOW(), NOW());
Column Description
restaurant_id The restaurant this key grants access to
api_key 64-character hex string. Auto-generated from the dashboard, or generate manually with bin2hex(random_bytes(32)) in PHP
platform Default platform name for bookings made with this key (e.g. "TheFork")
name Human-readable description (e.g. "TheFork production key")
is_active Set to 0 to revoke the key

You can create multiple keys per restaurant, each with a different platform.


Zapier integration example

When integrating with TheFork via Zapier:

  1. Trigger: New reservation in TheFork (via Zapier's TheFork integration)
  2. Action: Webhooks by Zapier > POST request
  3. Configuration:
    • URL: https://your-domain.com/wp-json/alexr/v1/bookings
    • Payload Type: JSON
    • Headers: X-API-Key: your-api-key-here
    • Body mapping:
Zapier field API field
First Name first_name
Last Name last_name
Email email
Phone phone
Date date (make sure format is YYYY-MM-DD)
Time time (make sure format is HH:MM, 24h)
Party Size party
Notes notes
(static value) platform = "TheFork"

Response codes summary

HTTP Code Meaning
200 Duplicate booking detected. Returns original booking data with "duplicate": true. No new booking created
201 Booking created successfully
400 Validation error (missing fields, invalid format, invalid status)
401 Authentication error (missing or invalid API key)
404 Restaurant not found