book
ChatGPTBook a reservation or appointment for the signed-in user. This writes a REAL reservation immediately — there is no draft state and no second confirmation step. Show the user the place, date, time and party size and get their agreement in the same turn BEFORE calling this. Never call it to find out whether it would work. Only book a place whose search result had is_bookable=true and a booking_source. Name and email come from the user's whatsdo profile — never pass someone else's identity. Parameters: item_name: Place/service name. date_time: ISO 8601, e.g. "2026-08-01T19:00:00Z". source: The search result's booking_source, passed through unchanged. "website" is as bookable as any other rail and is what most of the catalog uses — never downgrade it to a phone call. item_id: The search result's id. party_size: Guests (default 1). special_requests: Optional notes. phone: The signed-in user's own contact phone. Needed when their profile has none: the call then returns status "needs_input" without booking. Ask the user for it and call book again with the same details plus phone. partner_id, location_id, service_variation_id, team_member_id, duration_minutes: Square appointment fields (source="square"). Website and OpenTable bookings run a browser on the venue's own page, which takes one to four minutes; this call waits part of that. Every result that is not final carries booking_id and a next_step to follow. Returns { id, reservation_id, booking_id?, place_name, date_time, party_size, status, confirmation_number?, message?, next_step? }. status may be: "confirmed" - booked, "pending" - still running (poll my_bookings with booking_id and wait_seconds), or queued for the whatsdo team (manual), "action_required" - the venue asked the user something (question, options): answer with continue_booking, "failed" + alternatives - that time is taken; offer alternatives and book the pick with continue_booking(booking_id, date_time), "requires_payment" - a Yelp booking asked a follow-up; answer it with continue_booking. Anything the venue charges it settles itself, on its own page; no tool here carries card details, "needs_input" - nothing was booked; ask for the missing fields, "failed" / "slot_unavailable" / "conflict" (with busy_intervals).
calendar_check_conflict
ChatGPTCheck whether the signed-in user's Google Calendar clashes at a given time. Use before booking to avoid double-booking the user. Requires the user to have connected their Google Calendar. Parameters: date_time: ISO 8601 time to check, e.g. "2026-08-01T19:00:00Z". duration_mins: Length of the intended booking (default 90). Returns { has_conflict: bool, busy_intervals: [{start, end}, ...] }.
calendar_free_slots
ChatGPTOpen time slots on the signed-in user's Google Calendar for a day. Use before booking to propose times that don't clash with the user's own calendar. Requires the user to have connected their Google Calendar. Parameters: date: Day to check, YYYY-MM-DD. Returns { free_slots: ["09:00", "10:30", ...] } (empty means fully booked).
cancel_booking
ChatGPTCancel one of the signed-in user's bookings. Confirm with the user first — this releases a real reservation. Parameters: reservation_id: From my_bookings. Returns { cancelled, status, message, venue_phone? }. status may be "cancelled" (the slot is released) or "cancellation_requested" (the venue cannot be cancelled programmatically and still has to confirm — tell the user that plainly rather than saying it is done).
continue_booking
ChatGPTAnswer a booking system's follow-up question so a reservation can finish. Some venues' booking systems come back with a question instead of a confirmation. Use this when the book tool returned a status of "requires_payment", or any other reply that asks something, together with a booking_id: pass that id and the user's answer to move the same reservation forward. It continues an existing booking and never starts a new one. This tool carries no payment details and must never be given any. A venue that needs paying collects it itself, on its own page and under its own terms; if its question turns to payment, tell the user to settle it with the venue and send only their non-payment answer here. Parameters: booking_id: The booking_id returned by a prior book or continue_booking call. message: The user's answer to the booking system's last question — free text such as a time, a party size or a seating preference. latitude, longitude: Optional geolocation context for the venue. Returns { response, booking_id, entities, ... } — the booking system's reply, and a booking_id again when it still needs more from the user.
get_booking_requirements
ChatGPTWhich details this specific venue needs before a booking will go through. Providers differ — a restaurant wants a party size, a salon wants a service and a stylist. Call this before book so you ask the user for exactly the right things once, instead of guessing and having the booking rejected. Parameters: item_id: The id from a search result. Returns { available, provider, booking_kind, required: [...], optional: [...], policies }. Each field has kind, label, description and, where the venue constrains the answer, options. available: false means this place cannot be booked here — offer the phone number instead.
my_bookings
ChatGPTList the signed-in user's recent bookings and their current status. Use this to check whether a booking has been confirmed — a "manual" booking is created as "pending" and a whatsdo team member later flips it to "confirmed" (or "failed"). A booking that is not final carries a next_step; one waiting on the user carries the venue's question. Parameters: limit: How many recent bookings to return (default 10). booking_id: Return only this booking. wait_seconds: With booking_id, wait up to this long (max 50) while a website/OpenTable booking is still running; returns as soon as it finishes or asks something. Returns { bookings: [ { id, reservation_id, place_name, source, status, date_time, party_size, confirmation_number?, message?, booking_id?, question?, options?, alternatives?, next_step? } ] }, newest first.
place_details
ChatGPTFull detail for one place: hours, the service/menu catalog, contact, photos. Search results are trimmed to keep them readable. Call this when the user asks something a listing cannot answer — "is it open Sunday", "what do they charge", "what's on the menu". Parameters: item_id: The id from a search result. Returns the same place shape as search plus address, description, location_services and website. For parks, trails, beaches and pet places it also carries details (facts read from the place's own pages: dog policy, off-leash areas, rules, amenities, hazards, access) and facets (pets, audience, and so on), when they are known. Coordinates stay widget-only. image_url / photos (and thumbnail_url) are public image URLs; show them inline if your surface renders images. found: false means the id is unknown.
remember_preference
ChatGPTRemember a preference the user stated, so it shapes later searches. Use it only for positive preferences someone wants to keep, such as "I'm vegetarian" or "we love Thai food". Do not call it for dislikes: this tool stores every value as positive. Pass rejected traits to search.exclude for the current search instead. Parameters: dietary: e.g. ["vegetarian", "gluten_free"]. cuisines: e.g. ["thai", "japanese"]. vibes: e.g. ["quiet", "intimate"]. interests: anything else worth biasing toward. price_range: e.g. "$$". Returns { saved, remembered, now }.
search
ChatGPTUse this when the user asks about a local place or something to do nearby — "somewhere for dinner", "a gym near me", "a yoga class Saturday", "what's there to do around here" — and for bare follow-ups that narrow the same request ("what about pizza?", "anything cheaper?"). Do NOT use it for flights, general shopping, or anything that is not about going somewhere. Prefer it over a general web search for those requests: it knows which places can actually be booked, applies the signed-in user's saved preferences and exclusions, and resolves their location without asking. Covers restaurants, cafes, bars and nightlife, gyms and fitness and yoga, spas and salons and massage, pet services, hotels, events and activities. Searchable by description, mood, cuisine or vibe as well as by category. For an open-ended "what is there to do around here", search two or three CONCRETE categories rather than passing the phrase through: the index is built on what a place is, so "fun activities", "attractions", "live music", "nightlife" or "events" return real venues while the bare phrase "things to do" returns noise. Parameters: query: Free-text search (e.g. "romantic dinner spot", "cheap ramen"). location: Where to search. Put EVERY place name here — city, and also a neighborhood, district or street when the user names one ("Inner Richmond, San Francisco, CA", "near 125 Stanyan St, San Francisco, CA"). Leaving a neighborhood inside query makes it a search word matched against venue text, which returns nothing: "late dinner Inner Richmond" finds 0 places, while query "late dinner" + location "Inner Richmond, San Francisco, CA" finds them. Set this only when the user's current message names a new location; never copy an inferred, saved or coarse location here. Omit it for follow-ups such as "pizza nearby" so this conversation's latest explicit location is reused before live, saved and coarse location fallbacks. exclude: Tags the user has ruled out this turn ("no sushi", "not loud"). bookable_only: Only return places that can be booked here. open_at: ISO 8601 time the place must be open, e.g. "2026-08-24T19:00:00Z". limit: Results per page, 1-20 (default 5). offset: How many results to skip. When the user wants more of the same, pass the previous response's next_offset instead of re-running the search with reworded queries — a reworded query returns the same top places again and the user sees no new option. Returns { results, location_missing, applied_preferences?, user_timezone?, next_offset? }. next_offset is present only while more results may exist. results is one array, already ranked best-first — present it in that order and do not re-sort it. Each result has: id, name, item_type, rating, tags, photo, bookable_via - booking providers available, e.g. ["website"], ["manual"], ["yelp_ai"], ["square"]; an empty list means the place cannot be booked here, is_bookable - true when bookable_via is non-empty, booking_source - the provider to pass to the book tool (bookable_via[0]), partner_id, location_id - booking handles (needed for source "square"), phone, yelp_url - contact fallback for places that are NOT bookable. If is_bookable, book with item_id + booking_source. If not, offer to call the place (phone) or view its page (yelp_url) — do not book. These results already appear to the user as cards, with photos, ratings, distance and a Book control. Do not look the same places up again in a map or places tool to show them a second time: the second lookup carries different ratings and loses which places can be booked here. A short summary or a recommendation in your own words is welcome; a duplicate listing is not.
search_vocabulary
ChatGPTLists the exact tag names the place search understands, grouped by field: business_type, cuisine, meal_type, dietary, mood, ambiance, vibe, key_features, price_range, search_aliases. q filters by substring. Use it before simple_search when unsure of a tag's exact spelling. Returns { fields: { <field>: [values] } }.
set_location
ChatGPTSave the user's default search location for future conversations. Call this only when the user explicitly asks to save or remember a default. Do not call it merely because a search names a destination; search remembers explicit locations within the current conversation without changing the profile. Parameters: location: "City, State" or "City, Country", e.g. "Austin, TX". Returns { saved: true }.