{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/api-evangelist/withlocals/main/json-schema/withlocals-booking-schema.json", "title": "Booking", "description": "A partner booking. Returned by create, amend, cancel, and read.\n\nWhen `status=CANCELLED`, `cancellationReason` is set and the record persists\nfor partner refund handling.\n", "x-generated": "2026-10-09", "x-method": "derived", "x-generator": "derive-json-schema.py", "x-source": "openapi/withlocals-partner-api-openapi.yml#/components/schemas/Booking", "type": "object", "required": [ "id", "status", "productId", "title", "date", "time", "timeZone", "createdAt" ], "properties": { "id": { "type": "string", "format": "uuid", "description": "Withlocals booking id." }, "partnerReference": { "type": "string", "description": "Partner's own booking id (internally `external_id`)." }, "productId": { "type": "string", "format": "uuid" }, "title": { "type": "string", "description": "Denormalized product title at the time of booking." }, "date": { "type": "string", "format": "date" }, "time": { "type": "string", "pattern": "^[0-2][0-9]:[0-5][0-9]$", "description": "Local clock time at the experience location." }, "timeZone": { "type": "string", "description": "IANA time zone for `date` / `time`." }, "status": { "$ref": "#/$defs/BookingStatus" }, "cancellationReason": { "type": "string", "enum": [ "CANCELLEDBYGUEST", "CANCELLEDBYHOST", "CANCELLEDBYADMIN", "HOSTNOSHOW" ], "description": "Present when `status=CANCELLED`. Partner-initiated cancellations\n(`DELETE /bookings/{bookingId}`) always set `CANCELLEDBYGUEST`; the\nother values appear on bookings cancelled internally by the host,\nadmin, or marked as a no-show.\n" }, "cancellationDeadline": { "type": "string", "format": "date-time", "description": "Latest moment the booking can be cancelled for a full refund." }, "createdAt": { "type": "string", "format": "date-time", "description": "When the booking was created." }, "meetingPoint": { "$ref": "#/$defs/MeetingPoint" }, "tourLanguage": { "type": "string", "description": "ISO-639-1 language code." }, "specialRequest": { "type": "string", "description": "Free-text note from the guest, forwarded to the host." }, "mainGuest": { "type": "object", "required": [ "firstName" ], "description": "The main guest (traveller) on the booking. This is the lead traveller\nsupplied as `mainGuest` on create. Absent when no main guest is recorded.\n", "properties": { "firstName": { "type": "string" }, "lastName": { "type": "string" }, "phoneNumber": { "type": "string", "description": "Absent when the main guest has no phone number on their profile." } } }, "host": { "type": "object", "required": [ "firstName" ], "description": "Minimal host details for day-of identification.", "properties": { "firstName": { "type": "string" }, "phoneNumber": { "type": "string", "description": "Absent when the host has no phone number on their profile." } } } }, "$defs": { "BookingStatus": { "type": "string", "description": "Partner-facing booking lifecycle. Translated from the internal `TripStatus`\nby a single mapper (`PartnerBookingStatus.fromTripStatus`).\n\nv1 lifecycle (no holds — `POST /bookings` creates a CONFIRMED booking\ndirectly):\n\n| Partner status | From internal `TripStatus` |\n|---|---|\n| `CONFIRMED` | `CONFIRMED`, `COMPLETED` |\n| `CANCELLED` | `CANCELLEDBYGUEST` / `HOST` / `ADMIN` / `HOSTNOSHOW` / `COUPON` (with `cancellationReason`) |\n\nInternal statuses that belong to the guest negotiation flow (`PROPOSAL`,\n`PAIDPROPOSAL`, `UNCONFIRMED`, `REJECTED`, `DELETED`) are not\npartner-visible. `RESERVATION` / `TIMEDOUT` / `EXPIRED` cannot occur in\nv1 because there is no reserve step.\n", "enum": [ "CONFIRMED", "CANCELLED" ] }, "MeetingPoint": { "type": "object", "description": "Where the experience starts.", "required": [ "name" ], "properties": { "name": { "type": "string", "description": "Short human-readable name." }, "address": { "type": "string", "description": "Formatted address line." }, "lat": { "type": "number", "format": "double", "description": "Latitude in decimal degrees (WGS84)." }, "lon": { "type": "number", "format": "double", "description": "Longitude in decimal degrees (WGS84)." }, "instructions": { "type": "string", "description": "Free-text guidance for finding the meeting spot." } } } } }