{"openapi":"3.1.0","info":{"title":"Perigee Developer API","version":"2026-07-09","summary":"Coastal data and decision delivery over a stable, versioned API.","description":"Perigee combines NOAA CO-OPS, National Weather Service, and calculated astronomy with explicit provenance and freshness. Decision responses are planning aids, never navigation or safety clearances.","termsOfService":"https://perigeetides.com/terms","contact":{"name":"Perigee support","email":"support@cardinlabs.com"},"license":{"name":"Commercial and free-plan terms","url":"https://perigeetides.com/terms"}},"jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","servers":[{"url":"https://perigeetides.com","description":"Production"}],"tags":[{"name":"Stations","description":"Station discovery and metadata."},{"name":"Observations","description":"Predictions and observed conditions."},{"name":"Astronomy","description":"Sun and moon calculations."},{"name":"Decisions","description":"Explainable planning decisions with provenance and freshness."},{"name":"Platform","description":"Developer status and diagnostics."}],"paths":{"/api/v1/stations":{"get":{"operationId":"listStations","summary":"Search the NOAA station directory","tags":["Stations"],"security":[],"parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"state","in":"query","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":5000,"default":200}}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/stations/nearest":{"get":{"operationId":"findNearestStations","summary":"Find stations nearest a coordinate","tags":["Stations"],"security":[],"parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","minimum":-90,"maximum":90}},{"name":"lon","in":"query","required":true,"schema":{"type":"number","minimum":-180,"maximum":180}}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/stations/{id}":{"get":{"operationId":"getStation","summary":"Get station metadata, products, datums, and flood levels","tags":["Stations"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"NOAA CO-OPS station identifier.","schema":{"type":"string","pattern":"^[A-Za-z0-9]{4,16}$"},"example":"9414290"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/stations/{id}/predictions":{"get":{"operationId":"getTidePredictions","summary":"Get high/low or interval tide predictions","tags":["Observations"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"NOAA CO-OPS station identifier.","schema":{"type":"string","pattern":"^[A-Za-z0-9]{4,16}$"},"example":"9414290"},{"name":"interval","in":"query","schema":{"type":"string","enum":["hilo","h","1","5","6","10","15","30","60"],"default":"hilo"}},{"name":"begin_date","in":"query","schema":{"type":"string","format":"date"}},{"name":"hours","in":"query","schema":{"type":"integer","minimum":1,"maximum":168,"default":48}},{"name":"datum","in":"query","schema":{"type":"string","default":"MLLW"}}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/stations/{id}/water-levels":{"get":{"operationId":"getWaterLevels","summary":"Get observed water levels","tags":["Observations"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"NOAA CO-OPS station identifier.","schema":{"type":"string","pattern":"^[A-Za-z0-9]{4,16}$"},"example":"9414290"},{"name":"hours","in":"query","schema":{"type":"integer","minimum":1,"maximum":720,"default":24}},{"name":"datum","in":"query","schema":{"type":"string","default":"MLLW"}}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/stations/{id}/conditions":{"get":{"operationId":"getStationConditions","summary":"Get latest water, wind, temperature, and pressure readings","tags":["Observations"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"NOAA CO-OPS station identifier.","schema":{"type":"string","pattern":"^[A-Za-z0-9]{4,16}$"},"example":"9414290"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/stations/{id}/forecast":{"get":{"operationId":"getMarineForecast","summary":"Get NWS wind and marine forecast context","tags":["Observations"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"NOAA CO-OPS station identifier.","schema":{"type":"string","pattern":"^[A-Za-z0-9]{4,16}$"},"example":"9414290"},{"name":"hours","in":"query","schema":{"type":"integer","minimum":1,"maximum":156,"default":24}}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/astronomy":{"get":{"operationId":"getAstronomy","summary":"Calculate sun and moon details for a coordinate","tags":["Astronomy"],"security":[],"parameters":[{"name":"lat","in":"query","required":true,"schema":{"type":"number","minimum":-90,"maximum":90}},{"name":"lon","in":"query","required":true,"schema":{"type":"number","minimum":-180,"maximum":180}},{"name":"date","in":"query","schema":{"type":"string","format":"date"}},{"name":"days","in":"query","schema":{"type":"integer","minimum":1,"maximum":31,"default":1}}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/decisions/trip-health":{"post":{"operationId":"getTripHealth","summary":"Get one explainable Trip Health planning read","description":"Public product-led sample. Authenticated calls count against the credential's Developer quota.","tags":["Decisions"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TripHealthRequest"},"example":{"stationId":"9414290","activity":"fishing","localDate":"2026-07-10","localTime":"07:30"}}}},"responses":{"200":{"description":"Explainable decision.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","required":["decision"],"properties":{"decision":{"$ref":"#/components/schemas/TripHealthDecision"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/decisions/best-window":{"post":{"operationId":"findBestWindow","summary":"Rank 2–12 candidate local windows","tags":["Decisions"],"security":[{"ApiKeyBearer":[]},{"ApiKeyHeader":[]}],"x-perigee-scope":"decision:read","x-perigee-feature":"decision_api","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BestWindowRequest"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/decisions/evaluate-rules":{"post":{"operationId":"evaluateDecisionRules","summary":"Evaluate deterministic rules against a fresh planning decision","tags":["Decisions"],"security":[{"ApiKeyBearer":[]},{"ApiKeyHeader":[]}],"x-perigee-scope":"decision:read","x-perigee-feature":"decision_api","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluateRulesRequest"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/v1/decisions/material-change":{"post":{"operationId":"detectMaterialChange","summary":"Compare a prior decision summary with current inputs","tags":["Decisions"],"security":[{"ApiKeyBearer":[]},{"ApiKeyHeader":[]}],"x-perigee-scope":"decision:read","x-perigee-feature":"decision_api","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialChangeRequest"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/api/developer/status":{"get":{"operationId":"getDeveloperStatus","summary":"Get API, MCP, and upstream provider status","tags":["Platform"],"security":[],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"securitySchemes":{"ApiKeyBearer":{"type":"http","scheme":"bearer","bearerFormat":"pg_live_…","description":"Preferred. Send a scoped Perigee API credential."},"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"Alternative for clients that cannot set Bearer auth."}},"headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}}},"responses":{"BadRequest":{"description":"Input validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"A valid credential is required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The credential scope or plan entitlement is insufficient.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Minute or monthly allowance exhausted.","headers":{"X-Request-Id":{"description":"Stable request identifier for support and logs.","schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"description":"Credential or anonymous requests-per-minute limit.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current minute bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Minute-bucket reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Month-Limit":{"description":"Monthly request allowance for the resolved Developer plan.","schema":{"type":"integer"}},"X-Quota-Month-Remaining":{"description":"Requests remaining in the current UTC month.","schema":{"type":"integer"}},"X-Quota-Month-Reset":{"description":"Monthly reset as Unix seconds.","schema":{"type":"integer"}},"X-Quota-Warning":{"description":"Soft quota state: none, approaching, critical, or exhausted.","schema":{"type":"string","enum":["none","approaching","critical","exhausted"]}},"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unavailable":{"description":"A required provider or quota store is unavailable. Commercial quota fails closed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}},"TripHealthRequest":{"type":"object","additionalProperties":false,"required":["stationId","activity","localDate","localTime"],"properties":{"stationId":{"type":"string","pattern":"^[A-Za-z0-9]{4,16}$"},"activity":{"type":"string","enum":["fishing","boating","surf-paddle","beachcombing","photography","coastal-living"]},"localDate":{"type":"string","format":"date"},"localTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}}},"BestWindowRequest":{"type":"object","additionalProperties":false,"required":["stationId","activity","candidates"],"properties":{"stationId":{"type":"string"},"activity":{"type":"string"},"candidates":{"type":"array","minItems":2,"maxItems":12,"items":{"type":"object","required":["localDate","localTime"],"properties":{"localDate":{"type":"string","format":"date"},"localTime":{"type":"string"}}}}}},"EvaluateRulesRequest":{"allOf":[{"$ref":"#/components/schemas/TripHealthRequest"},{"type":"object","required":["rules"],"properties":{"rules":{"type":"array","minItems":1,"maxItems":20,"items":{"$ref":"#/components/schemas/DecisionRule"}}}}]},"MaterialChangeRequest":{"allOf":[{"$ref":"#/components/schemas/TripHealthRequest"},{"type":"object","required":["baseline"],"properties":{"baseline":{"type":"object","additionalProperties":true}}}]},"DecisionRule":{"oneOf":[{"type":"object","required":["id","kind","allowed"],"properties":{"id":{"type":"string"},"kind":{"const":"state_allowed"},"allowed":{"type":"array","items":{"type":"string","enum":["normal","watch","action-needed","unknown"]}}}},{"type":"object","required":["id","kind","minimum"],"properties":{"id":{"type":"string"},"kind":{"const":"minimum_confidence"},"minimum":{"type":"string","enum":["low","moderate","high"]}}},{"type":"object","required":["id","kind","maximum"],"properties":{"id":{"type":"string"},"kind":{"const":"maximum_missing_inputs"},"maximum":{"type":"integer","minimum":0}}},{"type":"object","required":["id","kind","sourceIds"],"properties":{"id":{"type":"string"},"kind":{"const":"required_fresh_sources"},"sourceIds":{"type":"array","items":{"type":"string"}}}}]},"DecisionSource":{"type":"object","required":["id","label","provider","kind","required","available","freshness","receivedAt","attributionUrl"],"properties":{"id":{"type":"string"},"label":{"type":"string"},"provider":{"type":"string","enum":["NOAA CO-OPS","National Weather Service","Perigee"]},"kind":{"type":"string","enum":["prediction","observation","forecast","calculation"]},"required":{"type":"boolean"},"available":{"type":"boolean"},"freshness":{"type":"string","enum":["fresh","aging","stale","unknown"]},"sourceAt":{"type":["string","null"],"format":"date-time"},"receivedAt":{"type":"string","format":"date-time"},"ageMinutes":{"type":["integer","null"]},"attributionUrl":{"type":"string","format":"uri"}}},"TripHealthDecision":{"type":"object","required":["contractVersion","kind","decisionId","evaluatedAt","requestedFor","state","confidence","reasons","sources","disclaimer"],"properties":{"contractVersion":{"type":"string"},"kind":{"const":"trip-health"},"decisionId":{"type":"string","format":"uuid"},"evaluatedAt":{"type":"string","format":"date-time"},"requestedFor":{"type":"string","format":"date-time"},"state":{"type":"string","enum":["normal","watch","action-needed","unknown"]},"confidence":{"type":"string","enum":["high","moderate","low"]},"headline":{"type":"string"},"summary":{"type":"string"},"reasons":{"type":"array","items":{"type":"object","additionalProperties":true}},"missingInputs":{"type":"array","items":{"type":"string"}},"sources":{"type":"array","items":{"$ref":"#/components/schemas/DecisionSource"}},"disclaimer":{"type":"string"}}}}},"x-perigee":{"apiVersion":"2026-07-09","credentialScopes":["raw:read","mcp:use","decision:read","webhook:read","webhook:write","usage:read"],"webhookEvents":["webhook.test","decision.material_change","quota.warning","quota.exceeded","api.degraded","status.incident.created","status.incident.updated","status.maintenance.scheduled"],"monthlyQuotaWindow":"UTC calendar month","supportWindow":"12 months after a successor version becomes generally available"}}