{
  "openapi": "3.1.0",
  "info": {
    "title": "Maki Car Rental Agent API",
    "version": "1.0.0",
    "description": "Public quote and availability API for Maki Car Rental.",
    "license": {
      "name": "Proprietary",
      "url": "https://www.maki-car-rental.com/rent-a-car/terms.html"
    }
  },
  "servers": [
    {
      "url": "https://www.maki-car-rental.com"
    }
  ],
  "security": [],
  "paths": {
    "/api/locations": {
      "get": {
        "operationId": "listLocations",
        "summary": "List pickup and return locations",
        "parameters": [
          {
            "name": "culture",
            "in": "query",
            "required": false,
            "description": "Response language. Defaults to en. Valid values: en, de, fr, zh.",
            "schema": {
              "type": "string",
              "enum": [
                "en",
                "de",
                "fr",
                "zh"
              ]
            },
            "example": "en"
          },
          {
            "name": "destination",
            "in": "query",
            "required": true,
            "description": "Rental destination. Valid values: mauritius, reunion, mahe, praslin.",
            "schema": {
              "$ref": "#/components/schemas/Destination"
            },
            "example": "mauritius"
          }
        ],
        "responses": {
          "200": {
            "description": "LocationsResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationsResponse"
                }
              }
            }
          },
          "400": {
            "description": "ErrorResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/availability": {
      "get": {
        "operationId": "getAvailability",
        "summary": "Get bookable car rental offers and proposed alternatives",
        "parameters": [
          {
            "name": "culture",
            "in": "query",
            "required": false,
            "description": "Response language. Defaults to en. Valid values: en, de, fr, zh.",
            "schema": {
              "type": "string",
              "enum": [
                "en",
                "de",
                "fr",
                "zh"
              ]
            },
            "example": "en"
          },
          {
            "name": "destination",
            "in": "query",
            "required": true,
            "description": "Rental destination. Valid values: mauritius, reunion, mahe, praslin.",
            "schema": {
              "$ref": "#/components/schemas/Destination"
            },
            "example": "mauritius"
          },
          {
            "name": "pickup_at",
            "in": "query",
            "required": true,
            "description": "Pickup date and time in destination local time. Use YYYY-MM-DD HH:mm or YYYY-MM-DDTHH:mm. Timezone offsets are not allowed. Must be 3 hours to 365 days in the future. Times are snapped down to the previous 15-minute increment.",
            "schema": {
              "type": "string"
            },
            "example": "2026-06-01 10:00"
          },
          {
            "name": "return_at",
            "in": "query",
            "required": true,
            "description": "Return date and time in destination local time. Use YYYY-MM-DD HH:mm or YYYY-MM-DDTHH:mm. Timezone offsets are not allowed. Must be 24 hours to 60 days after pickup_at. Times are snapped up to the next 15-minute increment.",
            "schema": {
              "type": "string"
            },
            "example": "2026-06-07 10:00"
          },
          {
            "name": "pickup_location",
            "in": "query",
            "required": true,
            "description": "Pickup location name or id. Examples: airport, MRU, Flic en Flac, 67.",
            "schema": {
              "type": "string"
            },
            "example": "airport"
          },
          {
            "name": "return_location",
            "in": "query",
            "required": true,
            "description": "Return location name or id. Examples: airport, MRU, Flic en Flac, 67.",
            "schema": {
              "type": "string"
            },
            "example": "Flic en Flac"
          },
          {
            "name": "currency",
            "in": "query",
            "required": false,
            "description": "Currency code. Defaults to EUR. Valid values: EUR, GBP, USD, MUR.",
            "schema": {
              "type": "string",
              "enum": [
                "EUR",
                "GBP",
                "USD",
                "MUR"
              ]
            },
            "example": "EUR"
          }
        ],
        "responses": {
          "200": {
            "description": "AvailabilityResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailabilityResponse"
                }
              }
            }
          },
          "400": {
            "description": "ErrorResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "timezoneOffsetRejected": {
                    "summary": "Timezone offsets are rejected",
                    "value": {
                      "error": "invalid_timezone",
                      "field": "pickup_at",
                      "message": "pickup_at must be destination-local time without a timezone offset"
                    }
                  },
                  "invalidDateTimeFormat": {
                    "summary": "Datetime must be destination-local YYYY-MM-DD HH:mm",
                    "value": {
                      "error": "invalid_datetime",
                      "field": "return_at",
                      "message": "return_at must use destination-local time as YYYY-MM-DD HH:mm without a timezone offset"
                    }
                  },
                  "pickupTooSoon": {
                    "summary": "Pickup must be at least 3 hours in the future",
                    "value": {
                      "error": "pickup_too_soon",
                      "field": "pickup_at",
                      "message": "pickup_at must be at least 3 hours in the future"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApi",
        "summary": "Get this OpenAPI document",
        "responses": {
          "200": {
            "description": "OpenAPI document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "OpenAPI 3.1 document for this API.",
                  "additionalProperties": true
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Destination": {
        "type": "string",
        "enum": [
          "mauritius",
          "reunion",
          "mahe",
          "praslin"
        ]
      },
      "Location": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "delivery_fee_min": {
            "type": "number"
          },
          "delivery_fee_max": {
            "type": "number"
          }
        }
      },
      "LocationsResponse": {
        "type": "object",
        "required": [
          "culture",
          "destination",
          "locations"
        ],
        "properties": {
          "culture": {
            "type": "string"
          },
          "destination": {
            "$ref": "#/components/schemas/Destination"
          },
          "locations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Location"
            }
          }
        }
      },
      "AvailabilityResponse": {
        "type": "object",
        "required": [
          "status",
          "culture",
          "currency",
          "destination",
          "pickup_at",
          "return_at",
          "pickup_location",
          "return_location",
          "useful_links",
          "offers"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "invalid_request"
            ]
          },
          "culture": {
            "type": "string"
          },
          "destination": {
            "$ref": "#/components/schemas/Destination"
          },
          "currency": {
            "type": "string"
          },
          "pickup_at": {
            "type": "string",
            "description": "Destination-local date and time with the applied timezone offset."
          },
          "return_at": {
            "type": "string",
            "description": "Destination-local date and time with the applied timezone offset."
          },
          "pickup_location": {
            "$ref": "#/components/schemas/Location"
          },
          "return_location": {
            "$ref": "#/components/schemas/Location"
          },
          "useful_links": {
            "$ref": "#/components/schemas/UsefulLinks"
          },
          "offers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AvailabilityOffer"
            }
          }
        }
      },
      "AvailabilityOffer": {
        "type": "object",
        "required": [
          "id",
          "name",
          "availability",
          "price_total",
          "vehicle"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "availability": {
            "type": "string",
            "enum": [
              "available",
              "alternative_proposed"
            ]
          },
          "price_total": {
            "type": "number"
          },
          "next_price_total": {
            "type": "number"
          },
          "delivery_fee": {
            "type": "number"
          },
          "vehicle": {
            "$ref": "#/components/schemas/Vehicle"
          },
          "proposal": {
            "$ref": "#/components/schemas/Proposal"
          },
          "off_hours_warning": {
            "type": "string"
          },
          "initiate_url": {
            "type": "string",
            "format": "uri",
            "description": "Booking initiation URL. Present for directly available offers. Proposed alternatives may omit it when they cannot be booked directly."
          }
        },
        "allOf": [
          {
            "if": {
              "properties": {
                "availability": {
                  "const": "available"
                }
              },
              "required": [
                "availability"
              ]
            },
            "then": {
              "properties": {
                "initiate_url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Booking initiation URL."
                }
              },
              "required": [
                "initiate_url"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "availability": {
                  "const": "alternative_proposed"
                }
              },
              "required": [
                "availability"
              ]
            },
            "then": {
              "properties": {
                "proposal": {
                  "$ref": "#/components/schemas/Proposal"
                }
              },
              "required": [
                "proposal"
              ]
            }
          }
        ]
      },
      "Vehicle": {
        "type": "object",
        "properties": {
          "image_url": {
            "type": "string",
            "format": "uri",
            "description": "Absolute URL for the public vehicle image shown on the Maki Car Rental website."
          },
          "seats": {
            "type": "integer"
          },
          "occasional_seats": {
            "type": "integer"
          },
          "doors": {
            "type": "integer"
          },
          "horsepower": {
            "type": "integer"
          },
          "engine_cc": {
            "type": "integer"
          },
          "abs": {
            "type": "boolean"
          },
          "power_windows": {
            "type": "boolean"
          },
          "utility_vehicle": {
            "type": "boolean"
          },
          "all_wheel_drive": {
            "type": "boolean"
          },
          "convertible": {
            "type": "boolean"
          },
          "air_conditioning": {
            "type": "boolean"
          },
          "cd_radio": {
            "type": "boolean"
          },
          "manual": {
            "$ref": "#/components/schemas/TransmissionAvailability"
          },
          "automatic": {
            "$ref": "#/components/schemas/TransmissionAvailability"
          }
        }
      },
      "TransmissionAvailability": {
        "type": "object",
        "required": [
          "available"
        ],
        "properties": {
          "available": {
            "type": "boolean"
          },
          "surcharge": {
            "type": "number"
          }
        },
        "additionalProperties": false
      },
      "Proposal": {
        "type": "object",
        "properties": {
          "pickup_at": {
            "type": "string",
            "description": "Proposed pickup date-time with destination timezone offset."
          },
          "return_at": {
            "type": "string",
            "description": "Proposed return date-time with destination timezone offset."
          },
          "gap": {
            "$ref": "#/components/schemas/ProposalGap"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ProposalGap": {
        "type": "object",
        "properties": {
          "from": {
            "type": "string",
            "description": "Start of unavailable gap with destination timezone offset."
          },
          "till": {
            "type": "string",
            "description": "End of unavailable gap with destination timezone offset."
          }
        },
        "additionalProperties": false
      },
      "UsefulLinks": {
        "type": "object",
        "required": [
          "faq",
          "terms",
          "contact",
          "terms_markdown",
          "destination_markdown"
        ],
        "properties": {
          "faq": {
            "type": "string",
            "format": "uri"
          },
          "terms": {
            "type": "string",
            "format": "uri"
          },
          "contact": {
            "type": "string",
            "format": "uri"
          },
          "terms_markdown": {
            "type": "string",
            "format": "uri"
          },
          "destination_markdown": {
            "type": "string",
            "format": "uri",
            "description": "Agent-readable destination knowledge document for the selected destination."
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "field": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}