{
  "openapi": "3.1.0",
  "info": {
    "title": "Feminiq Rides booking API",
    "version": "2.0.0",
    "description": "Two endpoints: a side-effect-free quote and the booking request. Every booking (airport transfer, custom ride or tour) is a request: it is stored and emailed to the driver and the customer, and no payment is taken. Feminiq Rides then confirms availability and the price personally and sends a Mollie payment request for 25% of the ride price (payment=deposit, the default) or the full price (payment=full); the booking is final once that payment is in, and any remainder is paid on the day of the ride. An API response never guarantees availability. Do not call POST /api/book without the customer's explicit approval of the shown quote and acceptance of the terms (https://www.feminiqrides.nl/terms.html). Rate limits: 5 booking requests and 30 quotes per client address per 15 minutes; HTTP 429 with Retry-After when exceeded. Every booking requires the signed quoteToken from /api/quote. Quotes expire after 15 minutes; expiry, changed rules or changed journeys (including the payment choice and the return date, time and flight) return HTTP 409 reviewRequired=true, requiring a fresh quote and renewed customer approval. Custom fares are honored within the validity window, never silently repriced at booking. Airport transfers and custom rides can include a return trip: returnTrip {date, time, flight?}. It is stored as a second booking (<bookingId>-ret) that Feminiq Rides confirms on its own and that gets its own payment request; tours cannot have one. Tour pickup is required and at most five tours may be selected."
  },
  "servers": [
    {
      "url": "https://www.feminiqrides.nl"
    }
  ],
  "paths": {
    "/api/quote": {
      "post": {
        "operationId": "quote",
        "summary": "Check rules and price. No booking, email or payment is created; no personal details or terms acceptance required.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteRequest"
              },
              "examples": {
                "fixed": {
                  "summary": "Schiphol transfer with a return trip, rules/price check only",
                  "value": {
                    "car": "bmw5",
                    "date": "2026-10-08",
                    "time": "10:00",
                    "passengers": 2,
                    "type": "fixed",
                    "routeId": "ams-spl",
                    "direction": "to",
                    "address": "Dam 1, 1012 JS Amsterdam",
                    "returnTrip": {
                      "date": "2026-10-15",
                      "time": "18:30",
                      "flight": "KL 1002"
                    }
                  }
                },
                "custom": {
                  "summary": "Custom ride with a return trip the same afternoon, rules/price check only",
                  "value": {
                    "car": "bmw5",
                    "date": "2026-10-08",
                    "time": "10:00",
                    "passengers": 2,
                    "type": "custom",
                    "pickup": "Dam 1, 1012 JS Amsterdam",
                    "dropoff": "Stationsplein 9, 1012 AB Amsterdam",
                    "returnTrip": {
                      "date": "2026-10-08",
                      "time": "16:00"
                    }
                  }
                },
                "tour": {
                  "summary": "Private tour with agreed pickup, paid in full in advance, rules/price check only",
                  "value": {
                    "car": "bmw5",
                    "date": "2026-10-08",
                    "time": "10:00",
                    "passengers": 2,
                    "type": "tour",
                    "tourIds": [
                      "amsterdam-city-tour"
                    ],
                    "pickup": "Hotel Okura, Ferdinand Bolstraat 333, Amsterdam",
                    "payment": "full"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Eligible under the pricing/time rules (not a guarantee of driver availability).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Not eligible; error is a machine-readable reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited."
          },
          "502": {
            "description": "Custom-ride fare could not be calculated; retry later."
          },
          "503": {
            "description": "quote_unavailable: signing service not configured; no accepted quote is returned."
          }
        }
      }
    },
    "/api/book": {
      "post": {
        "operationId": "book",
        "summary": "Create a booking request for any ride type. Has side effects: stores the request and emails the driver and the customer. No payment is created here; the payment request follows by email after Feminiq Rides confirms the ride.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BookRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received (paymentRequired is always false). Feminiq Rides confirms availability and the price, then emails a Mollie payment request for the deposit or the full price.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BookResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation or rule error (see error codes).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Origin not allowed."
          },
          "409": {
            "description": "quote_required, quote_invalid, quote_expired, quote_changed or quote_mismatch: reviewRequired=true. No booking or mail is created. Obtain a new quote and renewed explicit customer approval, then retry with its token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited."
          },
          "502": {
            "description": "request_failed: the request could not be stored or emailed. Retrying the identical request with the same bookingId is safe; after editing details use a new bookingId."
          },
          "503": {
            "description": "payment_unavailable or mail_unavailable: service not configured."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "QuoteRequest": {
        "type": "object",
        "allOf": [
          {
            "$ref": "#/components/schemas/RideRequirements"
          }
        ],
        "required": [
          "type",
          "car",
          "date",
          "time",
          "passengers"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "fixed",
              "custom",
              "tour"
            ]
          },
          "car": {
            "type": "string",
            "enum": [
              "bmw5",
              "vclass"
            ],
            "description": "BMW 5 Series Touring (bmw5) max 4 passengers, Mercedes V-Class (vclass) max 7 passengers."
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "Local date in Europe/Amsterdam."
          },
          "time": {
            "type": "string",
            "pattern": "^\\d{2}:\\d{2}$",
            "description": "Local time in Europe/Amsterdam, between 04:00 and 20:00."
          },
          "passengers": {
            "type": "integer",
            "minimum": 1,
            "maximum": 7
          },
          "luggageLarge": {
            "type": "integer",
            "minimum": 0,
            "maximum": 8,
            "default": 0,
            "description": "Large check-in suitcases. The BMW takes at most 3; more needs the V-Class (error code luggage)."
          },
          "luggageSmall": {
            "type": "integer",
            "minimum": 0,
            "maximum": 8,
            "default": 0,
            "description": "Pieces of hand luggage. The BMW takes at most 3; more needs the V-Class (error code luggage)."
          },
          "returnTrip": {
            "type": "object",
            "description": "Airport transfers (fixed) and custom rides only; tours fail with retour_type, and a value that is not an object fails with retour. Books the return leg as well, with the same vehicle, passengers and luggage: on a fixed route the opposite direction between the same address and Schiphol, priced as a second ride at the route price; on a custom ride from the drop-off back to the pickup, where the fare estimate covers both legs and is split evenly over them. The return must be at least one hour after the first ride (retour_order), between 04:00 and 20:00 (retour_hours), not on a blocked date (retour_date_blocked) and at most 2 years ahead (date_range); missing or invalid values fail with retour_date, retour_time or retour_datetime. There is no name card on either leg (meet_greet_unavailable). The request is stored as two linked bookings, bookingId and `<bookingId>-ret` (so bookingId may have at most 76 characters), each confirmed separately and each with its own payment request: 25% of that leg's price, or all of it with payment=full.",
            "properties": {
              "date": {
                "type": "string",
                "format": "date",
                "description": "Local date of the return ride in Europe/Amsterdam."
              },
              "time": {
                "type": "string",
                "pattern": "^\\d{2}:\\d{2}$",
                "description": "Local pickup time of the return ride in Europe/Amsterdam, between 04:00 and 20:00, at least 1 hour after the first ride."
              },
              "flight": {
                "type": "string",
                "maxLength": 24,
                "description": "Optional flight number for the return ride."
              }
            },
            "required": [
              "date",
              "time"
            ]
          },
          "routeId": {
            "type": "string",
            "description": "Fixed routes only; ids from /data/rates.json. The server reprices to the route the address belongs to.",
            "enum": [
              "ams-spl",
              "noord-spl",
              "zaandam-spl",
              "aveen-spl",
              "dh-spl",
              "rtm-spl",
              "almere-spl",
              "utrecht-spl",
              "eindhoven-spl"
            ]
          },
          "direction": {
            "type": "string",
            "enum": [
              "to",
              "from"
            ],
            "description": "Fixed routes only: to or from Schiphol."
          },
          "address": {
            "type": "string",
            "minLength": 4,
            "maxLength": 180,
            "description": "Fixed routes only: the non-airport pickup/drop-off address."
          },
          "payment": {
            "type": "string",
            "enum": [
              "deposit",
              "full"
            ],
            "default": "deposit",
            "description": "How the customer pays once the ride is confirmed: deposit = a payment request for 25% of the price, rest on the day of the ride; full = a payment request for the full price. With a returnTrip each leg gets its own payment request on these terms."
          },
          "pickup": {
            "type": "string",
            "description": "Required for custom rides and tours: agreed pickup address or hotel, preserved in review and confirmations.",
            "minLength": 4,
            "maxLength": 180
          },
          "dropoff": {
            "type": "string",
            "description": "Required for custom rides: drop-off address.",
            "minLength": 4,
            "maxLength": 180
          },
          "tourIds": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "amsterdam-city-tour",
                "countryside-tour",
                "keukenhof-tour",
                "aalsmeer-flower-auction",
                "dutch-water-defence-line",
                "giethoorn-day-trip",
                "south-holland-tour",
                "rotterdam-kinderdijk",
                "kroller-muller",
                "efteling-day-trip",
                "bruges-day-trip",
                "roermond-outlet",
                "mall-of-the-netherlands",
                "batavia-stad",
                "style-outlet-amsterdam"
              ]
            },
            "minItems": 1,
            "maxItems": 5,
            "description": "Tours only; ids from /data/tours.json.",
            "uniqueItems": true
          },
          "ticketService": {
            "type": "boolean",
            "description": "Tours only: attraction ticket purchase assistance, requires 28 days' notice."
          },
          "driverName": {
            "type": "string",
            "maxLength": 60
          },
          "flight": {
            "type": "string",
            "maxLength": 24
          },
          "notes": {
            "type": "string",
            "maxLength": 1000
          },
          "lang": {
            "type": "string",
            "enum": [
              "en",
              "nl",
              "de",
              "fr",
              "es",
              "ar",
              "zh-CN"
            ]
          }
        }
      },
      "BookRequest": {
        "type": "object",
        "allOf": [
          {
            "$ref": "#/components/schemas/RideRequirements"
          }
        ],
        "required": [
          "bookingId",
          "type",
          "car",
          "date",
          "time",
          "passengers",
          "name",
          "email",
          "phone",
          "acceptedTerms",
          "quoteToken"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "fixed",
              "custom",
              "tour"
            ]
          },
          "car": {
            "type": "string",
            "enum": [
              "bmw5",
              "vclass"
            ],
            "description": "BMW 5 Series Touring (bmw5) max 4 passengers, Mercedes V-Class (vclass) max 7 passengers."
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "Local date in Europe/Amsterdam."
          },
          "time": {
            "type": "string",
            "pattern": "^\\d{2}:\\d{2}$",
            "description": "Local time in Europe/Amsterdam, between 04:00 and 20:00."
          },
          "passengers": {
            "type": "integer",
            "minimum": 1,
            "maximum": 7
          },
          "luggageLarge": {
            "type": "integer",
            "minimum": 0,
            "maximum": 8,
            "default": 0,
            "description": "Large check-in suitcases. The BMW takes at most 3; more needs the V-Class (error code luggage)."
          },
          "luggageSmall": {
            "type": "integer",
            "minimum": 0,
            "maximum": 8,
            "default": 0,
            "description": "Pieces of hand luggage. The BMW takes at most 3; more needs the V-Class (error code luggage)."
          },
          "returnTrip": {
            "type": "object",
            "description": "Airport transfers (fixed) and custom rides only; tours fail with retour_type, and a value that is not an object fails with retour. Books the return leg as well, with the same vehicle, passengers and luggage: on a fixed route the opposite direction between the same address and Schiphol, priced as a second ride at the route price; on a custom ride from the drop-off back to the pickup, where the fare estimate covers both legs and is split evenly over them. The return must be at least one hour after the first ride (retour_order), between 04:00 and 20:00 (retour_hours), not on a blocked date (retour_date_blocked) and at most 2 years ahead (date_range); missing or invalid values fail with retour_date, retour_time or retour_datetime. There is no name card on either leg (meet_greet_unavailable). The request is stored as two linked bookings, bookingId and `<bookingId>-ret` (so bookingId may have at most 76 characters), each confirmed separately and each with its own payment request: 25% of that leg's price, or all of it with payment=full.",
            "properties": {
              "date": {
                "type": "string",
                "format": "date",
                "description": "Local date of the return ride in Europe/Amsterdam."
              },
              "time": {
                "type": "string",
                "pattern": "^\\d{2}:\\d{2}$",
                "description": "Local pickup time of the return ride in Europe/Amsterdam, between 04:00 and 20:00, at least 1 hour after the first ride."
              },
              "flight": {
                "type": "string",
                "maxLength": 24,
                "description": "Optional flight number for the return ride."
              }
            },
            "required": [
              "date",
              "time"
            ]
          },
          "routeId": {
            "type": "string",
            "description": "Fixed routes only; ids from /data/rates.json. The server reprices to the route the address belongs to.",
            "enum": [
              "ams-spl",
              "noord-spl",
              "zaandam-spl",
              "aveen-spl",
              "dh-spl",
              "rtm-spl",
              "almere-spl",
              "utrecht-spl",
              "eindhoven-spl"
            ]
          },
          "direction": {
            "type": "string",
            "enum": [
              "to",
              "from"
            ],
            "description": "Fixed routes only: to or from Schiphol."
          },
          "address": {
            "type": "string",
            "minLength": 4,
            "maxLength": 180,
            "description": "Fixed routes only: the non-airport pickup/drop-off address."
          },
          "payment": {
            "type": "string",
            "enum": [
              "deposit",
              "full"
            ],
            "default": "deposit",
            "description": "How the customer pays once the ride is confirmed: deposit = a payment request for 25% of the price, rest on the day of the ride; full = a payment request for the full price. With a returnTrip each leg gets its own payment request on these terms."
          },
          "pickup": {
            "type": "string",
            "description": "Required for custom rides and tours: agreed pickup address or hotel, preserved in review and confirmations.",
            "minLength": 4,
            "maxLength": 180
          },
          "dropoff": {
            "type": "string",
            "description": "Required for custom rides: drop-off address.",
            "minLength": 4,
            "maxLength": 180
          },
          "tourIds": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "amsterdam-city-tour",
                "countryside-tour",
                "keukenhof-tour",
                "aalsmeer-flower-auction",
                "dutch-water-defence-line",
                "giethoorn-day-trip",
                "south-holland-tour",
                "rotterdam-kinderdijk",
                "kroller-muller",
                "efteling-day-trip",
                "bruges-day-trip",
                "roermond-outlet",
                "mall-of-the-netherlands",
                "batavia-stad",
                "style-outlet-amsterdam"
              ]
            },
            "minItems": 1,
            "maxItems": 5,
            "description": "Tours only; ids from /data/tours.json.",
            "uniqueItems": true
          },
          "ticketService": {
            "type": "boolean",
            "description": "Tours only: attraction ticket purchase assistance, requires 28 days' notice."
          },
          "driverName": {
            "type": "string",
            "maxLength": 60
          },
          "flight": {
            "type": "string",
            "maxLength": 24
          },
          "notes": {
            "type": "string",
            "maxLength": 1000
          },
          "lang": {
            "type": "string",
            "enum": [
              "en",
              "nl",
              "de",
              "fr",
              "es",
              "ar",
              "zh-CN"
            ]
          },
          "bookingId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{8,80}$",
            "description": "Client-generated id. Re-sending the identical request with the same id is idempotent; a changed request needs a new id. With a returnTrip the return leg is stored as `<bookingId>-ret`, so bookingId may then have at most 76 characters."
          },
          "quoteToken": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048,
            "description": "Signed token returned by POST /api/quote. Send unchanged only after the customer approves that quote's total and payment. It binds the normalized journey, vehicle, passengers, payment choice, return trip, options, fare, rules version and 15-minute expiry. HTTP 409 reviewRequired=true means obtain a new quote and renewed customer approval before retrying. Never supply your own price."
          },
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "minLength": 7,
            "maxLength": 30
          },
          "company": {
            "type": "string",
            "description": "Honeypot for the website's hidden field. Must be omitted or empty; a non-empty value is treated as automated traffic and the request is acknowledged with suppressed:true without creating a booking or email."
          },
          "acceptedTerms": {
            "type": "boolean",
            "const": true,
            "description": "Must be an explicit act by the customer after reading the Terms & Conditions. Agents must not set this on a customer's behalf without their consent."
          },
          "joinGroup": {
            "type": "object",
            "description": "Optional. Adds this ride to the request group of an earlier ride, so the owner approves them together and the customer receives ONE payment request (the sum of each ride's 25%, or full price where chosen). Use the `groupId` and `groupToken` returned for the earlier request. It is ignored (the ride stands alone) when the token or email does not match, or once any ride of the group has been approved.",
            "properties": {
              "id": {
                "type": "string"
              },
              "token": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "token"
            ]
          }
        }
      },
      "QuoteResponse": {
        "type": "object",
        "required": [
          "ok",
          "eligible",
          "quoteToken",
          "rulesVersion",
          "quotedAt",
          "validUntil",
          "quote"
        ],
        "properties": {
          "quoteToken": {
            "type": "string",
            "description": "Pass to POST /api/book after explicit customer review and approval. Not a booking or availability guarantee."
          },
          "ok": {
            "type": "boolean"
          },
          "eligible": {
            "type": "boolean"
          },
          "availability": {
            "const": "not_guaranteed"
          },
          "rulesVersion": {
            "type": "string"
          },
          "quotedAt": {
            "type": "string",
            "format": "date-time"
          },
          "validUntil": {
            "type": "string",
            "format": "date-time"
          },
          "timezone": {
            "const": "Europe/Amsterdam"
          },
          "currency": {
            "const": "EUR"
          },
          "vatIncluded": {
            "type": "boolean"
          },
          "quote": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string"
              },
              "car": {
                "type": "string"
              },
              "routeId": {
                "type": "string"
              },
              "routeLabel": {
                "type": "string"
              },
              "tourIds": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "basePrice": {
                "type": "number"
              },
              "totalPrice": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "depositCents": {
                "type": "integer",
                "description": "Amount of the payment request sent after confirmation: 25% of totalPrice, or all of it when payment=full. With a return trip each leg is confirmed and requested on its own price, so the leg requests can differ from this figure by a cent or after the owner adjusts a leg's price."
              },
              "payOnline": {
                "type": "string",
                "description": "payment_request_after_confirmation: nothing is charged until Feminiq Rides confirms the ride."
              },
              "payInVehicle": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Remainder paid on the day of the ride."
              },
              "pickup": {
                "type": "string"
              },
              "dropoff": {
                "type": "string"
              },
              "address": {
                "type": "string"
              },
              "direction": {
                "type": "string"
              },
              "ticketService": {
                "type": "boolean"
              },
              "passengers": {
                "type": "integer"
              },
              "payment": {
                "type": "string",
                "enum": [
                  "deposit",
                  "full"
                ]
              },
              "outboundPrice": {
                "type": "number",
                "description": "Return trips only: the price of the first ride; totalPrice covers both legs."
              },
              "returnTrip": {
                "type": "object",
                "description": "Return trips only: the return leg. totalPrice is its price; direction is set for fixed routes only.",
                "properties": {
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "time": {
                    "type": "string"
                  },
                  "direction": {
                    "type": "string",
                    "enum": [
                      "to",
                      "from"
                    ]
                  },
                  "totalPrice": {
                    "type": "number"
                  }
                },
                "required": [
                  "date",
                  "time",
                  "totalPrice"
                ]
              }
            }
          }
        }
      },
      "BookResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "paymentRequired": {
            "type": "boolean",
            "const": false,
            "description": "Always false: payment is requested by email after Feminiq Rides confirms the ride."
          },
          "bookingId": {
            "type": "string"
          },
          "suppressed": {
            "type": "boolean"
          },
          "groupId": {
            "type": "string",
            "description": "The request group this ride belongs to (the first ride's booking id)."
          },
          "groupToken": {
            "type": "string",
            "description": "Proof of having made the group's first request; send it as joinGroup.token with the next ride."
          },
          "grouped": {
            "type": "boolean",
            "description": "True when this request is part of a group of more than one booking (a return trip, or a ride that joined an earlier request)."
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "reviewRequired": {
            "type": "boolean",
            "description": "On HTTP 409: no booking is created. Get a new quote and ask the customer to approve its total and payment again."
          },
          "error": {
            "type": "string"
          },
          "bookingId": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "description": "error is one of: address, body, body_too_large, booking_id, booking_id_conflict, capacity, car, content_type, custom_estimate_failed, date_blocked, date_range, datetime, direction, driver_name, dropoff, email, flight, hours, internal, lead_time, luggage, mail_unavailable, meet_greet_unavailable, method, name, notes, origin, payment, payment_unavailable, phone, pickup, quote_changed, quote_expired, quote_invalid, quote_mismatch, quote_required, quote_unavailable, rate_limit, request_failed, retour, retour_date, retour_date_blocked, retour_datetime, retour_hours, retour_order, retour_time, retour_type, route, terms, ticket_lead_time, tour, tour_duplicate, tour_limit, tour_price, tour_season, type."
      },
      "RideRequirements": {
        "type": "object",
        "properties": {
          "pickup": {
            "type": "string",
            "minLength": 4,
            "maxLength": 180,
            "description": "Required for custom rides and tours: agreed pickup address or hotel, preserved in review and confirmations."
          },
          "dropoff": {
            "type": "string",
            "minLength": 4,
            "maxLength": 180
          },
          "tourIds": {
            "type": "array",
            "uniqueItems": true
          },
          "email": {
            "type": "string",
            "maxLength": 254
          },
          "phone": {
            "type": "string",
            "pattern": "^[+()0-9 .-]{7,30}$"
          }
        },
        "allOf": [
          {
            "if": {
              "properties": {
                "type": {
                  "const": "fixed"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "required": [
                "routeId",
                "direction",
                "address"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "const": "custom"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "required": [
                "pickup",
                "dropoff"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "const": "tour"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "required": [
                "tourIds",
                "pickup"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "car": {
                  "const": "bmw5"
                }
              },
              "required": [
                "car"
              ]
            },
            "then": {
              "properties": {
                "passengers": {
                  "maximum": 4
                },
                "luggageLarge": {
                  "maximum": 3
                },
                "luggageSmall": {
                  "maximum": 3
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "const": "tour"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "not": {
                "required": [
                  "returnTrip"
                ]
              }
            }
          }
        ]
      }
    }
  }
}
