{
  "openapi": "3.0.3",
  "info": {
    "title": "Beach Day API",
    "version": "1.0.0",
    "description": "Beach Day API aggregates beach data, water quality, tides, weather, rules, and amenities. This spec reflects the publicly documented Django REST API.",
    "contact": {
      "name": "Beach Day API",
      "url": "https://beachdayapi.com"
    },
    "license": {
      "name": "Commercial API License",
      "url": "https://beachdayapi.com/terms/"
    }
  },
  "servers": [
    {
      "url": "https://beachdayapi.com/v1",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Health",
      "description": "Service status checks."
    },
    {
      "name": "Beaches",
      "description": "Beach search and detail endpoints."
    },
    {
      "name": "Conditions",
      "description": "Historical water quality and weather snapshots."
    },
    {
      "name": "Tides",
      "description": "Tide predictions derived from the latest stored conditions."
    },
    {
      "name": "Countries",
      "description": "Available countries and beach counts"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/health/": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Health check",
        "description": "Unauthenticated endpoint that returns a simple OK payload.",
        "security": [],
        "operationId": "getHealth",
        "responses": {
          "200": {
            "description": "Service is healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "example": {
                  "status": "ok",
                  "service": "Beach Day API"
                }
              }
            }
          }
        }
      }
    },
    "/beaches/": {
      "get": {
        "tags": [
          "Beaches"
        ],
        "summary": "List beaches",
        "description": "Search and list beaches. Supports offset/limit pagination (default: 100 results, max: 500).",
        "operationId": "listBeaches",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by state code, for example CA, FL, HI, or AU-NSW."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by country name (e.g., 'Croatia', 'Greece', 'Thailand', 'French Polynesia', 'New Caledonia', 'Fiji', 'Samoa', 'Tonga', 'New Zealand'). Case-insensitive."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Search beaches by name (case-insensitive, e.g. 'Malibu')."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of results to skip (default: 0)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 100,
              "maximum": 500
            },
            "description": "Max results per page (default: 100, max: 500)."
          }
        ],
        "responses": {
          "200": {
            "description": "Beach list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BeachListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/beaches/{id}/": {
      "get": {
        "tags": [
          "Beaches"
        ],
        "summary": "Get beach detail",
        "description": "Returns a beach record plus the latest stored condition data, rules, and amenities.",
        "operationId": "getBeachDetail",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Beach ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Beach detail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BeachDetail"
                },
                "example": {
                  "id": 1,
                  "name": "Venice Beach",
                  "state": "CA",
                  "county": "Los Angeles",
                  "city": "Los Angeles",
                  "latitude": 33.985,
                  "longitude": -118.4695,
                  "description": "Popular Los Angeles beach with boardwalk access.",
                  "nearest_buoy_id": "46025",
                  "nearest_tide_station": "9410660",
                  "beach_day_score": 82,
                  "water_quality": {
                    "grade": "A",
                    "advisory": false,
                    "source": "LA County Public Health",
                    "updated": "2026-06-24T08:00:00Z"
                  },
                  "weather": {
                    "temp_f": 74,
                    "condition": "clear",
                    "uv_index": 8,
                    "wind_speed_mph": 6,
                    "humidity_pct": 68,
                    "precipitation_in": 0.0
                  },
                  "ocean_conditions": {
                    "water_temp_f": 66,
                    "wave_height_ft": 2.4,
                    "rip_current_risk": "moderate"
                  },
                  "rules": [
                    {
                      "category": "dogs",
                      "status": "restricted",
                      "notes": "Allowed on leash before 10am."
                    },
                    {
                      "category": "alcohol",
                      "status": "prohibited",
                      "notes": "No alcohol on the beach."
                    }
                  ],
                  "amenities": [
                    {
                      "category": "lifeguard",
                      "available": true,
                      "hours": "9am-6pm",
                      "notes": "Seasonal staffed towers."
                    },
                    {
                      "category": "restrooms",
                      "available": true,
                      "hours": "",
                      "notes": "Public restrooms near the boardwalk."
                    }
                  ],
                  "country": "United States"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Beach not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/beaches/{id}/conditions/": {
      "get": {
        "tags": [
          "Conditions"
        ],
        "summary": "List beach conditions",
        "description": "Returns condition snapshots for a beach. Supports offset/limit pagination (default: 30 results, max: 200).",
        "operationId": "getBeachConditions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Beach ID."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of results to skip (default: 0)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 30,
              "maximum": 200
            },
            "description": "Max results per page (default: 30, max: 200)."
          }
        ],
        "responses": {
          "200": {
            "description": "Condition history.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BeachConditionsResponse"
                },
                "example": {
                  "beach_id": 1,
                  "count": 45,
                  "results": [
                    {
                      "id": 101,
                      "beach_id": 1,
                      "date": "2026-06-24",
                      "water_quality": {
                        "grade": "A",
                        "advisory": false,
                        "updated": "2026-06-24T08:00:00Z"
                      },
                      "weather": {
                        "temp_f": 74,
                        "condition": "clear",
                        "wind_speed_mph": 6,
                        "humidity_pct": 68,
                        "precipitation_in": 0.0
                      },
                      "ocean_conditions": {
                        "water_temp_f": 66,
                        "wave_height_ft": 2.4,
                        "rip_current_risk": "moderate"
                      },
                      "tides": [
                        {
                          "time": "2026-06-24T06:14:00-07:00",
                          "type": "high",
                          "height_ft": 5.1
                        },
                        {
                          "time": "2026-06-24T12:41:00-07:00",
                          "type": "low",
                          "height_ft": 0.8
                        }
                      ],
                      "beach_day_score": 82
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Beach not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/beaches/scored/": {
      "get": {
        "tags": [
          "Beaches"
        ],
        "summary": "Get scored beaches",
        "description": "Returns beaches ranked by beach day score. Supports offset/limit pagination (default: 50 results, max: 200).",
        "operationId": "getScoredBeaches",
        "responses": {
          "200": {
            "description": "Beach ranking.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "count",
                    "results"
                  ],
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BeachDetail"
                      }
                    },
                    "count": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "results": [
                    {
                      "id": 1,
                      "name": "Venice Beach",
                      "state": "CA",
                      "county": "Los Angeles",
                      "city": "Los Angeles",
                      "latitude": 33.985,
                      "longitude": -118.4695,
                      "description": "Popular Los Angeles beach with boardwalk access.",
                      "nearest_buoy_id": "46025",
                      "nearest_tide_station": "9410660",
                      "beach_day_score": 82,
                      "water_quality": {
                        "grade": "A",
                        "advisory": false,
                        "source": "LA County Public Health",
                        "updated": "2026-06-24T08:00:00Z"
                      },
                      "weather": {
                        "temp_f": 74,
                        "condition": "clear",
                        "uv_index": 8,
                        "wind_speed_mph": 6,
                        "humidity_pct": 68,
                        "precipitation_in": 0.0
                      },
                      "ocean_conditions": {
                        "water_temp_f": 66,
                        "wave_height_ft": 2.4,
                        "rip_current_risk": "moderate"
                      },
                      "rules": [
                        {
                          "category": "dogs",
                          "status": "restricted",
                          "notes": "Allowed on leash before 10am."
                        },
                        {
                          "category": "alcohol",
                          "status": "prohibited",
                          "notes": "No alcohol on the beach."
                        }
                      ],
                      "amenities": [
                        {
                          "category": "lifeguard",
                          "available": true,
                          "hours": "9am-6pm",
                          "notes": "Seasonal staffed towers."
                        },
                        {
                          "category": "restrooms",
                          "available": true,
                          "hours": "",
                          "notes": "Public restrooms near the boardwalk."
                        }
                      ]
                    },
                    {
                      "id": 2,
                      "name": "Santa Monica State Beach",
                      "state": "CA",
                      "county": "Los Angeles",
                      "city": "Santa Monica",
                      "latitude": 34.0094,
                      "longitude": -118.4973,
                      "description": "Wide sandy beach with easy access and family amenities.",
                      "nearest_buoy_id": "46025",
                      "nearest_tide_station": "9410840",
                      "beach_day_score": 79,
                      "water_quality": {
                        "grade": "A-",
                        "advisory": false,
                        "source": "LA County Public Health",
                        "updated": "2026-06-24T08:00:00Z"
                      },
                      "weather": {
                        "temp_f": 72,
                        "condition": "partly_cloudy",
                        "uv_index": 7,
                        "wind_speed_mph": 7,
                        "humidity_pct": 68,
                        "precipitation_in": 0.0
                      },
                      "ocean_conditions": {
                        "water_temp_f": 65,
                        "wave_height_ft": 2.0,
                        "rip_current_risk": "low"
                      },
                      "rules": [
                        {
                          "category": "dogs",
                          "status": "prohibited",
                          "notes": "No dogs on the sand."
                        }
                      ],
                      "amenities": [
                        {
                          "category": "parking_lot",
                          "available": true,
                          "hours": "",
                          "notes": "Paid public lots nearby."
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of results to skip (default: 0)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            },
            "description": "Max results per page (default: 50, max: 200)."
          }
        ]
      }
    },
    "/beaches/{id}/rules/": {
      "get": {
        "tags": [
          "Beaches"
        ],
        "summary": "Get beach rules",
        "description": "Returns beach rule records as category/status/notes triples.",
        "operationId": "getBeachRules",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rules for the beach.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BeachRulesResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Beach not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/beaches/{id}/amenities/": {
      "get": {
        "tags": [
          "Beaches"
        ],
        "summary": "Get beach amenities",
        "description": "Returns amenity records as category/available/hours/notes tuples.",
        "operationId": "getBeachAmenities",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Amenities for the beach.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BeachAmenitiesResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Beach not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/tides/{beach_id}/": {
      "get": {
        "tags": [
          "Tides"
        ],
        "summary": "Get tide predictions",
        "description": "Returns up to 7 days of tide predictions sourced from stored condition records.",
        "operationId": "getTidePredictions",
        "parameters": [
          {
            "name": "beach_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tide predictions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TideResponse"
                },
                "example": {
                  "beach_id": 1,
                  "tide_predictions": [
                    {
                      "date": "2026-06-24",
                      "tides": [
                        {
                          "time": "2026-06-24T06:14:00-07:00",
                          "type": "high",
                          "height_ft": 5.1
                        },
                        {
                          "time": "2026-06-24T12:41:00-07:00",
                          "type": "low",
                          "height_ft": 0.8
                        },
                        {
                          "time": "2026-06-24T18:57:00-07:00",
                          "type": "high",
                          "height_ft": 4.7
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Beach not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/countries/": {
      "get": {
        "summary": "List available countries",
        "description": "Returns all countries with beach counts, ordered by count descending.",
        "operationId": "listCountries",
        "tags": [
          "Countries"
        ],
        "parameters": [],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Country list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountryListResponse"
                },
                "example": {
                  "count": 58,
                  "results": [
                    {
                      "country": "United States",
                      "beach_count": 3500
                    },
                    {
                      "country": "Spain",
                      "beach_count": 2488
                    },
                    {
                      "country": "Italy",
                      "beach_count": 1497
                    },
                    {
                      "country": "France",
                      "beach_count": 1324
                    },
                    {
                      "country": "India",
                      "beach_count": 480
                    },
                    {
                      "country": "Brazil",
                      "beach_count": 0
                    },
                    {
                      "country": "Colombia",
                      "beach_count": 0
                    },
                    {
                      "country": "Uruguay",
                      "beach_count": 0
                    },
                    {
                      "country": "Ecuador",
                      "beach_count": 0
                    },
                    {
                      "country": "Chile",
                      "beach_count": 0
                    },
                    {
                      "country": "Peru",
                      "beach_count": 0
                    },
                    {
                      "country": "New Zealand",
                      "beach_count": 698
                    },
                    {
                      "country": "Thailand",
                      "beach_count": 380
                    },
                    {
                      "country": "China",
                      "beach_count": 315
                    },
                    {
                      "country": "Australia",
                      "beach_count": 280
                    },
                    {
                      "country": "Vietnam",
                      "beach_count": 90
                    },
                    {
                      "country": "Cambodia",
                      "beach_count": 42
                    },
                    {
                      "country": "Croatia",
                      "beach_count": 0
                    },
                    {
                      "country": "Greece",
                      "beach_count": 0
                    },
                    {
                      "country": "French Polynesia",
                      "beach_count": 22
                    },
                    {
                      "country": "New Caledonia",
                      "beach_count": 63
                    },
                    {
                      "country": "Fiji",
                      "beach_count": 18
                    },
                    {
                      "country": "Samoa",
                      "beach_count": 21
                    },
                    {
                      "country": "Tonga",
                      "beach_count": 12
                    },
                    {
                      "country": "Cook Islands",
                      "beach_count": 8
                    },
                    {
                      "country": "American Samoa",
                      "beach_count": 3
                    },
                    {
                      "country": "Tuvalu",
                      "beach_count": 5
                    },
                    {
                      "country": "Niue",
                      "beach_count": 3
                    },
                    {
                      "country": "Wallis and Futuna",
                      "beach_count": 4
                    },
                    {
                      "country": "Tokelau",
                      "beach_count": 1
                    },
                    {
                      "country": "Algeria",
                      "beach_count": 301
                    },
                    {
                      "country": "Seychelles",
                      "beach_count": 105
                    },
                    {
                      "country": "Comoros",
                      "beach_count": 107
                    },
                    {
                      "country": "Morocco",
                      "beach_count": 58
                    },
                    {
                      "country": "Egypt",
                      "beach_count": 45
                    },
                    {
                      "country": "Mauritius",
                      "beach_count": 45
                    },
                    {
                      "country": "Tunisia",
                      "beach_count": 93
                    },
                    {
                      "country": "Cape Verde",
                      "beach_count": 62
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API key",
        "description": "User API key from the dashboard. Send as Authorization: Bearer <key>."
      }
    },
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status",
          "service"
        ],
        "properties": {
          "status": {
            "type": "string",
            "example": "ok"
          },
          "service": {
            "type": "string",
            "example": "Beach Day API"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "detail": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "balance": {
            "type": "integer"
          },
          "required": {
            "type": "integer"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "BeachListItem": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "state",
          "latitude",
          "longitude",
          "nearest_buoy_id",
          "nearest_tide_station"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "readOnly": true
          },
          "name": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "Two-letter US state code or compound AU code such as AU-NSW."
          },
          "country": {
            "type": "string",
            "description": "Country name (e.g., 'United States', 'Croatia', 'Greece', 'French Polynesia', 'New Caledonia', 'Fiji', 'Samoa', 'Tonga', 'New Zealand', 'Cook Islands')."
          },
          "latitude": {
            "type": "number",
            "format": "float",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "format": "float",
            "nullable": true
          },
          "nearest_buoy_id": {
            "type": "string",
            "minLength": 0
          },
          "nearest_tide_station": {
            "type": "string",
            "minLength": 0
          },
          "nudism": {
            "type": "string"
          },
          "surf_spot": {
            "type": "boolean",
            "default": false
          },
          "supervised": {
            "type": "string"
          },
          "lifeguard": {
            "type": "string"
          }
        },
        "example": {
          "id": 1,
          "name": "Venice Beach",
          "state": "CA",
          "latitude": 33.985,
          "longitude": -118.469,
          "nearest_buoy_id": "46025",
          "nearest_tide_station": "9410660"
        }
      },
      "BeachListResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "count",
          "results"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "minimum": 0
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BeachListItem"
            }
          }
        },
        "example": {
          "count": 47,
          "results": [
            {
              "id": 1,
              "name": "Venice Beach",
              "state": "CA",
              "latitude": 33.985,
              "longitude": -118.469,
              "nearest_buoy_id": "46025",
              "nearest_tide_station": "9410660"
            }
          ]
        }
      },
      "JsonBlob": {
        "type": "object",
        "additionalProperties": true
      },
      "BeachRule": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "category",
          "status",
          "notes"
        ],
        "properties": {
          "category": {
            "type": "string",
            "enum": [
              "dogs",
              "alcohol",
              "fires",
              "smoking",
              "camping",
              "drones",
              "parking",
              "other"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "allowed",
              "prohibited",
              "restricted",
              "seasonal"
            ]
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "BeachAmenity": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "category",
          "available",
          "hours",
          "notes"
        ],
        "properties": {
          "category": {
            "type": "string",
            "enum": [
              "restrooms",
              "showers",
              "lifeguard",
              "parking_lot",
              "food",
              "picnic",
              "playground",
              "accessibility",
              "rentals"
            ]
          },
          "available": {
            "type": "boolean"
          },
          "hours": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "BeachDetail": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "state",
          "latitude",
          "longitude",
          "description",
          "nearest_buoy_id",
          "nearest_tide_station",
          "beach_day_score",
          "water_quality",
          "weather",
          "ocean_conditions",
          "rules",
          "amenities"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "readOnly": true
          },
          "name": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "Two-letter US state code or compound AU code such as AU-NSW."
          },
          "country": {
            "type": "string",
            "description": "Country name (e.g., 'United States', 'Cambodia', 'Thailand', 'French Polynesia', 'New Caledonia', 'Fiji', 'Samoa', 'Tonga', 'New Zealand')."
          },
          "county": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "latitude": {
            "type": "number",
            "format": "float",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "format": "float",
            "nullable": true
          },
          "description": {
            "type": "string"
          },
          "nearest_buoy_id": {
            "type": "string",
            "minLength": 0
          },
          "nearest_tide_station": {
            "type": "string",
            "minLength": 0
          },
          "beach_day_score": {
            "type": "number",
            "nullable": true
          },
          "water_quality": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/JsonBlob"
              }
            ]
          },
          "weather": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/JsonBlob"
              }
            ]
          },
          "ocean_conditions": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/JsonBlob"
              }
            ]
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BeachRule"
            }
          },
          "amenities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BeachAmenity"
            }
          },
          "nudism": {
            "type": "string"
          },
          "surf_spot": {
            "type": "boolean",
            "default": false
          },
          "supervised": {
            "type": "string"
          },
          "lifeguard": {
            "type": "string"
          }
        }
      },
      "BeachConditionsItem": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "beach_id",
          "date",
          "water_quality",
          "weather",
          "ocean_conditions",
          "tides",
          "beach_day_score"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "readOnly": true
          },
          "beach_id": {
            "type": "integer"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "water_quality": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/JsonBlob"
              }
            ]
          },
          "weather": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/JsonBlob"
              }
            ]
          },
          "ocean_conditions": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/JsonBlob"
              }
            ]
          },
          "tides": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/JsonBlob"
            }
          },
          "beach_day_score": {
            "type": "number",
            "nullable": true
          }
        }
      },
      "BeachConditionsResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "beach_id",
          "count",
          "results"
        ],
        "properties": {
          "beach_id": {
            "type": "integer"
          },
          "count": {
            "type": "integer"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BeachConditionsItem"
            }
          }
        }
      },
      "BeachRulesResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "beach_id",
          "rules"
        ],
        "properties": {
          "beach_id": {
            "type": "integer"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BeachRule"
            }
          }
        }
      },
      "BeachAmenitiesResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "beach_id",
          "amenities"
        ],
        "properties": {
          "beach_id": {
            "type": "integer"
          },
          "amenities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BeachAmenity"
            }
          }
        }
      },
      "TidePrediction": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "date",
          "tides"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "tides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JsonBlob"
            }
          }
        }
      },
      "TideResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "beach_id",
          "tide_predictions"
        ],
        "properties": {
          "beach_id": {
            "type": "integer"
          },
          "tide_predictions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TidePrediction"
            }
          }
        }
      },
      "CountryListResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CountryItem"
            }
          }
        }
      },
      "CountryItem": {
        "type": "object",
        "properties": {
          "country": {
            "type": "string",
            "description": "Country name (e.g., 'Morocco', 'Algeria', 'Kenya', 'Croatia', 'Greece', 'France', 'French Polynesia', 'New Caledonia', 'Fiji', 'Samoa', 'Tonga', 'New Zealand')"
          },
          "beach_count": {
            "type": "integer",
            "description": "Number of beaches in this country"
          }
        }
      }
    }
  }
}