Charter Boats API
Bookings

Book a Boat

Reserve a boat and create a booking with payment

Booking is a two-step process:

  1. Reserve -- check availability and get confirmed pricing
  2. Create and Pay -- create the booking record and Stripe PaymentIntent

Both steps require session authentication.


Step 1: Reserve

POST/bookings/reserve

Validates the boat, checks availability (including live checks against external booking systems), resolves pricing from seasonal rates, and returns the confirmed price. Does not create a booking or hold dates.

Request Body

FieldTypeRequiredDescription
boat_idstringYesID of the boat to book
start_datestringYesStart date (YYYY-MM-DD)
end_datestringYesEnd date (YYYY-MM-DD)
guest_countintegerNoNumber of guests (validated against boat capacity)

Request

curl -X POST https://charter.boats/api/bookings/reserve \
  -H "Content-Type: application/json" \
  -H "Cookie: <session-cookie>" \
  -d '{
    "boat_id": "550e8400-e29b-41d4-a716-446655440000",
    "start_date": "2026-07-12",
    "end_date": "2026-07-19",
    "guest_count": 6
  }'

Response

{
  "available": true,
  "confirmedPrice": 4200,
  "nights": 7,
  "priceUpdated": false
}

Response Fields

FieldTypeDescription
availablebooleanAlways true (errors thrown if unavailable)
confirmedPricenumberFinal charter price for the date range
nightsintegerNumber of nights
priceUpdatedbooleantrue if the live price differs from stored seasonal pricing

Errors

StatusMessage
400Missing required fields: boat_id, start_date, end_date
400This boat is not available for booking
400Maximum capacity is N guests
400Check-in is only available on Saturday
400Minimum charter duration is N days
400You cannot book your own company's boat
401Authentication required
404Boat not found
409These dates are no longer available
502Could not verify availability. Please try again.

Step 2: Create and Pay

POST/bookings/create-and-pay

Creates the booking record, holds dates on external booking systems, resolves fees, and creates a Stripe PaymentIntent. The client uses the returned clientSecret to complete payment via Stripe Elements.

After payment succeeds on the client, call POST /bookings/{id}/confirm to finalize.

Request Body

FieldTypeRequiredDescription
boat_idstringYesID of the boat to book
start_datestringYesStart date (YYYY-MM-DD)
end_datestringYesEnd date (YYYY-MM-DD)
guest_countintegerNoNumber of guests
guest_first_namestringNoGuest first name (defaults to auth user's name)
guest_last_namestringNoGuest last name (defaults to auth user's name)
guest_emailstringNoGuest email (defaults to auth user's email)
guest_phonestringNoGuest phone number
selected_optional_fee_idsstring[]NoIDs of optional fees the guest selected
coupon_codestringNoCoupon code to apply

Request

curl -X POST https://charter.boats/api/bookings/create-and-pay \
  -H "Content-Type: application/json" \
  -H "Cookie: <session-cookie>" \
  -d '{
    "boat_id": "550e8400-e29b-41d4-a716-446655440000",
    "start_date": "2026-07-12",
    "end_date": "2026-07-19",
    "guest_count": 6,
    "guest_first_name": "Jane",
    "guest_last_name": "Doe",
    "guest_email": "jane@example.com",
    "guest_phone": "+385911234567"
  }'

Response

{
  "bookingId": "booking-uuid",
  "clientSecret": "pi_xxx_secret_xxx",
  "paymentIntentId": "pi_xxx",
  "confirmedPrice": 4200,
  "confirmedCurrency": "EUR",
  "totalPrice": 4445,
  "holdExpiresAt": "2026-06-01T11:15:00.000Z",
  "priceChanged": false,
  "fees": {
    "charter": 4200,
    "requiredFees": [
      {
        "id": "fee-uuid",
        "description": "Final cleaning",
        "amount": 150,
        "period": "per_booking",
        "computed": 150
      }
    ],
    "optionalFees": [],
    "serviceFee": 45,
    "couponDiscount": 0,
    "couponCode": null
  }
}

Response Fields

FieldTypeDescription
bookingIdstringCreated booking ID (UUID)
clientSecretstringStripe PaymentIntent client secret for completing payment
paymentIntentIdstringStripe PaymentIntent ID
confirmedPricenumberCharter base price
confirmedCurrencystringCurrency code (EUR or USD)
totalPricenumberTotal amount charged (charter + required fees + optional fees + service fee - coupon)
holdExpiresAtstringWhen the date hold expires (15 minutes for direct/Nausys boats)
priceChangedbooleantrue if the live price differs from the earlier reserve check
previousPricenumberPrevious charter price (only present when priceChanged is true)
previousTotalnumberPrevious total (only present when priceChanged is true)
feesobjectDetailed fee breakdown
fees.charternumberBase charter price
fees.requiredFeesarrayMandatory fees (cleaning, transit, etc.)
fees.optionalFeesarrayGuest-selected optional fees
fees.serviceFeenumberFlat platform service fee ($45)
fees.couponDiscountnumberDiscount amount from coupon
fees.couponCodestringApplied coupon code, or null

Booking Status After Creation

Boat TypeInitial StatusReason
External (Nausys/MMK)acceptedDates are held as an option on the external system
Direct (instant book)acceptedMoves to confirmed after payment
Direct (standard)pendingRequires owner approval

Errors

StatusMessage
400Missing required fields: boat_id, start_date, end_date
400This boat is not available for booking
400Maximum capacity is N guests
400Check-in is only available on Saturday
400Minimum charter duration is N days
400You cannot book your own company's boat
400These dates are no longer available
401Authentication required
404Boat not found
500Failed to create booking
502Could not reserve dates. Please try again.
502Payment setup failed. Please try again.

On this page