Booking flow

Build a booking session, confirm its saved terms with the customer, then book that revision. Quotes and arrival windows do not reserve availability.

The examples below are tool arguments, not complete MCP requests. IDs, customer details, and payment tokens are illustrative. Use returned IDs and a fresh UUID for each new booking attempt.

1. Start a session

Call create_booking_session with one to seven stops in visit order:

{
  "stops": [
    {"address": "2000 Union St, San Francisco, CA 94123"},
    {
      "address": "3101 24th St, San Francisco, CA 94110",
      "address2": "Apt 4B",
      "floor": "4",
      "elevator": true
    }
  ],
  "addons": []
}

The response contains session.id, revision, quotes, and missing. Present the returned quotes and let the customer select an option. Each quote includes its price breakdown and eligible add-ons. Selected add-ons are already included in its price.

One stop means work at a single location, so its quotes are labor-only help (one_lugger or two_luggers, no truck). Two or more stops quote vehicles. Approximate locations can be used to browse quotes, but scheduling and booking require precise street addresses. Correct the session's stops before continuing.

create_estimates is an alternative starting point. It returns a separate session and checkout url for each option. Share the selected estimate's url so the customer can book on Lugg, or continue its session_id using the same flow below.

2. Select the option and services

Call update_booking_session with a quote's estimate_id as quote_id, plus the revision you just read:

{
  "session_id": "SESSION_ID",
  "expected_revision": 0,
  "quote_id": "ESTIMATE_ID_FROM_SESSION_QUOTES"
}

Use the actual returned revision rather than assuming it is zero. Every response returns the current revision; use it for the next update or booking call. A stale revision returns session_changed.

To change optional services, send addons with the complete selection of returned add-on slugs. An empty array removes all selections. Changing stops or add-ons re-prices the selected option. If that option no longer supports the choices, for example a vehicle when the stops drop to one, the session drops its quote and lists quote as missing. Select another option from the returned quotes. A vehicle left with one stop also lists dropoff: add a stop to keep it, or select a labor option.

After selection, update responses omit the other options from the quotes array. Call get_booking_session to compare or switch options again.

3. Find an arrival window

Call get_availability:

{
  "session_id": "SESSION_ID"
}

Without a date, the response covers today through six days later, within the booking horizon. It includes today's available on-demand options and up to three scheduled windows per day. When has_more is true, call again with that day's date in YYYY-MM-DD format to see all scheduled windows. Dates use the returned service-region timezone.

The default arrival_window_ref is origin: arrival at the first stop. Use destination to request arrival windows for the last stop. Neither represents the time the whole job will finish. Save the chosen window's ID unchanged.

On-demand windows have a relative arrival label. The saved session represents them with null start and end times; do not turn an earlier quote timestamp into an arrival promise.

4. Save the customer and booking details

Call update_booking_session with the current revision:

{
  "session_id": "SESSION_ID",
  "expected_revision": 1,
  "arrival_window_id": "WINDOW_ID_FROM_GET_AVAILABILITY",
  "customer": {
    "name": "Jamie Example",
    "phone_number": "+14155550123",
    "email": "jamie@example.com"
  },
  "description": "One couch",
  "instructions": "Use the building's loading entrance.",
  "tip_cents": 2000
}

The customer needs a name and supported mobile phone number. Email is optional. A tip is additional to the service quote; it must be zero or an integer of at least 100 cents.

Omitted fields keep their saved values. Customer fields merge individually. Send null only to deliberately clear a nullable field. Resolve every item in session.missing before payment. get_booking_session retrieves the current session when resuming.

5. Obtain payment approval

Review the saved route, service, add-ons, arrival window, price, and tip with the customer. Obtain authorization to book those terms. A session revision identifies the terms; it does not record customer consent.

When the session is ready and eligible for payment, session.payment.handlers supplies the supported payment configuration:

Field Use
type The supported handler, currently stripe_shared_payment_token
config.network_business_profile Pass to Stripe as seller_details.network_business_profile when obtaining the token
requirements.currency Currency the token must cover
requirements.requested_amount_cents Exact requested amount, including the saved tip
requirements.confirmation_required_at The time through which the token must remain valid for payment authorization; not a capture deadline

Obtain the token through your host's supported payment capability. Lugg consumes an issued shared payment token; it does not issue one. Do not ask the customer to provide card details or paste a token into chat.

Use the returned requirements rather than calculating a payment amount yourself. Quote totals include applicable fees and discounts; account credits are not assumed. Fixed prices include labor. Variable quotes estimate the work. Do not add selected add-on prices twice.

If the host cannot obtain the supported payment type, offer browser checkout only through a url Lugg returned: an estimate's url once the customer picks it, or the session url once missing is empty. An empty handler list does not mean payment is unnecessary: check missing details, attempt status, and the booking result.

6. Create the booking

Call create_booking with the revision the customer confirmed:

{
  "session_id": "SESSION_ID",
  "expected_revision": 2,
  "payment": {
    "type": "stripe_shared_payment_token",
    "shared_payment_token": "TOKEN_FROM_PAYMENT_CAPABILITY"
  },
  "idempotency_key": "7a874b42-7f04-4fb3-8e8d-83fd993be09d"
}

Use a new UUID for a new attempt. Preserve the key and every argument for an identical transport retry. Do not send customer, route, price, or window overrides; the saved session determines the booking.

A quote older than a day is priced again at booking. If its price changed, quote_changed stops the booking and saves the new price in the session. Read the session and obtain customer approval for the new terms before proceeding.

Report success only from the booking result and its current state. Give the customer the confirmation number and returned booking details. A completed session means booking creation succeeded, not that the move is complete or that payment has been captured. Scheduled bookings may defer authorization.

Errors and retries

After a booking error or lost response, call get_booking_session before starting another payment. A timeout is not proof of failure.

session.attempt_status Next action
null Resolve missing details and use current requirements. For a lost response, preserve the original arguments and key for an identical retry.
active Booking is in progress. Inspect the same session again. Do not edit it, start another payment, or create a replacement session to bypass it.
unknown Stop payment attempts and contact support. Time passing does not make a replacement attempt safe.
failed Correct the definite failure, refresh requirements, and use a new UUID for the next attempt.
succeeded Return the existing booking and its current state. A replay does not create another booking, including after cancellation.

Do not infer success solely from a populated session.booking; unresolved or failed attempts may also have an attached booking. An interrupted active attempt that remains unresolved needs support.

For session_changed, read the latest session and confirm any changed customer-facing terms. For a stale or unavailable window, fetch availability and update the same session when its attempt state permits it. For insufficient or expired token approval, obtain a token meeting the current requirements after a definite failure. Do not reuse a token already bound to a failed booking.

Session creation itself is not idempotent. Do not blindly retry it or create new sessions to bypass unresolved attempts. See the published skill://book-with-lugg/references/recovery.md resource for detailed error guidance.

Cancel a booking

After the customer explicitly requests cancellation, call cancel_booking with the exact confirmation number and a matching booking-customer phone number or email:

{
  "confirmation_number": "ABC123",
  "email": "jamie@example.com"
}

A stop contact is not sufficient. An already-cancelled booking returns success with already_cancelled: true without repeating cancellation. Fulfilled and completed bookings cannot be cancelled through this tool; other bookings remain subject to eligibility. Report the returned outcome, and do not promise refund amounts or timing not supplied by Lugg.